0

Now writes images to temporary files and atomically moves in place*

* on systems with an atomic os.rename
This commit is contained in:
Andrew Brown
2012-02-26 00:14:58 -05:00
parent c759b20f8e
commit 19f6f136e4
3 changed files with 102 additions and 40 deletions

View File

@@ -178,6 +178,74 @@ def get_tiles_by_chunk(chunkcol, chunkrow):
return product(colrange, rowrange)
# Define a context manager to handle atomic renaming or "just forget it write
# straight to the file" depending on whether os.rename provides atomic
# overwrites.
# Detect whether os.rename will overwrite files
import tempfile
with tempfile.NamedTemporaryFile() as f1:
with tempfile.NamedTemporaryFile() as f2:
try:
os.rename(f1.name,f2.name)
except OSError:
renameworks = False
else:
renameworks = True
# re-make this file so it can be deleted without error
open(f1.name, 'w').close()
del tempfile,f1,f2
doc = """This class acts as a context manager for files that are to be written
out overwriting an existing file.
The parameter is the destination filename. The value returned into the context
is the filename that should be used. On systems that support an atomic
os.rename(), the filename will actually be a temporary file, and it will be
atomically replaced over the destination file on exit.
On systems that don't support an atomic rename, the filename returned is the
filename given.
If an error is encountered, the file is attempted to be removed, and the error
is propagated.
Example:
with FileReplacer("config") as configname:
with open(configout, 'w') as configout:
configout.write(newconfig)
"""
if renameworks:
class FileReplacer(object):
__doc__ = doc
def __init__(self, destname):
self.destname = destname
self.tmpname = destname + ".tmp"
def __enter__(self):
# rename works here. Return a temporary filename
return self.tmpname
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
# error
try:
os.remove(self.tmpname)
except Exception, e:
logging.warning("An error was raised, so I was doing "
"some cleanup first, but I couldn't remove "
"'%s'!", self.tmpname)
else:
# atomic rename into place
os.rename(self.tmpname, self.destname)
else:
class FileReplacer(object):
__doc__ = doc
def __init__(self, destname):
self.destname = destname
def __enter__(self):
return self.destname
def __exit__(self, exc_type, exc_val, exc_tb):
return
del renameworks
# Logging related classes are below
# Some cool code for colored logging: