diff --git a/README.md b/README.md index 00c3f97..9d0c1a5 100644 --- a/README.md +++ b/README.md @@ -52,26 +52,26 @@ We recommend to use [`orjson`](https://pypi.org/project/orjson) or [`msgspec`](https://pypi.org/project/msgspec) for performance critical applications: -| encode | json | jsonyx | msgspec | orjson | rapidjson | unit (μs) | -|:--------------------------------------------| -----:|-------:|--------:|--------:|----------:|----------:| -| List of 256 booleans | 4.82 | 4.11 | 1.16 | 1.00 | 3.12 | 1.85 | -| List of 256 ASCII strings | 14.71 | 12.73 | 1.67 | 1.00 | 10.12 | 3.64 | -| List of 256 floats | 23.47 | 23.54 | 1.38 | 1.00 | 24.87 | 8.57 | -| List of 256 dicts with 1 int | 10.87 | 11.17 | 1.48 | 1.00 | 6.30 | 8.54 | -| Medium complex object | 9.90 | 9.76 | 1.24 | 1.00 | 7.31 | 14.48 | -| List of 256 strings | 26.73 | 14.99 | 2.26 | 1.00 | 34.28 | 13.69 | -| Complex object | 7.80 | 5.55 | 1.00 | inf[^1] | 6.92 | 205.10 | -| Dict with 256 lists of 256 dicts with 1 int | 9.58 | 10.23 | 1.27 | 1.00 | 5.32 | 2517.22 | +| encode | json | jsonyx | msgspec | orjson | rapidjson | unit (μs) | +|:--------------------------------------------|------:|-------:|--------:|--------:|----------:|----------:| +| List of 256 booleans | 4.60 | 3.92 | 1.08 | 1.00 | 3.29 | 1.95 | +| List of 256 ASCII strings | 11.57 | 12.67 | 1.52 | 1.00 | 9.23 | 4.27 | +| List of 256 floats | 22.02 | 23.15 | 1.41 | 1.00 | 22.76 | 9.14 | +| List of 256 dicts with 1 int | 10.33 | 11.31 | 1.52 | 1.00 | 6.36 | 8.85 | +| Medium complex object | 9.68 | 10.13 | 1.22 | 1.00 | 6.71 | 15.26 | +| List of 256 strings | 21.84 | 11.63 | 2.12 | 1.00 | 30.21 | 14.97 | +| Complex object | 7.49 | 5.32 | 1.00 | inf[^1] | 6.71 | 207.61 | +| Dict with 256 lists of 256 dicts with 1 int | 8.40 | 9.14 | 1.20 | 1.00 | 5.04 | 2743.09 | -| decode | json | jsonyx | msgspec | orjson | rapidjson | unit (μs) | -|:--------------------------------------------|-----:|-------:|--------:|-------:|----------:|----------:| -| List of 256 booleans | 3.40 | 5.24 | 2.06 | 1.00 | 2.42 | 2.03 | -| List of 256 ASCII strings | 1.68 | 2.05 | 1.12 | 1.00 | 1.59 | 13.11 | -| List of 256 floats | 6.58 | 7.38 | 1.45 | 1.00 | 5.71 | 10.25 | -| List of 256 dicts with 1 int | 2.36 | 2.84 | 1.38 | 1.00 | 2.22 | 32.11 | -| Medium complex object | 2.89 | 3.70 | 1.23 | 1.00 | 2.62 | 33.99 | -| List of 256 strings | 1.02 | 1.00 | 2.74 | 2.04 | 2.99 | 64.38 | -| Complex object | 1.12 | 1.04 | 1.06 | 1.00 | 1.23 | 1061.41 | -| Dict with 256 lists of 256 dicts with 1 int | 1.66 | 1.91 | 1.14 | 1.00 | 1.47 | 17536.25 | +| decode | json | jsonyx | msgspec | orjson | rapidjson | simdjson | unit (μs) | +|:--------------------------------------------|------:|-------:|--------:|-------:|----------:|---------:|----------:| +| List of 256 booleans | 4.63 | 7.15 | 2.88 | 1.49 | 3.36 | 1.00 | 1.44 | +| List of 256 ASCII strings | 6.51 | 7.98 | 4.32 | 3.81 | 6.12 | 1.00 | 3.37 | +| List of 256 floats | 10.81 | 11.92 | 2.28 | 1.57 | 9.39 | 1.00 | 6.20 | +| List of 256 dicts with 1 int | 12.04 | 14.29 | 6.73 | 4.98 | 11.07 | 1.00 | 6.31 | +| Medium complex object | 11.84 | 15.33 | 5.02 | 4.00 | 10.61 | 1.00 | 8.25 | +| List of 256 strings | 4.68 | 3.22 | 8.06 | 6.49 | 9.21 | 1.00 | 20.25 | +| Complex object | 9.12 | 8.55 | 8.99 | 8.16 | 10.25 | 1.00 | 132.89 | +| Dict with 256 lists of 256 dicts with 1 int | 17.42 | 19.91 | 11.83 | 11.09 | 15.17 | 1.00 | 1752.60 | [^1]: failed due to recursion error \ No newline at end of file diff --git a/bench/__main__.py b/bench/__main__.py index 73e22cf..f039cf6 100644 --- a/bench/__main__.py +++ b/bench/__main__.py @@ -15,6 +15,7 @@ import msgspec import orjson import rapidjson +import simdjson from tabulate import tabulate # type: ignore import jsonyx @@ -94,6 +95,7 @@ "orjson": orjson.loads, # pylint: disable-next=I1101 "rapidjson": rapidjson.Decoder(), + "simdjson": simdjson.Parser().parse, } @@ -122,7 +124,7 @@ def _run_benchmark( row.append(1_000_000 * unit) results.append(row) - headers: list[str] = [name, *funcs.keys(), "unit\u00a0(\u03bcs)"] + headers: list[str] = [name, *funcs.keys(), "unit\xa0(\u03bcs)"] print() print(tabulate(results, headers, tablefmt="pipe", floatfmt=".02f")) print(tabulate(results, headers, tablefmt="rst", floatfmt=".02f")) diff --git a/bench/requirements.txt b/bench/requirements.txt index 74b5fc1..cf683c3 100644 --- a/bench/requirements.txt +++ b/bench/requirements.txt @@ -1,4 +1,5 @@ msgspec==0.18.6 orjson==3.10.7 +pysimdjson==6.0.2 python-rapidjson==1.20 tabulate==0.9.0 diff --git a/docs/source/index.rst b/docs/source/index.rst index b0394b7..009488a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -51,34 +51,34 @@ performance and no dependencies. .. rubric:: Benchmark -We recommend to use :pypi:`orjson` or :pypi:`msgspec` for performance critical -applications: - -=========================================== ===== ====== ======= ======== ========= ========= -encode json jsonyx msgspec orjson rapidjson unit (μs) -=========================================== ===== ====== ======= ======== ========= ========= -List of 256 booleans 4.82 4.11 1.16 1.00 3.12 1.85 -List of 256 ASCII strings 14.71 12.73 1.67 1.00 10.12 3.64 -List of 256 floats 23.47 23.54 1.38 1.00 24.87 8.57 -List of 256 dicts with 1 int 10.87 11.17 1.48 1.00 6.30 8.54 -Medium complex object 9.90 9.76 1.24 1.00 7.31 14.48 -List of 256 strings 26.73 14.99 2.26 1.00 34.28 13.69 -Complex object 7.80 5.55 1.00 inf [1]_ 6.92 205.10 -Dict with 256 lists of 256 dicts with 1 int 9.58 10.23 1.27 1.00 5.32 2517.22 -=========================================== ===== ====== ======= ======== ========= ========= - -=========================================== ==== ====== ======= ====== ========= ========= -decode json jsonyx msgspec orjson rapidjson unit (μs) -=========================================== ==== ====== ======= ====== ========= ========= -List of 256 booleans 3.40 5.24 2.06 1.00 2.42 2.03 -List of 256 ASCII strings 1.68 2.05 1.12 1.00 1.59 13.11 -List of 256 floats 6.58 7.38 1.45 1.00 5.71 10.25 -List of 256 dicts with 1 int 2.36 2.84 1.38 1.00 2.22 32.11 -Medium complex object 2.89 3.70 1.23 1.00 2.62 33.99 -List of 256 strings 1.02 1.00 2.74 2.04 2.99 64.38 -Complex object 1.12 1.04 1.06 1.00 1.23 1061.41 -Dict with 256 lists of 256 dicts with 1 int 1.66 1.91 1.14 1.00 1.47 17536.25 -=========================================== ==== ====== ======= ====== ========= ========= +We recommend to use :pypi:`orjson`, :pypi:`pysimdjson` or :pypi:`msgspec` for +performance critical applications: + +=========================================== ===== ====== ======= ======== ========= ========= +encode json jsonyx msgspec orjson rapidjson unit (μs) +=========================================== ===== ====== ======= ======== ========= ========= +List of 256 booleans 4.60 3.92 1.08 1.00 3.29 1.95 +List of 256 ASCII strings 11.57 12.67 1.52 1.00 9.23 4.27 +List of 256 floats 22.02 23.15 1.41 1.00 22.76 9.14 +List of 256 dicts with 1 int 10.33 11.31 1.52 1.00 6.36 8.85 +Medium complex object 9.68 10.13 1.22 1.00 6.71 15.26 +List of 256 strings 21.84 11.63 2.12 1.00 30.21 14.97 +Complex object 7.49 5.32 1.00 inf [1]_ 6.71 207.61 +Dict with 256 lists of 256 dicts with 1 int 8.40 9.14 1.20 1.00 5.04 2743.09 +=========================================== ===== ====== ======= ======== ========= ========= + +=========================================== ===== ====== ======= ====== ========= ======== ========= +decode json jsonyx msgspec orjson rapidjson simdjson unit (μs) +=========================================== ===== ====== ======= ====== ========= ======== ========= +List of 256 booleans 4.63 7.15 2.88 1.49 3.36 1.00 1.44 +List of 256 ASCII strings 6.51 7.98 4.32 3.81 6.12 1.00 3.37 +List of 256 floats 10.81 11.92 2.28 1.57 9.39 1.00 6.20 +List of 256 dicts with 1 int 12.04 14.29 6.73 4.98 11.07 1.00 6.31 +Medium complex object 11.84 15.33 5.02 4.00 10.61 1.00 8.25 +List of 256 strings 4.68 3.22 8.06 6.49 9.21 1.00 20.25 +Complex object 9.12 8.55 8.99 8.16 10.25 1.00 132.89 +Dict with 256 lists of 256 dicts with 1 int 17.42 19.91 11.83 11.09 15.17 1.00 1752.60 +=========================================== ===== ====== ======= ====== ========= ======== ========= Check out the :doc:`get-started` section for further information, including how to :ref:`install ` the project. diff --git a/src/jsonyx/_manipulator.py b/src/jsonyx/_manipulator.py index 62dc9c4..239add6 100644 --- a/src/jsonyx/_manipulator.py +++ b/src/jsonyx/_manipulator.py @@ -303,6 +303,7 @@ def _run_select_query( for target, key in nodes: _check_query_key(target, key, allow_slice=True) + # TODO(Nice Zombies): exclude None nodes = [ (target, key) for (target, key) in nodes diff --git a/src/jsonyx/test/test_run_select_query.py b/src/jsonyx/test/test_run_select_query.py index 60487e1..17c5166 100644 --- a/src/jsonyx/test/test_run_select_query.py +++ b/src/jsonyx/test/test_run_select_query.py @@ -29,6 +29,7 @@ def __getitem__(item: slice) -> slice: _slicer: _Slicer = _Slicer() +# TODO(Nice Zombies): test with None @pytest.mark.parametrize(("node", "keep"), [ # List (([], slice(0)), True),