Skip to main content

A safer file opener

Project description

✏️safer: a safer file opener ✏️

No more partial writes or corruption! For file streams, sockets or any callable.

Install safer from the command line with pip (https://pypi.org/project/pip): pip install safer.

Tested on Python 3.4 and 3.8 For Python 2.7, use https://github.com/rec/safer/tree/v2.0.5

See the Medium article here.

safer does not force atomic writing of files! It is aimed at preventing corrupt files, streams, socket connections or similar, but from to a programmer error, not because of concurrent modification of files from other threads or processes. See https://pypi.org/project/atomicwrites/ if you need atomic file writing.

  • safer.writer() wraps an existing writer or socket and writes a whole response or nothing, by caching written data in memory

  • safer.open() is a drop-in replacement for built-in open that writes a whole file or nothing by caching written data on disk. Unfortunately, disk caching does not work on Windows.

  • safer.closer() returns a stream like from safer.write() that also closes the underlying stream or callable when it closes.

  • safer.printer() is safer.open() except that it yields a a function that prints to the stream. Like safer.open(), it unfortunately does not work on Windows.


safer.open()

safer.open() writes a whole file or nothing. It’s a drop-in replacement for built-in open() except that safer.open() leaves the original file unchanged on failure.

EXAMPLE

# dangerous
with open(filename, 'w') as fp:
    json.dump(data, fp)
    # If an exception is raised, the file is empty or partly written

# safer
with safer.open(filename, 'w') as fp:
    json.dump(data, fp)
    # If an exception is raised, the file is unchanged.

safer.open(filename) returns a file stream fp like open(filename) would, except that fp writes to a temporary file in the same directory.

If fp is used as a context manager and an exception is raised, then fp.safer_failed is automatically set to True. And when fp.close() is called, the temporary file is moved over filename unless fp.safer_failed is true.


safer.writer()

safer.writer() is like safer.open() except that it uses an existing writer, a socket, or a callback.

EXAMPLE

sock = socket.socket(*args)

# dangerous
try:
    write_header(sock)
    write_body(sock)
    write_footer(sock)
 except:
    write_error(sock)  # You already wrote the header!

# safer
with safer.write(sock) as s:
    write_header(s)
    write_body(s)
    write_footer(s)
 except:
    write_error(sock)  # Nothing has been written

safer.printer()

safer.printer() is similar to safer.open() except it yields a function that prints to the open file - it’s very convenient for printing text.

Like safer.open(), if an exception is raised within its context manager, the original file is left unchanged.

EXAMPLE

# dangerous
with open(file, 'w') as fp:
    for item in items:
        print(item, file=fp)
    # Prints lines until the first exception

# safer
with safer.printer(file) as print:
    for item in items:
        print(item)
    # Either the whole file is written, or nothing

NOTES

If a stream fp return from safer.open() is used as a context

manager and an exception is raised, the property fp.safer_failed is set to True.

In the method fp.close(), if fp.safer_failed is not set, then the temporary file is moved over the original file, successfully completing the write.

If fp.safer_failed is true, then if delete_failures is true, the temporary file is deleted.

If the mode argument contains either 'a' (append), or '+'

(update), then the original file will be copied to the temporary file before writing starts.

Note that safer uses an extra temporary file which is renamed over the file only after the stream closes without failing. This uses as much disk space as the old and new files put together.

FUNCTIONS

safer.writer(stream, is_binary=None, close_on_exit=False)

Write safely to file streams, sockets and callables.

safer.writer yields an in-memory stream that you can write to, but which is only written to the original stream if the context finished without raising an exception.

Because the actual writing happens when the context exits, it’s possible to block indefinitely if the underlying socket, stream or callable does.

ARGUMENTS
stream:

A file stream, a socket, or a callable that will receive data

is_binary:

Is stream a binary stream?

If is_binary is None, deduce whether it’s a binary file from the stream, or assume it’s text otherwise.

safer.open(name, mode=’r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, follow_symlinks=True, make_parents=False, delete_failures=True, temp_file=True)

A drop-in replacement for open() which returns a stream which only overwrites the original file when close() is called, and only if there was no failure

If a stream fp return from safer.open() is used as a context manager and an exception is raised, the property fp.safer_failed is set to True.

In the method fp.close(), if fp.safer_failed is not set, then the temporary file is moved over the original file, successfully completing the write.

If fp.safer_failed is true, then if delete_failures is true, the temporary file is deleted.

If the mode argument contains either 'a' (append), or '+' (update), then the original file will be copied to the temporary file before writing starts.

Note that safer uses an extra temporary file which is renamed over the file only after the stream closes without failing. This uses as much disk space as the old and new files put together.

ARGUMENTS
make_parents:

If true, create the parent directory of the file if it doesn’t exist

delete_failures:

If true, the temporary file is deleted if there is an exception

follow_symlinks:

If true, overwrite the file pointed to and not the symlink

temp_file:

If true use a disk file and os.rename() at the end, otherwise cache the writes in memory. If it’s a string, use this as the name of the temporary file, otherwise select one in the same directory as the target file, or in the system tempfile for streams that aren’t files.

The remaining arguments are the same as for built-in open().

safer.closer(stream, is_binary=None, close_on_exit=False)

Like safer.writer() but with close_on_exit=True by default

ARGUMENTS
stream:

A file stream, a socket, or a callable that will receive data

is_binary:

Is stream a binary stream?

If is_binary is None, deduce whether it’s a binary file from the stream, or assume it’s text otherwise.

safer.printer(name, mode=’r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, follow_symlinks=True, make_parents=False, delete_failures=True, temp_file=True)

A context manager that yields a function that prints to the opened file, only overwriting the original file at the exit of the context, and only if there was no exception thrown

If the mode argument contains either 'a' (append), or '+' (update), then the original file will be copied to the temporary file before writing starts.

Note that safer uses an extra temporary file which is renamed over the file only after the stream closes without failing. This uses as much disk space as the old and new files put together.

ARGUMENTS
make_parents:

If true, create the parent directory of the file if it doesn’t exist

delete_failures:

If true, the temporary file is deleted if there is an exception

follow_symlinks:

If true, overwrite the file pointed to and not the symlink

temp_file:

If true use a disk file and os.rename() at the end, otherwise cache the writes in memory. If it’s a string, use this as the name of the temporary file, otherwise select one in the same directory as the target file, or in the system tempfile for streams that aren’t files.

The remaining arguments are the same as for built-in open().

ARGUMENTS
make_parents:

If true, create the parent directory of the file if it doesn’t exist

delete_failures:

If true, the temporary file is deleted if there is an exception

follow_symlinks:

If true, overwrite the file pointed to and not the symlink

temp_file:

If true use a disk file and os.rename() at the end, otherwise cache the writes in memory. If it’s a string, use this as the name of the temporary file, otherwise select one in the same directory as the target file, or in the system tempfile for streams that aren’t files.

The remaining arguments are the same as for built-in open().

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

safer-3.1.2.tar.gz (9.6 kB view details)

Uploaded Source

Built Distribution

safer-3.1.2-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file safer-3.1.2.tar.gz.

File metadata

  • Download URL: safer-3.1.2.tar.gz
  • Upload date:
  • Size: 9.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/45.1.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.8.1

File hashes

Hashes for safer-3.1.2.tar.gz
Algorithm Hash digest
SHA256 c4db5dbd01d6c167f316770bac0ef429da5eee9529bf2f7870b8ade9d1a2053f
MD5 64f8487fdcb57a7943ea02982cade74c
BLAKE2b-256 80a05e3fd2b5b9fea329ac673c1bbea83af3266ef7d0e84ccbe4c36cfe4c583d

See more details on using hashes here.

File details

Details for the file safer-3.1.2-py3-none-any.whl.

File metadata

  • Download URL: safer-3.1.2-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/45.1.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.8.1

File hashes

Hashes for safer-3.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 8444cb98e0b395c02e342504bb2d95a877d6967e5fb98540bdbfea4e0db334f3
MD5 39d39b3118075bf58e512ec68e43d20c
BLAKE2b-256 189e85a9d3516eb2fec076ba442be901cc7fc4205c2cb8eaf2ef2efca01a89e1

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page