Skip to content

Commit

Permalink
Merge pull request #8 from TkTech/big_numbers
Browse files Browse the repository at this point in the history
Support for serializing and deserializing Decimals.
  • Loading branch information
TkTech authored Nov 15, 2024
2 parents 2d885d9 + 34c8d0c commit 68e9ba7
Show file tree
Hide file tree
Showing 18 changed files with 3,243 additions and 1,355 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 3.1.0
current_version = 4.0.0
commit = True
tag = True

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ubuntu-20.04, windows-2019, macos-11]
py: ["cp38", "cp39", "cp310", "cp311", "cp312", "pp38", "pp39", "pp310"]
os: [ubuntu-latest, windows-latest, macos-11]
py: ["cp39", "cp310", "cp311", "cp312", "cp313", "pp38", "pp39", "pp310"]

steps:
- uses: actions/[email protected]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v3
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ _build/
*.egg-info
*.so
dist/
.idea
.idea
.vscode/settings.json
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

# py_yyjson

![py_yyjson Logo](misc/logo_small.png)

Fast, flexible Python bindings for the excellent [yyjson][] project.

## Documentation
Expand Down
34 changes: 17 additions & 17 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

# -- Project information -----------------------------------------------------

project = 'py_yyjson'
copyright = '2022, Tyler Kennedy <[email protected]>'
author = 'Tyler Kennedy'
project = "py_yyjson"
copyright = "2022, Tyler Kennedy <[email protected]>"
author = "Tyler Kennedy"


# -- General configuration ---------------------------------------------------
Expand All @@ -28,49 +28,49 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
'sphinx.ext.todo',
'sphinx.ext.doctest',
'sphinx_copybutton'
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"sphinx.ext.todo",
"sphinx.ext.doctest",
"sphinx_copybutton",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
language = "en"

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'furo'
html_title = '[py]yyjson'
html_theme = "furo"
html_title = "[py]yyjson"
html_logo = "../misc/logo_small.png"

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]

html_theme_options = {
}
html_theme_options = {}


# -- Extension configuration -------------------------------------------------

# -- Options for todo extension ----------------------------------------------

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
todo_include_todos = True
198 changes: 155 additions & 43 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,53 @@
Python bindings to the fantastic `yyjson`_ project. This module provides a fast,
flexible, portable, and correct JSON parser and serializer.

Binary packages are provided for many versions of Python on many architectures,
and only requires a C89-compliant compiler when building from source.
.. image:: https://img.shields.io/github/sponsors/tktech
:alt: GitHub Sponsors

Sales Pitch
-----------
.. image:: https://img.shields.io/pypi/l/yyjson
:alt: PyPI - License

[py]yyjson is several times faster than the builtin JSON module, and is faster
than most other JSON libraries. It's also more flexible, allowing you to parse
JSON with strict specification compliance, or with extensions such as comments,
trailing commas, Inf/NaN, and more.
.. image:: https://img.shields.io/pypi/v/yyjson
:alt: PyPI - Version

For all Python JSON libraries, the majority of time isn't spent parsing the
JSON, it's spent creating Python objects to represent that JSON. [py]yyjson
can provide significant speedups by avoiding creating Python objects for the
entire document, allowing you to extract just the parts of the document you
actually care about. It also provides facilities for manipulating the
document in native code, such as performing a JSON Merge-Patch (RFC 7386)
or a JSON Patch (RFC 6902), avoiding creating Python objects entirely.

[py]yyjson is a lightweight project dependency with low maintenance overhead.
It's written in C, and has no dependencies other than a C89 compiler. It's
licensed under the MIT license, so you can use it in any project, even
commercial ones. Pre-built binary wheels are available for many versions of
Python on many architectures, such as x86, x86_64, ARM, and ARM64, PowerPC,
IBM Z, and more. PyPy is also supported.
Features
--------

- **Fast**: `yyjson` is several times faster than the builtin JSON module, and
is `faster than most other JSON libraries <https://github.com/tktech/json_benchmark>`_.
- **Flexible**: Parse JSON with strict specification compliance, or with
extensions such as comments, trailing commas, Inf/NaN, numbers of any size,
and more.
- **Lightweight**: `yyjson` is a lightweight project dependency with low
maintenance overhead. It's written in C, and has no dependencies other than
a C89 compiler. Built wheels are between 50kb and 800kb depending on the
platform.
- **Portable**: Binary wheels are available for many versions of Python
on many architectures, such as x86, x86_64, ARM, and ARM64, PowerPC, IBM Z,
and more. PyPy is also supported. Supports Python 3.9 and newer.
- **Manipulate documents**: The fastest JSON Merge-Patch (RFC 7386), JSON Patch
(RFC 6902), and JSON Pointer (RFC 6901) implementations available for Python
allow you to manipulate JSON documents without deserializing them into Python
objects.
- **Traceable**: `yyjson` uses Python's memory allocator by default, so you can
trace memory leaks and other memory issues using Python's built-in tools.


Installation
------------

If binary wheels are available for your platform, you can install the latest
version of [py]yyjson with pip:
version of yyjson with pip:

pip install yyjson

If you want to build from source, or if binary wheels aren't available, you'll
need a C89 compiler, such as GCC or Clang.
just need a C89 compiler, such as GCC or Clang.

Or you can install the latest development version from GitHub:

pip install git+https://github.com/tktech/py_yyjson.git


Benchmarks
Expand All @@ -59,35 +69,68 @@ libraries.
Examples
--------

Load a document
^^^^^^^^^^^^^^^
Parsing
^^^^^^^

Simply parse an entire JSON document to a Python object::
Parse a JSON document from a file:

from pathlib import Path
from yyjson import Document
.. code-block:: python
>>> from pathlib import Path
>>> from yyjson import Document
>>> doc = Document(Path("canada.json")).as_obj
>>> doc
{'type': 'FeatureCollection', 'features': [...], 'bbox': [...], 'crs': {...}}
Parse a JSON document from a string:

.. code-block:: python
doc = Document(Path("canada.json")).as_obj
>>> from yyjson import Document
>>> doc = Document('{"hello": "world"}').as_obj
>>> doc
{'hello': 'world'}
Parse a JSON document from a bytes object:

.. code-block:: python
>>> from yyjson import Document
>>> doc = Document(b'{"hello": "world"}').as_obj
>>> doc
{'hello': 'world'}
Load part of a document
^^^^^^^^^^^^^^^^^^^^^^^

Parse a JSON document, but only extract the part you care about by using
a JSON Pointer::
When you only need a small part of a document, you can use a JSON Pointer to
extract just the part you actually need. This can be a massive performance
improvement when working with large JSON documents, as most of the time
spent parsing JSON in Python is spent just creating the Python objects!

from pathlib import Path
from yyjson import Document
.. code-block:: python
doc = Document(Path("canada.json"))
features = doc.get_pointer("/features")
>> from pathlib import Path
>> from yyjson import Document
>>> doc = Document(Path("canada.json"))
>>> features = doc.get_pointer("/features")
Patch a document
^^^^^^^^^^^^^^^^

Add an entry to a GeoJSON file without deserializing the entire document
into Python objects::
JSON manipulation operations are supported, such as
`JSON Merge-Patch <https://tools.ietf.org/html/rfc7386>`_ and
`JSON Patch <https://tools.ietf.org/html/rfc6902>`_. These operations
allow you to manipulate JSON documents without deserializing them into
Python objects at all.

For example, lets add an entry to a GeoJSON file without deserializing
the entire document into Python objects using JSON Patch:

.. code-block:: python
from pathlib import Path
from yyjson import Document
Expand All @@ -112,14 +155,83 @@ into Python objects::
Serialize an object
^^^^^^^^^^^^^^^^^^^
Serialize a Python object to JSON::
Serialize a Python object to JSON:
from yyjson import Document
.. code-block:: python
>>> from yyjson import Document
>>> doc = Document({
... "hello": "world",
... "foo": [1, 2, 3],
... "bar": {"a": 1, "b": 2}
... })
>>> doc.dumps()
'{"hello":"world","foo":[1,2,3],"bar":{"a":1,"b":2}}'
Customizing JSON Reading & Writing
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can customize the JSON reading and writing process using
:class:`yyjson.ReaderFlags` and :class:`yyjson.WriterFlags`. For example
if we wanted to allow comments and trailing commas, we could do:
.. code-block:: python
>>> from yyjson import Document, ReaderFlags, WriterFlags
>>> doc = Document(
... '{"hello": "world",} // This is a comment',
... ReaderFlags.ALLOW_COMMENTS | ReaderFlags.ALLOW_TRAILING_COMMAS
... )
Likewise we can customize the writing process:
.. code-block:: python
>>> from yyjson import Document, ReaderFlags, WriterFlags
>>> doc = Document({
... "hello": "world"
... })
>>> doc.dumps(flags=WriterFlags.PRETTY_TWO_SPACES)
Reading Huge Numbers
^^^^^^^^^^^^^^^^^^^^
If you're reading huge floats/doubles or require perfect precision, you can
tell yyjson to read them as Decimals:
.. code-block:: python
>>> from yyjson import Document, ReaderFlags
>>> float('1.7976931348623157e+310')
inf
>>> doc = Document(
... '{"huge": 1.7976931348623157e+310}',
... flags=ReaderFlags.NUMBERS_AS_DECIMAL
... )
>>> print(doc.get_pointer('/huge'))
1.7976931348623157E+310
Or use ``ReaderFlags.BIG_NUMBERS_AS_DECIMAL`` to only read numbers that are
too large for Python's float type as Decimals:
.. code-block:: python
>>> from yyjson import Document, ReaderFlags
>>> doc = Document(
'{"huge": 1.7976931348623157e+310, "small": 1.0}',
flags=ReaderFlags.BIG_NUMBERS_AS_DECIMAL
)
>>> type(doc.get_pointer('/huge'))
<class 'decimal.Decimal'>
>>> type(doc.get_pointer('/small'))
<class 'float'>
doc = Document({
"hello": "world"
})
print(doc.dumps())
.. _yyjson: https://github.com/ibireme/yyjson
.. _json_benchmark: https://github.com/tktech/json_benchmark
Binary file added misc/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added misc/logo_small.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 68e9ba7

Please sign in to comment.