diff options
author | Will McGugan <will@willmcgugan.com> | 2015-04-19 12:46:53 +0100 |
---|---|---|
committer | Will McGugan <will@willmcgugan.com> | 2015-04-19 12:46:53 +0100 |
commit | 7731df71a7b68c7a8ff181326bf84dd71b7c8a14 (patch) | |
tree | 8440fb2ee22f62627083163d29198368f77c5823 /fs/utils.py | |
parent | 29b519fb3ebead760cedb784e244d3fbaf6981ff (diff) | |
download | pyfilesystem-git-7731df71a7b68c7a8ff181326bf84dd71b7c8a14.tar.gz |
added open_atomic_write
Diffstat (limited to 'fs/utils.py')
-rw-r--r-- | fs/utils.py | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/fs/utils.py b/fs/utils.py index 8fd6254..208fc61 100644 --- a/fs/utils.py +++ b/fs/utils.py @@ -16,8 +16,10 @@ __all__ = ['copyfile', 'isfile', 'isdir', 'find_duplicates', - 'print_fs'] + 'print_fs', + 'open_atomic_write'] +import os import sys import stat import six @@ -628,6 +630,46 @@ def print_fs(fs, return dircount[0], filecount[0] +class AtomicWriter(object): + """Context manager to perform atomic writes""" + + def __init__(self, fs, path, mode='w'): + self.fs = fs + self.path = path + self.mode = mode + self.tmp_path = path + '~' + self._f = None + + def __enter__(self): + self._f = self.fs.open(self.tmp_path, self.mode) + return self._f + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is None: + if self._f is not None: + if hasattr('_f', 'flush'): + self._f.flush() + if hasattr(self._f, 'fileno'): + os.fsync(self._f.fileno()) + self._f.close() + self._f = None + self.fs.rename(self.tmp_path, self.path) + else: + if self._f is not None: + self._f.close() + + +def open_atomic_write(fs, path, mode='w'): + """Open a file for 'atomic' writing + + This returns a context manager which ensures that a file is written in its entirety or not at all. + + """ + return AtomicWriter(fs, path, mode=mode) + + + + if __name__ == "__main__": from fs.tempfs import TempFS from six import b |