Added makeBackupIfSmaller and Everything and Nothing.

This commit is contained in:
Jeremy Fincher 2004-09-10 06:32:17 +00:00
parent e98bb7a787
commit 5dbcf950a8

View File

@ -707,12 +707,13 @@ def mungeEmailForWeb(s):
class AtomicFile(file): class AtomicFile(file):
"""Used for files that need to be atomically written -- i.e., if there's a """Used for files that need to be atomically written -- i.e., if there's a
failure, the original file remains, unmodified. mode must be 'w' or 'wb'""" failure, the original file remains, unmodified. mode must be 'w' or 'wb'"""
def __init__(self, filename, mode='w', def __init__(self, filename, mode='w', allowEmptyOverwrite=True,
allowEmptyOverwrite=True, tmpDir=None): makeBackupIfSmaller=True, tmpDir=None):
if mode not in ('w', 'wb'): if mode not in ('w', 'wb'):
raise ValueError, 'Invalid mode: %r' % mode raise ValueError, 'Invalid mode: %r' % mode
self.rolledback = False self.rolledback = False
self.allowEmptyOverwrite = allowEmptyOverwrite self.allowEmptyOverwrite = allowEmptyOverwrite
self.makeBackupIfSmaller = makeBackupIfSmaller
self.filename = filename self.filename = filename
if tmpDir is None: if tmpDir is None:
# If not given a tmpDir, we'll just put a random token on the end # If not given a tmpDir, we'll just put a random token on the end
@ -723,6 +724,8 @@ class AtomicFile(file):
# directory), put our random token on the end, and put it in tmpDir # directory), put our random token on the end, and put it in tmpDir
tempFilename = '%s.%s' % (os.path.basename(self.filename), mktemp()) tempFilename = '%s.%s' % (os.path.basename(self.filename), mktemp())
self.tempFilename = os.path.join(tmpDir, tempFilename) self.tempFilename = os.path.join(tmpDir, tempFilename)
# This doesn't work because of the uncollectable garbage effect.
# self.__parent = super(AtomicFile, self)
super(AtomicFile, self).__init__(self.tempFilename, mode) super(AtomicFile, self).__init__(self.tempFilename, mode)
def rollback(self): def rollback(self):
@ -739,13 +742,20 @@ class AtomicFile(file):
# doesn't exist. # doesn't exist.
size = os.path.getsize(self.tempFilename) size = os.path.getsize(self.tempFilename)
originalExists = os.path.exists(self.filename) originalExists = os.path.exists(self.filename)
# We use shutil.move here instead of os.rename because
# the latter doesn't work on Windows when self.filename
# (the target) already exists. shutil.move handles those
# intricacies for us.
if size or self.allowEmptyOverwrite or not originalExists: if size or self.allowEmptyOverwrite or not originalExists:
if os.path.exists(self.tempFilename): if originalExists:
# We use shutil.move here instead of os.rename because currentSize = os.path.getsize(self.filename)
# the latter doesn't work on Windows when self.filename if self.makeBackupIfSmaller and size < currentSize:
# (the target) already exists. shutil.move handles those now = int(time.time())
# intricacies for us. backupFilename = '%s.backup.%s' % (self.filename, now)
shutil.move(self.tempFilename, self.filename) shutil.copy(self.filename, backupFilename)
shutil.move(self.tempFilename, self.filename)
else:
raise ValueError, 'AtomicFile.close called after rollback.'
def __del__(self): def __del__(self):
# We rollback because if we're deleted without being explicitly closed, # We rollback because if we're deleted without being explicitly closed,
@ -787,6 +797,22 @@ def callTracer(fd=None, basename=True):
print >>fd, '%s: %s(%s)' % (filename, funcname, lineno) print >>fd, '%s: %s(%s)' % (filename, funcname, lineno)
return tracer return tracer
# These are used by Owner and Misc for their callBefore/callAfter attributes.
class Everything(object):
def __contains__(self, x):
return True
def __iter__(self):
return iter([])
class Nothing(object):
def __contains__(self, x):
return False
def __iter__(self):
return iter([])
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest
doctest.testmod(sys.modules['__main__']) doctest.testmod(sys.modules['__main__'])