Name | safer JSON |
Version |
4.12.3
JSON |
| download |
home_page | https://github.com/rec/safer |
Summary | 🧿 A safer writer for files and streams 🧿 |
upload_time | 2024-01-15 10:21:50 |
maintainer | |
docs_url | None |
author | Tom Ritchford |
requires_python | >=3.8 |
license | MIT |
keywords |
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
|
coveralls test coverage |
No coveralls.
|
# 🧿 `safer`: A safer writer 🧿
Avoid partial writes or corruption!
`safer` wraps file streams, sockets, or a callable, and offers a drop-in
replacement for regular old `open()`.
## Quick summary
### A tiny example
import safer
with safer.open(filename, 'w') as fp:
fp.write('one')
print('two', file=fp)
raise ValueError
# filename was not written.
### How to use
Use [pip](https://pypi.org/project/pip) to install `safer` from the command
line: `pip install safer`.
Tested on Python 3.4 - 3.11. An old Python 2.7 version
is [here](https://github.com/rec/safer/tree/v2.0.5).
See the Medium article [here](https://medium.com/@TomSwirly/%EF%B8%8F-safer-a-safer-file-writer-%EF%B8%8F-5fe267dbe3f5)
### The details
`safer` helps prevent programmer error from corrupting files, socket
connections, or generalized streams by writing a whole file or nothing.
It does not prevent concurrent modification of files from other threads or
processes: if you need atomic file writing, see
https://pypi.org/project/atomicwrites/
It also has a useful `dry_run` setting to let you test your code without
actually overwriting the target file.
* `safer.writer()` wraps an existing writer, socket or stream and writes a
whole response or nothing
* `safer.open()` is a drop-in replacement for built-in `open` that
writes a whole file or nothing
* `safer.closer()` returns a stream like from `safer.write()` that also
closes the underlying stream or callable when it closes.
* `safer.dump()` is like a safer `json.dump()` which can be used for any
serialization protocol, including Yaml and Toml, and also allows you to
write to file streams or any other callable.
* `safer.printer()` is `safer.open()` except that it yields a
a function that prints to the stream.
By default, `safer` buffers the written data in memory in a `io.StringIO`
or `io.BytesIO`.
For very large files, `safer.open()` has a `temp_file` argument which
writes the data to a temporary file on disk, which is moved over using
`os.rename` if the operation completes successfully. This functionality
does not work on Windows. (In fact, it's unclear if any of this works on
Windows, but that certainly won't. Windows developer solicted!)
### Example: `safer.writer()`
`safer.writer()` wraps an existing stream - a writer, socket, or callback -
in a temporary stream which is only copied to the target stream at close(), and
only if no exception was raised.
Suppose `sock = socket.socket(*args)`.
The old, dangerous way goes like this.
try:
write_header(sock)
write_body(sock) # Exception is thrown here
write_footer(sock)
except Exception:
write_error(sock) # Oops, the header was already written
With `safer` you write all or nothing:
try:
with safer.writer(sock) as s:
write_header(s)
write_body(s) # Exception is thrown here
write_footer(s)
except Exception:
write_error(sock) # Nothing has been written
### Example: `safer.open()` and json
`safer.open()` is a a drop-in replacement for built-in `open()` except that
when used as a context, it leaves the original file unchanged on failure.
It's easy to write broken JSON if something within it doesn't serialize.
with open(filename, 'w') as fp:
json.dump(data, fp)
# If an exception is raised, the file is empty or partly written
`safer` prevents this:
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 memory stream or a temporary file in the
same directory.
If `fp` is used as a context manager and an exception is raised, then the
property `fp.safer_failed` on the stream is automatically set to `True`.
And when `fp.close()` is called, the cached data is stored in `filename` -
*unless* `fp.safer_failed` is true.
### Example: `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.
Before.
with open(file, 'w') as fp:
for item in items:
print(item, file=fp)
# Prints lines until the first exception
With `safer`
with safer.printer(file) as print:
for item in items:
print(item)
# Either the whole file is written, or nothing
### [API Documentation](https://rec.github.io/safer#safer--api-documentation)
Raw data
{
"_id": null,
"home_page": "https://github.com/rec/safer",
"name": "safer",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "",
"keywords": "",
"author": "Tom Ritchford",
"author_email": "tom@swirly.com",
"download_url": "https://files.pythonhosted.org/packages/ce/2a/c3335267939708bbf8d6a9bb7334b88057bdafd2a2234fbe38de169578f2/safer-4.12.3.tar.gz",
"platform": null,
"description": "# \ud83e\uddff `safer`: A safer writer \ud83e\uddff\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",
"bugtrack_url": null,
"license": "MIT",
"summary": "\ud83e\uddff A safer writer for files and streams \ud83e\uddff",
"version": "4.12.3",
"project_urls": {
"Documentation": "https://rec.github.io/safer",
"Homepage": "https://github.com/rec/safer",
"Repository": "https://github.com/rec/safer"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "a90ed6ebd4a5594750ed5ab06e76e9d652bc1058fc4b6bc7898d81d3ab04d0ea",
"md5": "2b1cbef9ac9e6cade4e1627437fe3cdd",
"sha256": "def5100a9eac29379ef7c8fac5f0232b80fbcb7915e1dcfcd35df1a282696663"
},
"downloads": -1,
"filename": "safer-4.12.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2b1cbef9ac9e6cade4e1627437fe3cdd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 10504,
"upload_time": "2024-01-15T10:21:49",
"upload_time_iso_8601": "2024-01-15T10:21:49.527130Z",
"url": "https://files.pythonhosted.org/packages/a9/0e/d6ebd4a5594750ed5ab06e76e9d652bc1058fc4b6bc7898d81d3ab04d0ea/safer-4.12.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "ce2ac3335267939708bbf8d6a9bb7334b88057bdafd2a2234fbe38de169578f2",
"md5": "192fab3d6478fd54b2359deb56ea74ff",
"sha256": "264eb65b2c4efa324099054015a07917cd7b31ae03f8f04471696b474890c9c1"
},
"downloads": -1,
"filename": "safer-4.12.3.tar.gz",
"has_sig": false,
"md5_digest": "192fab3d6478fd54b2359deb56ea74ff",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 8515,
"upload_time": "2024-01-15T10:21:50",
"upload_time_iso_8601": "2024-01-15T10:21:50.869598Z",
"url": "https://files.pythonhosted.org/packages/ce/2a/c3335267939708bbf8d6a9bb7334b88057bdafd2a2234fbe38de169578f2/safer-4.12.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-01-15 10:21:50",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "rec",
"github_project": "safer",
"travis_ci": true,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "safer"
}