On Wed, 2 Sep 2015 19:06 Steven D'Aprano <st...@pearwood.info> wrote:
Howdy, I have a utility function for performing atomic file saves, and I'd like to ask for a code review and comments. I have published this on ActiveState: https://code.activestate.com/recipes/579097-safely-and-atomically-write-to-a-file/ under an MIT licence. You should read the version there, I discuss the use-case for the function and include an extensive doc string. Feel free to comment either here or on the ActiveState site. Here is the function, minus the docstring (for brevity): import contextlib import os import stat import tempfile @contextlib.contextmanager def atomic_write(filename, text=True, keep=True, owner=None, group=None, perms=None, suffix='.bak', prefix='tmp'): t = (uid, gid, mod) = (owner, group, perms) if any(x is None for x in t): info = os.stat(filename) if uid is None: uid = info.st_uid if gid is None: gid = info.st_gid if mod is None: mod = stat.S_IMODE(info.st_mode) path = os.path.dirname(filename) fd, tmp = tempfile.mkstemp( suffix=suffix, prefix=prefix, dir=path, text=text) try: with os.fdopen(fd, 'w' if text else 'wb') as f: yield f os.rename(tmp, filename) tmp = None os.chown(filename, uid, gid) os.chmod(filename, mod) finally: if (tmp is not None) and (not keep): # Silently delete the temporary file. Ignore any errors. try: os.unlink(tmp) except: pass Usage is: with atomic_write("mydata.txt") as f: f.write("some data") # if an error occurs in here, mydata.txt is preserved # if no error occurs and the with-block exits cleanly, # mydata.txt is atomically overwritten with the new contents. The function is written for Python 2.6, but should work on 2.7 as well. I'm looking for a review of the code, and any general comments. In particular, have I missed any ways that the function may fail and lose data? One question comes to mind -- should I perform a flush and/or sync of the file before the rename? Your with statement will close the file so that shouldn't be necessary. Not an expert on these things but maybe it makes sense to call chown/chmod before the rename so that a failure can't result in the replaced file's permissions being changed. -- Oscar
-- https://mail.python.org/mailman/listinfo/python-list