Skip to content

Commit 68e9ba7

Browse files
authored
Merge pull request #8 from TkTech/big_numbers
Support for serializing and deserializing Decimals.
2 parents 2d885d9 + 34c8d0c commit 68e9ba7

18 files changed

+3243
-1355
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 3.1.0
2+
current_version = 4.0.0
33
commit = True
44
tag = True
55

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ jobs:
4848
strategy:
4949
fail-fast: true
5050
matrix:
51-
os: [ubuntu-20.04, windows-2019, macos-11]
52-
py: ["cp38", "cp39", "cp310", "cp311", "cp312", "pp38", "pp39", "pp310"]
51+
os: [ubuntu-latest, windows-latest, macos-11]
52+
py: ["cp39", "cp310", "cp311", "cp312", "cp313", "pp38", "pp39", "pp310"]
5353

5454
steps:
5555
- uses: actions/[email protected]

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
fail-fast: false
1616
matrix:
1717
os: [ubuntu-latest, macos-latest, windows-latest]
18-
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
18+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
1919

2020
steps:
2121
- uses: actions/checkout@v3

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ _build/
88
*.egg-info
99
*.so
1010
dist/
11-
.idea
11+
.idea
12+
.vscode/settings.json

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
# py_yyjson
55

6+
![py_yyjson Logo](misc/logo_small.png)
7+
68
Fast, flexible Python bindings for the excellent [yyjson][] project.
79

810
## Documentation

docs/conf.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717

1818
# -- Project information -----------------------------------------------------
1919

20-
project = 'py_yyjson'
21-
copyright = '2022, Tyler Kennedy <[email protected]>'
22-
author = 'Tyler Kennedy'
20+
project = "py_yyjson"
21+
copyright = "2022, Tyler Kennedy <[email protected]>"
22+
author = "Tyler Kennedy"
2323

2424

2525
# -- General configuration ---------------------------------------------------
@@ -28,49 +28,49 @@
2828
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
2929
# ones.
3030
extensions = [
31-
'sphinx.ext.autodoc',
32-
'sphinx.ext.viewcode',
33-
'sphinx.ext.todo',
34-
'sphinx.ext.doctest',
35-
'sphinx_copybutton'
31+
"sphinx.ext.autodoc",
32+
"sphinx.ext.viewcode",
33+
"sphinx.ext.todo",
34+
"sphinx.ext.doctest",
35+
"sphinx_copybutton",
3636
]
3737

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

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

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

5353

5454
# -- Options for HTML output -------------------------------------------------
5555

5656
# The theme to use for HTML and HTML Help pages. See the documentation for
5757
# a list of builtin themes.
5858
#
59-
html_theme = 'furo'
60-
html_title = '[py]yyjson'
59+
html_theme = "furo"
60+
html_title = "[py]yyjson"
61+
html_logo = "../misc/logo_small.png"
6162

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

67-
html_theme_options = {
68-
}
68+
html_theme_options = {}
6969

7070

7171
# -- Extension configuration -------------------------------------------------
7272

7373
# -- Options for todo extension ----------------------------------------------
7474

7575
# If true, `todo` and `todoList` produce output, else they produce nothing.
76-
todo_include_todos = True
76+
todo_include_todos = True

docs/index.rst

Lines changed: 155 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,53 @@
1010
Python bindings to the fantastic `yyjson`_ project. This module provides a fast,
1111
flexible, portable, and correct JSON parser and serializer.
1212

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

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

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

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

32-
[py]yyjson is a lightweight project dependency with low maintenance overhead.
33-
It's written in C, and has no dependencies other than a C89 compiler. It's
34-
licensed under the MIT license, so you can use it in any project, even
35-
commercial ones. Pre-built binary wheels are available for many versions of
36-
Python on many architectures, such as x86, x86_64, ARM, and ARM64, PowerPC,
37-
IBM Z, and more. PyPy is also supported.
23+
Features
24+
--------
25+
26+
- **Fast**: `yyjson` is several times faster than the builtin JSON module, and
27+
is `faster than most other JSON libraries <https://github.com/tktech/json_benchmark>`_.
28+
- **Flexible**: Parse JSON with strict specification compliance, or with
29+
extensions such as comments, trailing commas, Inf/NaN, numbers of any size,
30+
and more.
31+
- **Lightweight**: `yyjson` is a lightweight project dependency with low
32+
maintenance overhead. It's written in C, and has no dependencies other than
33+
a C89 compiler. Built wheels are between 50kb and 800kb depending on the
34+
platform.
35+
- **Portable**: Binary wheels are available for many versions of Python
36+
on many architectures, such as x86, x86_64, ARM, and ARM64, PowerPC, IBM Z,
37+
and more. PyPy is also supported. Supports Python 3.9 and newer.
38+
- **Manipulate documents**: The fastest JSON Merge-Patch (RFC 7386), JSON Patch
39+
(RFC 6902), and JSON Pointer (RFC 6901) implementations available for Python
40+
allow you to manipulate JSON documents without deserializing them into Python
41+
objects.
42+
- **Traceable**: `yyjson` uses Python's memory allocator by default, so you can
43+
trace memory leaks and other memory issues using Python's built-in tools.
3844

3945

4046
Installation
4147
------------
4248

4349
If binary wheels are available for your platform, you can install the latest
44-
version of [py]yyjson with pip:
50+
version of yyjson with pip:
4551

4652
pip install yyjson
4753

4854
If you want to build from source, or if binary wheels aren't available, you'll
49-
need a C89 compiler, such as GCC or Clang.
55+
just need a C89 compiler, such as GCC or Clang.
56+
57+
Or you can install the latest development version from GitHub:
58+
59+
pip install git+https://github.com/tktech/py_yyjson.git
5060

5161

5262
Benchmarks
@@ -59,35 +69,68 @@ libraries.
5969
Examples
6070
--------
6171

62-
Load a document
63-
^^^^^^^^^^^^^^^
72+
Parsing
73+
^^^^^^^
6474

65-
Simply parse an entire JSON document to a Python object::
75+
Parse a JSON document from a file:
6676

67-
from pathlib import Path
68-
from yyjson import Document
77+
.. code-block:: python
78+
79+
>>> from pathlib import Path
80+
>>> from yyjson import Document
81+
>>> doc = Document(Path("canada.json")).as_obj
82+
>>> doc
83+
{'type': 'FeatureCollection', 'features': [...], 'bbox': [...], 'crs': {...}}
84+
85+
86+
Parse a JSON document from a string:
87+
88+
.. code-block:: python
6989
70-
doc = Document(Path("canada.json")).as_obj
90+
>>> from yyjson import Document
91+
>>> doc = Document('{"hello": "world"}').as_obj
92+
>>> doc
93+
{'hello': 'world'}
94+
95+
Parse a JSON document from a bytes object:
96+
97+
.. code-block:: python
98+
99+
>>> from yyjson import Document
100+
>>> doc = Document(b'{"hello": "world"}').as_obj
101+
>>> doc
102+
{'hello': 'world'}
71103
72104
73105
Load part of a document
74106
^^^^^^^^^^^^^^^^^^^^^^^
75107

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

79-
from pathlib import Path
80-
from yyjson import Document
113+
.. code-block:: python
81114
82-
doc = Document(Path("canada.json"))
83-
features = doc.get_pointer("/features")
115+
>> from pathlib import Path
116+
>> from yyjson import Document
117+
>>> doc = Document(Path("canada.json"))
118+
>>> features = doc.get_pointer("/features")
84119
85120
86121
Patch a document
87122
^^^^^^^^^^^^^^^^
88123

89-
Add an entry to a GeoJSON file without deserializing the entire document
90-
into Python objects::
124+
JSON manipulation operations are supported, such as
125+
`JSON Merge-Patch <https://tools.ietf.org/html/rfc7386>`_ and
126+
`JSON Patch <https://tools.ietf.org/html/rfc6902>`_. These operations
127+
allow you to manipulate JSON documents without deserializing them into
128+
Python objects at all.
129+
130+
For example, lets add an entry to a GeoJSON file without deserializing
131+
the entire document into Python objects using JSON Patch:
132+
133+
.. code-block:: python
91134
92135
from pathlib import Path
93136
from yyjson import Document
@@ -112,14 +155,83 @@ into Python objects::
112155
Serialize an object
113156
^^^^^^^^^^^^^^^^^^^
114157
115-
Serialize a Python object to JSON::
158+
Serialize a Python object to JSON:
116159
117-
from yyjson import Document
160+
.. code-block:: python
161+
162+
>>> from yyjson import Document
163+
>>> doc = Document({
164+
... "hello": "world",
165+
... "foo": [1, 2, 3],
166+
... "bar": {"a": 1, "b": 2}
167+
... })
168+
>>> doc.dumps()
169+
'{"hello":"world","foo":[1,2,3],"bar":{"a":1,"b":2}}'
170+
171+
172+
Customizing JSON Reading & Writing
173+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
174+
175+
You can customize the JSON reading and writing process using
176+
:class:`yyjson.ReaderFlags` and :class:`yyjson.WriterFlags`. For example
177+
if we wanted to allow comments and trailing commas, we could do:
178+
179+
180+
.. code-block:: python
181+
182+
>>> from yyjson import Document, ReaderFlags, WriterFlags
183+
>>> doc = Document(
184+
... '{"hello": "world",} // This is a comment',
185+
... ReaderFlags.ALLOW_COMMENTS | ReaderFlags.ALLOW_TRAILING_COMMAS
186+
... )
187+
188+
189+
Likewise we can customize the writing process:
190+
191+
192+
.. code-block:: python
193+
194+
>>> from yyjson import Document, ReaderFlags, WriterFlags
195+
>>> doc = Document({
196+
... "hello": "world"
197+
... })
198+
>>> doc.dumps(flags=WriterFlags.PRETTY_TWO_SPACES)
199+
200+
201+
Reading Huge Numbers
202+
^^^^^^^^^^^^^^^^^^^^
203+
204+
If you're reading huge floats/doubles or require perfect precision, you can
205+
tell yyjson to read them as Decimals:
206+
207+
.. code-block:: python
208+
209+
>>> from yyjson import Document, ReaderFlags
210+
>>> float('1.7976931348623157e+310')
211+
inf
212+
>>> doc = Document(
213+
... '{"huge": 1.7976931348623157e+310}',
214+
... flags=ReaderFlags.NUMBERS_AS_DECIMAL
215+
... )
216+
>>> print(doc.get_pointer('/huge'))
217+
1.7976931348623157E+310
218+
219+
220+
Or use ``ReaderFlags.BIG_NUMBERS_AS_DECIMAL`` to only read numbers that are
221+
too large for Python's float type as Decimals:
222+
223+
.. code-block:: python
224+
225+
>>> from yyjson import Document, ReaderFlags
226+
>>> doc = Document(
227+
'{"huge": 1.7976931348623157e+310, "small": 1.0}',
228+
flags=ReaderFlags.BIG_NUMBERS_AS_DECIMAL
229+
)
230+
>>> type(doc.get_pointer('/huge'))
231+
<class 'decimal.Decimal'>
232+
>>> type(doc.get_pointer('/small'))
233+
<class 'float'>
118234
119-
doc = Document({
120-
"hello": "world"
121-
})
122-
print(doc.dumps())
123235
124236
.. _yyjson: https://github.com/ibireme/yyjson
125237
.. _json_benchmark: https://github.com/tktech/json_benchmark

misc/logo.png

222 KB
Loading

misc/logo_small.png

40.4 KB
Loading

0 commit comments

Comments
 (0)