| =================== |
| python-atomicwrites |
| =================== |
| |
| Unmaintained |
| ============ |
| |
| `PyPI wants me to enable 2FA just because I maintain this package |
| <https://github.com/untitaker/python-atomicwrites/issues/61>`_, and both that |
| and the mess resulting from a stunt of mine, I thought it'd be a good time to |
| deprecate this package. Python 3 has `os.replace` and `os.rename` which |
| probably do well enough of a job for most usecases. |
| |
| ---- |
| |
| .. image:: https://travis-ci.com/untitaker/python-atomicwrites.svg?branch=master |
| :target: https://travis-ci.com/untitaker/python-atomicwrites |
| .. image:: https://ci.appveyor.com/api/projects/status/vadc4le3c27to59x/branch/master?svg=true |
| :target: https://ci.appveyor.com/project/untitaker/python-atomicwrites/branch/master |
| .. image:: https://readthedocs.org/projects/python-atomicwrites/badge/?version=latest |
| :target: https://python-atomicwrites.readthedocs.io/en/latest/?badge=latest |
| :alt: Documentation Status |
| |
| **Atomic file writes.** |
| |
| .. code-block:: python |
| |
| from atomicwrites import atomic_write |
| |
| with atomic_write('foo.txt', overwrite=True) as f: |
| f.write('Hello world.') |
| # "foo.txt" doesn't exist yet. |
| |
| # Now it does. |
| |
| See `API documentation <https://python-atomicwrites.readthedocs.io/en/latest/#api>`_ for more |
| low-level interfaces. |
| |
| Features that distinguish it from other similar libraries (see `Alternatives and Credit`_): |
| |
| - Race-free assertion that the target file doesn't yet exist. This can be |
| controlled with the ``overwrite`` parameter. |
| |
| - Windows support, although not well-tested. The MSDN resources are not very |
| explicit about which operations are atomic. I'm basing my assumptions off `a |
| comment |
| <https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/449bb49d-8acc-48dc-a46f-0760ceddbfc3/movefileexmovefilereplaceexisting-ntfs-same-volume-atomic?forum=windowssdk#a239bc26-eaf0-4920-9f21-440bd2be9cc8>`_ |
| by `Doug Cook |
| <https://social.msdn.microsoft.com/Profile/doug%20e.%20cook>`_, who appears |
| to be a Microsoft employee: |
| |
| Question: Is MoveFileEx atomic if the existing and new |
| files are both on the same drive? |
| |
| The simple answer is "usually, but in some cases it will silently fall-back |
| to a non-atomic method, so don't count on it". |
| |
| The implementation of MoveFileEx looks something like this: [...] |
| |
| The problem is if the rename fails, you might end up with a CopyFile, which |
| is definitely not atomic. |
| |
| If you really need atomic-or-nothing, you can try calling |
| NtSetInformationFile, which is unsupported but is much more likely to be |
| atomic. |
| |
| - Simple high-level API that wraps a very flexible class-based API. |
| |
| - Consistent error handling across platforms. |
| |
| |
| How it works |
| ============ |
| |
| It uses a temporary file in the same directory as the given path. This ensures |
| that the temporary file resides on the same filesystem. |
| |
| The temporary file will then be atomically moved to the target location: On |
| POSIX, it will use ``rename`` if files should be overwritten, otherwise a |
| combination of ``link`` and ``unlink``. On Windows, it uses MoveFileEx_ through |
| stdlib's ``ctypes`` with the appropriate flags. |
| |
| Note that with ``link`` and ``unlink``, there's a timewindow where the file |
| might be available under two entries in the filesystem: The name of the |
| temporary file, and the name of the target file. |
| |
| Also note that the permissions of the target file may change this way. In some |
| situations a ``chmod`` can be issued without any concurrency problems, but |
| since that is not always the case, this library doesn't do it by itself. |
| |
| .. _MoveFileEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx |
| |
| fsync |
| ----- |
| |
| On POSIX, ``fsync`` is invoked on the temporary file after it is written (to |
| flush file content and metadata), and on the parent directory after the file is |
| moved (to flush filename). |
| |
| ``fsync`` does not take care of disks' internal buffers, but there don't seem |
| to be any standard POSIX APIs for that. On OS X, ``fcntl`` is used with |
| ``F_FULLFSYNC`` instead of ``fsync`` for that reason. |
| |
| On Windows, `_commit <https://msdn.microsoft.com/en-us/library/17618685.aspx>`_ |
| is used, but there are no guarantees about disk internal buffers. |
| |
| Alternatives and Credit |
| ======================= |
| |
| Atomicwrites is directly inspired by the following libraries (and shares a |
| minimal amount of code): |
| |
| - The Trac project's `utility functions |
| <http://www.edgewall.org/docs/tags-trac-0.11.7/epydoc/trac.util-pysrc.html>`_, |
| also used in `Werkzeug <http://werkzeug.pocoo.org/>`_ and |
| `mitsuhiko/python-atomicfile |
| <https://github.com/mitsuhiko/python-atomicfile>`_. The idea to use |
| ``ctypes`` instead of ``PyWin32`` originated there. |
| |
| - `abarnert/fatomic <https://github.com/abarnert/fatomic>`_. Windows support |
| (based on ``PyWin32``) was originally taken from there. |
| |
| Other alternatives to atomicwrites include: |
| |
| - `sashka/atomicfile <https://github.com/sashka/atomicfile>`_. Originally I |
| considered using that, but at the time it was lacking a lot of features I |
| needed (Windows support, overwrite-parameter, overriding behavior through |
| subclassing). |
| |
| - The `Boltons library collection <https://github.com/mahmoud/boltons>`_ |
| features a class for atomic file writes, which seems to have a very similar |
| ``overwrite`` parameter. It is lacking Windows support though. |
| |
| License |
| ======= |
| |
| Licensed under the MIT, see ``LICENSE``. |