Name | jsonlight JSON |
Version |
0.0.7
JSON |
| download |
home_page | https://yourlabs.io/oss/jsonlight |
Summary | json with rudimentary type encoding/decoding for Python |
upload_time | 2024-09-17 17:11:55 |
maintainer | None |
docs_url | None |
author | James Pic |
requires_python | None |
license | MIT |
keywords |
cli
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
jsonlight: json with rudimentary type encoding/decoding for Python
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adds support for a couple of new Python magic methods to make Python object
oriented JSON encoding and decoding a bit easier, with the following goals in
mind:
- jsonlight.dumps should always work, even if it has to fallback to a string
- it detects if an object being dumped defines a ``__jsondump__`` method
- it detects if an object being dumped is of a type defined in the global
typemap, or the one that's being used
- for complete round-tripping, the type schema is maintained in a
``__jsonload__`` method that you must implement
Standard types
--------------
This is what you can already do in Python:
.. code:: python
from json import loads, dumps
from uuid import UUID, uuid4
obj = uuid4()
assert obj == UUID(loads(dumps(str(obj))))
All standard Python types such as UUID must have an encode/decode method in the
default typemap provided by jsonlight, so encoding to JSON should always work.
However, the type must be specified on load:
.. code:: python
from jsonlight import loads, dumps
from uuid import UUID, uuid4
obj = uuid4()
assert obj == loads(UUID, dumps(obj))
You can see that the main difference with ``json.loads`` is that
``jsonlight.loads`` requires a type as first argument. This is because
``jsonlight.loads`` will first call ``json.loads`` to convert the string into a
Python object with basic JSON tyes, and then pass that to the type's
``__jsonload__`` function, or rely on the typemap defined functions if any.
Nested types
------------
You may leverage the ``__jsondump__`` and ``__jsonload__`` methods based on the
following conventions:
- ``__jsondump__``: return a representation of self with JSON data types
- ``__jsonload__``: instanciate an object based on the result from __jsondump__
Example:
.. code-block:: python
from jsonlight import load
class YourClass:
def __init__(self):
self.now = datetime.now()
def __jsondump__(self):
return dict(now=self.now)
@classmethod
def __jsonload__(cls, data):
return cls(load(datetime, data['now'])
As you can see:
- you don't have to worry about calling ``__jsondump__`` on return values of
your own ``__jsondump__`` because ``jsonlight.dumps`` will do that
recursively,
- you have full control on deserialization just like with ``__setstate__``, but
if you call jsonlight.load in there yourself then you don't have to
duplicate deserialization logic on nested objects,
Typemaps
--------
This lib must support all standard Python types, and it already works for
things like UUID or Path because they cast fine from and to strings. However,
this is not the case for datetimes and there is no JSON standard for datetimes.
Since it is a requirement for jsonlight to support all standard python types, a
default typemap is also included, which makes datetimes export to string with
``.isoformat()`` and from string with ``.fromisoformat()``:
.. code-block:: python
now = datetime.now()
assert now == loads(datetime, dumps(now))
This is the reason why we have typemaps. The typemap in jsonlight maps a Python
type to a couple of encoding/decoding functions, so that we have something that
works without monkey patching.
To illustrate how to use a specific typemap, let's decide we want to remove the
leading slash of all Path objects dumps and ensure there is one on load, we
will define our own typemap:
.. code-block:: python
typemap = {
Path: (
lambda value: str(value).lstrip('/'),
lambda data: Path('/' + data.lstrip('/')),
),
}
assert dumps(Path('/foo/bar'), typemap) == '"foo/bar"'
assert loads(Path, '"foo/bar"', typemap) == Path('/foo/bar')
A couple of possibilities are left to keep in mind:
- ``typemap.update(jsonlight.typemap)`` adds the default jsonlight typemap to
your own,
- ``jsonlight.typemap.update(typemap)`` adds your own typemap on top of the
default typemap.
Raw data
{
"_id": null,
"home_page": "https://yourlabs.io/oss/jsonlight",
"name": "jsonlight",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "cli",
"author": "James Pic",
"author_email": "jamespic@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/79/d7/e610d3f9a650562a36c1d7b77931061c2bc8226e752e8fa5d4874f315c4f/jsonlight-0.0.7.tar.gz",
"platform": null,
"description": "jsonlight: json with rudimentary type encoding/decoding for Python\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAdds support for a couple of new Python magic methods to make Python object\noriented JSON encoding and decoding a bit easier, with the following goals in\nmind:\n\n- jsonlight.dumps should always work, even if it has to fallback to a string\n- it detects if an object being dumped defines a ``__jsondump__`` method\n- it detects if an object being dumped is of a type defined in the global\n typemap, or the one that's being used\n- for complete round-tripping, the type schema is maintained in a\n ``__jsonload__`` method that you must implement\n\nStandard types\n--------------\n\nThis is what you can already do in Python:\n\n.. code:: python\n\n from json import loads, dumps\n from uuid import UUID, uuid4\n\n obj = uuid4()\n assert obj == UUID(loads(dumps(str(obj))))\n\nAll standard Python types such as UUID must have an encode/decode method in the\ndefault typemap provided by jsonlight, so encoding to JSON should always work.\nHowever, the type must be specified on load:\n\n.. code:: python\n\n from jsonlight import loads, dumps\n from uuid import UUID, uuid4\n\n obj = uuid4()\n assert obj == loads(UUID, dumps(obj))\n\nYou can see that the main difference with ``json.loads`` is that\n``jsonlight.loads`` requires a type as first argument. This is because\n``jsonlight.loads`` will first call ``json.loads`` to convert the string into a\nPython object with basic JSON tyes, and then pass that to the type's\n``__jsonload__`` function, or rely on the typemap defined functions if any.\n\nNested types\n------------\n\nYou may leverage the ``__jsondump__`` and ``__jsonload__`` methods based on the\nfollowing conventions:\n\n- ``__jsondump__``: return a representation of self with JSON data types\n- ``__jsonload__``: instanciate an object based on the result from __jsondump__\n\nExample:\n\n.. code-block:: python\n\n from jsonlight import load\n\n class YourClass:\n def __init__(self):\n self.now = datetime.now()\n\n def __jsondump__(self):\n return dict(now=self.now)\n\n @classmethod\n def __jsonload__(cls, data):\n return cls(load(datetime, data['now'])\n\n\nAs you can see:\n\n- you don't have to worry about calling ``__jsondump__`` on return values of\n your own ``__jsondump__`` because ``jsonlight.dumps`` will do that\n recursively,\n- you have full control on deserialization just like with ``__setstate__``, but\n if you call jsonlight.load in there yourself then you don't have to\n duplicate\u00a0deserialization logic on nested objects,\n\nTypemaps\n--------\n\nThis lib must support all standard Python types, and it already works for\nthings like UUID or Path because they cast fine from and to strings. However,\nthis is not the case for datetimes and there is no JSON standard for datetimes.\n\nSince it is a requirement for jsonlight to support all standard python types, a\ndefault typemap is also included, which makes datetimes export to string with\n``.isoformat()`` and from string with ``.fromisoformat()``:\n\n.. code-block:: python\n\n now = datetime.now()\n assert now == loads(datetime, dumps(now))\n\nThis is the reason why we have typemaps. The typemap in jsonlight maps a Python\ntype to a couple of encoding/decoding functions, so that we have something that\nworks without monkey patching.\n\nTo illustrate how to use a specific typemap, let's decide we want to remove the\nleading slash of all Path objects dumps and ensure there is one on load, we\nwill define our own typemap:\n\n.. code-block:: python\n\n typemap = {\n Path: (\n lambda value: str(value).lstrip('/'),\n lambda data: Path('/' + data.lstrip('/')),\n ),\n }\n assert dumps(Path('/foo/bar'), typemap) == '\"foo/bar\"'\n assert loads(Path, '\"foo/bar\"', typemap) == Path('/foo/bar')\n\nA couple of possibilities are left to keep in mind:\n\n- ``typemap.update(jsonlight.typemap)`` adds the default jsonlight typemap to\n your own,\n- ``jsonlight.typemap.update(typemap)`` adds your own typemap on top of the\n default typemap.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "json with rudimentary type encoding/decoding for Python",
"version": "0.0.7",
"project_urls": {
"Homepage": "https://yourlabs.io/oss/jsonlight"
},
"split_keywords": [
"cli"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "79d7e610d3f9a650562a36c1d7b77931061c2bc8226e752e8fa5d4874f315c4f",
"md5": "233f08afa42a54a25ff144df41ee54f8",
"sha256": "75bb22b79cbf7335a4a6052f035901b162cc446f22841bb39479c6fb91e6bf10"
},
"downloads": -1,
"filename": "jsonlight-0.0.7.tar.gz",
"has_sig": false,
"md5_digest": "233f08afa42a54a25ff144df41ee54f8",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 3161,
"upload_time": "2024-09-17T17:11:55",
"upload_time_iso_8601": "2024-09-17T17:11:55.226364Z",
"url": "https://files.pythonhosted.org/packages/79/d7/e610d3f9a650562a36c1d7b77931061c2bc8226e752e8fa5d4874f315c4f/jsonlight-0.0.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-17 17:11:55",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "jsonlight"
}