safer 4.6.0__tar.gz → 4.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -63,7 +63,7 @@ or `io.BytesIO`.
|
|
|
63
63
|
|
|
64
64
|
For very large files, `safer.open()` has a `temp_file` argument which
|
|
65
65
|
writes the data to a temporary file on disk, which is moved over using
|
|
66
|
-
`os.
|
|
66
|
+
`os.replace` if the operation completes successfully. This functionality
|
|
67
67
|
does not work on Windows. (In fact, it's unclear if any of this works on
|
|
68
68
|
Windows, but that certainly won't. Windows developer solicted!)
|
|
69
69
|
|
|
@@ -201,7 +201,7 @@ def writer(
|
|
|
201
201
|
closes
|
|
202
202
|
|
|
203
203
|
temp_file: If `temp_file` is truthy, write to a disk file and use
|
|
204
|
-
os.
|
|
204
|
+
os.replace() at the end, otherwise cache the writes in memory.
|
|
205
205
|
|
|
206
206
|
If `temp_file` is a string, use it as the name of the temporary
|
|
207
207
|
file, otherwise select one in the same directory as the target
|
|
@@ -323,7 +323,7 @@ def open(
|
|
|
323
323
|
if there is an exception.
|
|
324
324
|
|
|
325
325
|
temp_file: If `temp_file` is truthy, write to a disk file and use
|
|
326
|
-
os.
|
|
326
|
+
os.replace() at the end, otherwise cache the writes in memory.
|
|
327
327
|
|
|
328
328
|
If `temp_file` is a string, use it as the name of the temporary
|
|
329
329
|
file, otherwise select one in the same directory as the target
|
|
@@ -385,15 +385,11 @@ def open(
|
|
|
385
385
|
os.makedirs(parent)
|
|
386
386
|
|
|
387
387
|
def simple_open():
|
|
388
|
-
print('simple_open', name, mode)
|
|
389
388
|
return __builtins__['open'](name, mode, buffering, **kwargs)
|
|
390
389
|
|
|
391
390
|
def simple_write(value):
|
|
392
|
-
print('simple_write', name, value)
|
|
393
391
|
with simple_open() as fp:
|
|
394
392
|
fp.write(value)
|
|
395
|
-
print('simple_write done')
|
|
396
|
-
print(__builtins__['open'](name).read())
|
|
397
393
|
|
|
398
394
|
if is_read or not enabled:
|
|
399
395
|
return simple_open()
|
|
@@ -647,7 +643,7 @@ class _FileRenameCloser(_FileCloser):
|
|
|
647
643
|
shutil.copymode(self.target_file, self.temp_file)
|
|
648
644
|
else:
|
|
649
645
|
os.chmod(self.temp_file, 0o100644)
|
|
650
|
-
os.
|
|
646
|
+
os.replace(self.temp_file, self.target_file)
|
|
651
647
|
|
|
652
648
|
|
|
653
649
|
class _StreamCloser(_Closer):
|
|
@@ -664,7 +660,6 @@ class _StreamCloser(_Closer):
|
|
|
664
660
|
closer(self.fp.safer_failed)
|
|
665
661
|
|
|
666
662
|
def _write_on_success(self, v):
|
|
667
|
-
print('_StreamCloser._write_on_success', v, self.write)
|
|
668
663
|
while True:
|
|
669
664
|
written = self.write(v)
|
|
670
665
|
v = (written is not None) and v[written:]
|
|
@@ -5,7 +5,7 @@ modules = \
|
|
|
5
5
|
['safer']
|
|
6
6
|
setup_kwargs = {
|
|
7
7
|
'name': 'safer',
|
|
8
|
-
'version': '4.
|
|
8
|
+
'version': '4.7.0',
|
|
9
9
|
'description': '🧿 A safer writer for files and streams 🧿',
|
|
10
10
|
'long_description': "# 🧿 `safer`: A safer writer 🧿\n\nAvoid partial writes or corruption!\n\n`safer` wraps file streams, sockets, or a callable, and offers a drop-in\nreplacement for regular old `open()`.\n\n## Quick summary\n\n### A tiny example\n\n import safer\n\n with safer.open(filename, 'w') as fp:\n fp.write('one')\n print('two', file=fp)\n raise ValueError\n # filename was not written.\n\n\n### How to use\n\nUse [pip](https://pypi.org/project/pip) to install `safer` from the command\nline: `pip install safer`.\n\nTested on Python 3.4 - 3.11. An old Python 2.7 version\nis [here](https://github.com/rec/safer/tree/v2.0.5).\n\nSee the Medium article [here](https://medium.com/@TomSwirly/%EF%B8%8F-safer-a-safer-file-writer-%EF%B8%8F-5fe267dbe3f5)\n\n### The details\n\n`safer` helps prevent programmer error from corrupting files, socket\nconnections, or generalized streams by writing a whole file or nothing.\n\nIt does not prevent concurrent modification of files from other threads or\nprocesses: if you need atomic file writing, see\nhttps://pypi.org/project/atomicwrites/\n\nIt also has a useful `dry_run` setting to let you test your code without\nactually overwriting the target file.\n\n* `safer.writer()` wraps an existing writer, socket or stream and writes a\n whole response or nothing\n\n* `safer.open()` is a drop-in replacement for built-in `open` that\n writes a whole file or nothing\n\n* `safer.closer()` returns a stream like from `safer.write()` that also\n closes the underlying stream or callable when it closes.\n\n* `safer.dump()` is like a safer `json.dump()` which can be used for any\n serialization protocol, including Yaml and Toml, and also allows you to\n write to file streams or any other callable.\n\n* `safer.printer()` is `safer.open()` except that it yields a\n a function that prints to the stream.\n\nBy default, `safer` buffers the written data in memory in a `io.StringIO`\nor `io.BytesIO`.\n\nFor very large files, `safer.open()` has a `temp_file` argument which\nwrites the data to a temporary file on disk, which is moved over using\n`os.rename` if the operation completes successfully. This functionality\ndoes not work on Windows. (In fact, it's unclear if any of this works on\nWindows, but that certainly won't. Windows developer solicted!)\n\n\n### Example: `safer.writer()`\n\n`safer.writer()` wraps an existing stream - a writer, socket, or callback -\nin a temporary stream which is only copied to the target stream at close(), and\nonly if no exception was raised.\n\nSuppose `sock = socket.socket(*args)`.\n\nThe old, dangerous way goes like this.\n\n try:\n write_header(sock)\n write_body(sock) # Exception is thrown here\n write_footer(sock)\n except Exception:\n write_error(sock) # Oops, the header was already written\n\nWith `safer` you write all or nothing:\n\n try:\n with safer.writer(sock) as s:\n write_header(s)\n write_body(s) # Exception is thrown here\n write_footer(s)\n except Exception:\n write_error(sock) # Nothing has been written\n\n### Example: `safer.open()` and json\n\n`safer.open()` is a a drop-in replacement for built-in `open()` except that\nwhen used as a context, it leaves the original file unchanged on failure.\n\nIt's easy to write broken JSON if something within it doesn't serialize.\n\n with open(filename, 'w') as fp:\n json.dump(data, fp)\n # If an exception is raised, the file is empty or partly written\n\n`safer` prevents this:\n\n with safer.open(filename, 'w') as fp:\n json.dump(data, fp)\n # If an exception is raised, the file is unchanged.\n\n`safer.open(filename)` returns a file stream `fp` like `open(filename)`\nwould, except that `fp` writes to memory stream or a temporary file in the\nsame directory.\n\nIf `fp` is used as a context manager and an exception is raised, then the\nproperty `fp.safer_failed` on the stream is automatically set to `True`.\n\nAnd when `fp.close()` is called, the cached data is stored in `filename` -\n*unless* `fp.safer_failed` is true.\n\n### Example: `safer.printer()`\n\n`safer.printer()` is similar to `safer.open()` except it yields a function\nthat prints to the open file - it's very convenient for printing text.\n\nLike `safer.open()`, if an exception is raised within its context manager,\nthe original file is left unchanged.\n\nBefore.\n\n with open(file, 'w') as fp:\n for item in items:\n print(item, file=fp)\n # Prints lines until the first exception\n\nWith `safer`\n\n with safer.printer(file) as print:\n for item in items:\n print(item)\n # Either the whole file is written, or nothing\n\n\n### [API Documentation](https://rec.github.io/safer#safer--api-documentation)\n",
|
|
11
11
|
'author': 'Tom Ritchford',
|
|
File without changes
|
|
File without changes
|