jsonatapy 2.1.6__tar.gz → 2.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. jsonatapy-2.2.1/CHANGELOG.md +172 -0
  2. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/Cargo.lock +3 -3
  3. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/Cargo.toml +1 -1
  4. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/PKG-INFO +26 -55
  5. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/README.md +25 -54
  6. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/pyproject.toml +1 -1
  7. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/python/jsonatapy/__init__.py +133 -22
  8. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/ast_transform.rs +804 -108
  9. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/evaluator.rs +619 -82
  10. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/lib.rs +104 -23
  11. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/parser.rs +100 -1
  12. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/vm.rs +178 -20
  13. jsonatapy-2.2.1/tests/integration_test.rs +1720 -0
  14. jsonatapy-2.1.6/CHANGELOG.md +0 -45
  15. jsonatapy-2.1.6/tests/integration_test.rs +0 -687
  16. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.gitignore +0 -0
  17. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.gitmodules +0 -0
  18. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/.gitignore +0 -0
  19. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/memories/architecture.md +0 -0
  20. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/memories/conventions.md +0 -0
  21. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/memories/core.md +0 -0
  22. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/memories/memory_maintenance.md +0 -0
  23. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/memories/suggested_commands.md +0 -0
  24. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/memories/task_completion.md +0 -0
  25. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/memories/tech_stack.md +0 -0
  26. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/.serena/project.yml +0 -0
  27. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/LICENSE +0 -0
  28. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/benches/evaluator_bench.rs +0 -0
  29. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/examples/evaluator_demo.rs +0 -0
  30. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/examples/parser_demo.rs +0 -0
  31. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/python/jsonatapy/py.typed +0 -0
  32. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/ast.rs +0 -0
  33. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/compiler.rs +0 -0
  34. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/datetime.rs +0 -0
  35. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/functions.rs +0 -0
  36. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/parser/README.md +0 -0
  37. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/signature.rs +0 -0
  38. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/src/value.rs +0 -0
  39. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/tests/datetime_picture_suite.rs +0 -0
  40. {jsonatapy-2.1.6 → jsonatapy-2.2.1}/tests/parent_and_focus_binding_suite.rs +0 -0
@@ -0,0 +1,172 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ ### Changed
13
+
14
+ ### Deprecated
15
+
16
+ ### Removed
17
+
18
+ ### Fixed
19
+
20
+ ### Security
21
+
22
+ ## [2.2.1] - 2026-07-08
23
+
24
+ > Same code as [2.1.7](#217---2026-07-08) below, renumbered. This project's release versions
25
+ > track the jsonata-js major/minor version they target (patch numbers are independent — see
26
+ > README). `2.1.7` incorrectly continued the old `2.1.x` patch series even though this release's
27
+ > guardrails feature and signature-engine fixes target jsonata-js `2.2.0`/`2.2.1`; `2.1.7` is
28
+ > superseded immediately by this release and should not be used.
29
+
30
+ ### Added
31
+ - Guardrails: `timeout` (ms, error code `D1012`), `max_stack_depth` (error code `D1011`), and
32
+ `max_sequence_length` (error code `D2015`) keyword arguments on `compile()` and every
33
+ `evaluate*()` call, enforced consistently across all three execution engines (tree-walker,
34
+ compiled-expression fast path, bytecode VM). All default to `None` (unlimited) — no behavior
35
+ change unless configured. See [Guardrails](docs/api.md#guardrails). (jsonata-js 2.2.1 Phase 2, #56)
36
+ - Documented the guardrails API in `docs/api.md`, `docs/usage.md`, and `docs/error-handling.md`
37
+ (previously shipped with accurate Python docstrings but no user-facing docs), and corrected
38
+ `docs/migration-from-js.md`'s stale claim that Python had no built-in timeout support.
39
+
40
+ ### Fixed
41
+ - A deeply-nested expression (arithmetic chains, parenthesized/grouped expressions) no longer
42
+ crashes the whole process (previously a native stack overflow) — now raises a graceful `U1002`
43
+ error instead, via a depth guard in the parser and a second, defense-in-depth guard in the
44
+ post-parse AST pass.
45
+ - `Instr::MakeArray`/`MakeObject`/`BlockEnd`'s bytecode operands (and `CallBuiltin`'s argument
46
+ count, and internal constant-pool bookkeeping) no longer silently produce wrong, truncated
47
+ results for oversized literals/blocks/calls (e.g. array literals with more than 65,535
48
+ elements) — such cases now fall back to the always-correct tree-walker instead.
49
+ - `ast_transform.rs`'s depth-guard error messages no longer imply `%`/`@`/`#` ancestor-operator
50
+ usage (e.g. "...while resolving ancestor/path metadata") when the guard fires for any
51
+ sufficiently-nested expression, including plain arithmetic.
52
+ - Release workflow now fails loudly on a fresh dispatch when the target version tag already
53
+ exists at a different commit, instead of silently reusing the wrong commit (#53).
54
+
55
+ ## [2.1.7] - 2026-07-08
56
+
57
+ **Superseded by [2.2.1](#221---2026-07-08) above, published the same day.** This version was
58
+ numbered following a simple patch-increment from `2.1.6` rather than this project's actual
59
+ versioning policy (track jsonata-js's major/minor). It is fully functional and was not yanked —
60
+ package registries don't allow deleting a published version — but `2.2.1` is the version that
61
+ should be used going forward.
62
+
63
+ ### Added
64
+ - Guardrails: `timeout` (ms, error code `D1012`), `max_stack_depth` (error code `D1011`), and
65
+ `max_sequence_length` (error code `D2015`) keyword arguments on `compile()` and every
66
+ `evaluate*()` call, enforced consistently across all three execution engines (tree-walker,
67
+ compiled-expression fast path, bytecode VM). All default to `None` (unlimited) — no behavior
68
+ change unless configured. See [Guardrails](docs/api.md#guardrails). (jsonata-js 2.2.1 Phase 2, #56)
69
+ - Documented the guardrails API in `docs/api.md`, `docs/usage.md`, and `docs/error-handling.md`
70
+ (previously shipped with accurate Python docstrings but no user-facing docs), and corrected
71
+ `docs/migration-from-js.md`'s stale claim that Python had no built-in timeout support.
72
+
73
+ ### Fixed
74
+ - A deeply-nested expression (arithmetic chains, parenthesized/grouped expressions) no longer
75
+ crashes the whole process (previously a native stack overflow) — now raises a graceful `U1002`
76
+ error instead, via a depth guard in the parser and a second, defense-in-depth guard in the
77
+ post-parse AST pass.
78
+ - `Instr::MakeArray`/`MakeObject`/`BlockEnd`'s bytecode operands (and `CallBuiltin`'s argument
79
+ count, and internal constant-pool bookkeeping) no longer silently produce wrong, truncated
80
+ results for oversized literals/blocks/calls (e.g. array literals with more than 65,535
81
+ elements) — such cases now fall back to the always-correct tree-walker instead.
82
+ - `ast_transform.rs`'s depth-guard error messages no longer imply `%`/`@`/`#` ancestor-operator
83
+ usage (e.g. "...while resolving ancestor/path metadata") when the guard fires for any
84
+ sufficiently-nested expression, including plain arithmetic.
85
+ - Release workflow now fails loudly on a fresh dispatch when the target version tag already
86
+ exists at a different commit, instead of silently reusing the wrong commit (#53).
87
+
88
+ ## [2.1.6] - 2026-07-07
89
+
90
+ ### Added
91
+ - `%` (parent-reference) and `@`/`#` (focus/index binding) operators.
92
+ - jsonata-js 2.2.1 Phase 1: signature engine rewrite adding `+`/`-` arity support (#36).
93
+ - Versioned documentation via `mike`, fixing a gh-pages deploy race (#39).
94
+
95
+ ### Fixed
96
+ - Reference test-suite coverage gaps: loader fix, datetime picture-strings,
97
+ `formatInteger`/`parseInteger` (Phases 0-2), and array-constructor/`distinct` stragglers
98
+ (Phase 5, #44).
99
+ - `release.yml` never actually built macOS wheels, due to a broken `actions/setup-python`
100
+ invocation (#41).
101
+ - Several benchmark accuracy/fairness corrections (await `jsonata-js` calls properly, substantiate
102
+ pre-converted-data speedup claims, use clean CI-sourced numbers, use jsonata-python's `Context`
103
+ for fair repeated-eval timing) (#45, #46, #49, #50).
104
+
105
+ ### Changed
106
+ - macOS temporarily dropped from the main release matrix pending a self-hosted runner fix (#45,
107
+ #47) — later restored via a self-hosted Mac Mini runner.
108
+
109
+ ## [2.1.5] - 2026-07-04
110
+
111
+ ### Fixed
112
+ - Native stack overflow on deep recursion — replaced with a graceful, coded error (fixes #34).
113
+ - Lambda IDs are now generated from a monotonic counter instead of an AST pointer address, fixing
114
+ a ~0.5%-frequency wrong-closure bug from id aliasing across recursive/repeated evaluation
115
+ (fixes #35).
116
+ - Tree-walker missing-path/field access now correctly produces `Undefined` instead of `Null` in
117
+ the ~20 sites that predated the `Null`/`Undefined` distinction (fixes #32).
118
+ - CI repairs following the default-branch rename to `main`; patched `RUSTSEC-2026-0097`.
119
+
120
+ ### Changed
121
+ - Bumped `pyo3` to 0.29 and `rand` to 0.10.
122
+
123
+ ## [2.1.4] - 2026-03-22
124
+
125
+ ### Added
126
+ - `cargo publish` step in the release workflow.
127
+
128
+ ### Fixed
129
+ - Release workflow is now idempotent for version-bump and tag-creation steps.
130
+ - Corrected an incorrect expected value in the `substring` test suite.
131
+
132
+ ## [2.1.3] - 2026-03-22
133
+
134
+ > Versions 2.1.1 and 2.1.2 were bumped internally but never published as standalone tagged
135
+ > releases — their changes are folded into this entry, the next version actually released.
136
+
137
+ ### Added
138
+ - Bytecode VM (`compiler.rs` + `vm.rs`, "Phase 4") restored and wired into the Python execution
139
+ path, with Criterion benchmarks comparing it against the tree-walker.
140
+ - `pyo3` made an optional dependency; Rust crate renamed to `jsonata-core` and published to
141
+ crates.io independently of the `jsonatapy` PyPI package.
142
+
143
+ ### Fixed
144
+ - PyO3 0.28 compatibility (`PyObject` → `Py<PyAny>`).
145
+ - Clippy deprecations and `cargo-deny` license-check failures.
146
+ - Upgraded Pillow (dev/docs dependency) to 12.1.1 for a CVE fix.
147
+
148
+ ### Changed
149
+ - Multiple benchmark documentation and accuracy corrections.
150
+
151
+ ## [2.1.0] - 2026-02-08
152
+
153
+ ### Added
154
+ - Initial public release: Rust-based JSONata implementation targeting jsonata-js v2.1.0 semantics.
155
+ - Full jsonata-js v2.1.0 reference test-suite compatibility.
156
+ - Python bindings (PyO3), published as `jsonatapy` on PyPI.
157
+ - Rust core, published as `jsonata-core` on crates.io.
158
+
159
+ ---
160
+
161
+ ## Reference Implementation Tracking
162
+
163
+ This project tracks the [jsonata-js](https://github.com/jsonata-js/jsonata) reference implementation.
164
+
165
+ **Current status:** Full test-suite compatibility with jsonata-js v2.1.0 (+3 commits). jsonata-js
166
+ v2.2.1 compatibility work is in progress — Phase 1 (signature engine, `+`/`-` arity support) and
167
+ Phase 2 (resource guardrails) are done; see
168
+ `docs/superpowers/specs/2026-07-04-jsonata-2.2.1-design.md` for the authoritative, up-to-date
169
+ status of this effort.
170
+
171
+ ### Version History
172
+ - Target tracking v2.1.0 - Project initialization (2025-01-17)
@@ -255,9 +255,9 @@ dependencies = [
255
255
 
256
256
  [[package]]
257
257
  name = "crossbeam-epoch"
258
- version = "0.9.18"
258
+ version = "0.9.20"
259
259
  source = "registry+https://github.com/rust-lang/crates.io-index"
260
- checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
260
+ checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
261
261
  dependencies = [
262
262
  "crossbeam-utils",
263
263
  ]
@@ -483,7 +483,7 @@ dependencies = [
483
483
 
484
484
  [[package]]
485
485
  name = "jsonata-core"
486
- version = "2.1.6"
486
+ version = "2.2.1"
487
487
  dependencies = [
488
488
  "base64",
489
489
  "chrono",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "jsonata-core"
3
- version = "2.1.6"
3
+ version = "2.2.1"
4
4
  edition = "2021"
5
5
  authors = ["txjmb <txjmb@users.noreply.github.com>"]
6
6
  description = "High-performance Rust implementation of JSONata query and transformation language"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jsonatapy
3
- Version: 2.1.6
3
+ Version: 2.2.1
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -47,10 +47,14 @@ Project-URL: Repository, https://github.com/txjmb/jsonata-core
47
47
 
48
48
  High-performance [JSONata](https://jsonata.org/) implementation in Rust, with Python bindings.
49
49
 
50
- > Much of this project was built with human guidance using Claude Code. There was no performant
51
- > JSONata implementation in Python, so the goal was to port JSONata to Rust (with a PyO3 wrapper
52
- > for Python) and see how fast it could go. The answer: faster than V8 for most expression
53
- > workloads, and faster than the next pure-Rust implementation.
50
+ Much of this project was built using Claude Code with significant human oversight. There was no performant
51
+ JSONata implementation in Python, so the goal was to port JSONata to Rust (with a PyO3 wrapper
52
+ for Python) and see how fast it could go. The answer: faster than V8 for most expression
53
+ workloads, and faster than the next pure-Rust implementation.
54
+
55
+ Many, many thanks to the incredible work of all the maintainers of the [JSONata](https://github.com/jsonata-js/jsonata) reference library. JSONata is a very powerful, well-designed, and useful language that has made an impact on many projects. This project leverages their outstanding work to extend that capability to Python and Rust and would not be possible without that project. The implementation in Rust was strongly influenced by their implementation. The 1600+ tests they created provided the scaffolding and validation for all of this project. This project will continue to follow and be a derivative of the reference project as the JSONata reference library evolves.
56
+
57
+ Release versions will follow the reference jsonata-js project major and minor release numbers, but not necessarily patches. This will make it easier for adopters of this library to understand each release's JSONata API compatibility. As an example, 2.1.7 should be compliant with 2.1.x jsonata-js tests, but may have fixes specific to this library. If a patch release for jsonata-js is relevant for this project, it will be included in a patch release that may or may not follow the patch numbers of the upstream project.
54
58
 
55
59
  [![Crates.io](https://img.shields.io/crates/v/jsonata-core.svg)](https://crates.io/crates/jsonata-core)
56
60
  [![PyPI version](https://badge.fury.io/py/jsonatapy.svg)](https://pypi.org/project/jsonatapy/)
@@ -91,10 +95,10 @@ let result = Evaluator::new().evaluate(&ast, &data)?;
91
95
  ```toml
92
96
  # Cargo.toml
93
97
  [dependencies]
94
- jsonata-core = "2.1.2" # pure Rust, no Python dependency
98
+ jsonata-core = "2.1.6" # pure Rust, no Python dependency
95
99
 
96
100
  # Optional: disable SIMD for constrained targets
97
- jsonata-core = { version = "2.1.2", default-features = false }
101
+ jsonata-core = { version = "2.1.6", default-features = false }
98
102
  ```
99
103
 
100
104
  ---
@@ -124,10 +128,10 @@ print(result) # 2450
124
128
 
125
129
  # Pre-convert data once for maximum throughput
126
130
  data = jsonatapy.JsonataData(large_dataset)
127
- result = expr.evaluate_with_data(data) # 4–15x faster than evaluate(dict)
131
+ result = expr.evaluate_with_data(data) # 3–15x faster than evaluate(dict)
128
132
  ```
129
133
 
130
- Supports Python 3.10, 3.11, 3.12, 3.13 on Linux, macOS (Intel & ARM), and Windows.
134
+ Supports Python 3.10, 3.11, 3.12, 3.13, 3.14 on Linux, macOS (Intel & ARM), and Windows.
131
135
 
132
136
  ---
133
137
 
@@ -148,58 +152,25 @@ See [official JSONata docs](https://docs.jsonata.org/) for the full language ref
148
152
  ## Performance
149
153
 
150
154
  `jsonata-core` passes **1682/1682** JSONata reference tests and is the fastest JSONata
151
- implementation available in either Rust or Python.
152
-
153
- ### Pure Rust (Criterion benchmarks, no Python overhead)
154
-
155
- | Category | jsonata-core | vs jsonata-rs |
156
- |----------|-------------|----------------|
157
- | Simple path lookup | 81 ns | ~40x faster |
158
- | Arithmetic expression | 140 ns | ~40x faster |
159
- | Conditional | 106 ns | ~30x faster |
160
- | String operations | 126–284 ns | ~30x faster |
161
- | $sum (100 elements) | 287 ns | ~70x faster |
162
- | Filter predicate (100 objects) | 7.9 µs | ~50x faster |
163
- | Realistic workload (100 products) | 9–44 µs | ~40x faster |
155
+ implementation available in either Rust or Python:
164
156
 
165
- Run the benchmarks yourself:
166
- ```bash
167
- cargo bench --no-default-features --features simd
168
- ```
157
+ - **~6x faster on average** than the JavaScript reference implementation (V8), across all
158
+ benchmark categories — up to ~16x for complex transformations and string operations
159
+ - **~40x faster** than jsonata-rs (the next pure-Rust JSONata implementation) on pure-Rust
160
+ Criterion benchmarks with no Python overhead on either side (`cargo bench`)
161
+ - **hundreds of times faster** than jsonata-python, even when it reuses its fastest
162
+ (`Context`-based) repeated-evaluation path
169
163
 
170
- ### Python path (`jsonatapy`)
171
-
172
- `jsonatapy` is the fastest Python JSONata implementation by a large margin, and faster than
173
- the JavaScript reference implementation for most pure expression workloads:
174
-
175
- | Category | vs JavaScript (V8) | vs jsonata-python |
176
- |----------|--------------------|-------------------|
177
- | Simple paths | **5–8x faster** (array index access: roughly tied) | ~20–40x faster |
178
- | Conditionals | **15x faster** | ~40x faster |
179
- | String operations | **8–15x faster** | ~30–45x faster |
180
- | Complex transformations | **5–15x faster** | ~20–40x faster |
181
- | Higher-order functions | **12–19x faster** | ~50–70x faster |
182
- | Array-heavy workloads | **~1–3x slower to ~4x faster**, depending on access pattern | ~10–50x faster |
183
-
184
- ### The Python boundary
185
-
186
- For large array workloads, the dominant cost is converting Python dicts to Rust values
187
- on each `evaluate()` call — not expression evaluation itself. Two API paths avoid this:
164
+ For large array workloads, pre-convert data once with `jsonatapy.JsonataData` and reuse it
165
+ across queries — this avoids the Python↔Rust conversion cost that otherwise dominates:
188
166
 
189
167
  ```python
190
- # Path 1: Pre-convert data once, reuse across many queries (4–15x faster than evaluate(dict))
191
168
  data = jsonatapy.JsonataData(large_dataset)
192
- result = expr.evaluate_with_data(data)
193
-
194
- # Path 2: Data arrives as a raw JSON string — pass it directly
195
- result_str = expr.evaluate_json(raw_json_string)
169
+ result = expr.evaluate_with_data(data) # 3–15x faster than evaluate(dict)
196
170
  ```
197
171
 
198
- With pre-converted data, realistic workloads (filtering, transforming, aggregating over
199
- 100-object arrays) run **~5–8x faster than V8**, not slower — even the raw `evaluate(dict)`
200
- path without pre-conversion is roughly at parity with V8 (0.5–2x either direction).
201
-
202
- See [Performance docs](docs/performance.md) for full benchmark results and methodology.
172
+ See [Performance docs](docs/performance.md) for the full category-by-category breakdown and
173
+ benchmark methodology.
203
174
 
204
175
  ---
205
176
 
@@ -208,7 +179,7 @@ See [Performance docs](docs/performance.md) for full benchmark results and metho
208
179
  - **1682/1682 JSONata reference tests passing**
209
180
  - **Pure Rust core** — no JavaScript runtime, no Node.js dependency
210
181
  - **Optional Python bindings** — PyO3/maturin, zero-copy where possible
211
- - **Cross-platform** — Linux, macOS (Intel & ARM), Windows; Python 3.10–3.13
182
+ - **Cross-platform** — Linux, macOS (Intel & ARM), Windows; Python 3.10–3.14
212
183
  - **SIMD-accelerated JSON parsing** — via `simd-json` (optional feature)
213
184
 
214
185
  ---
@@ -2,10 +2,14 @@
2
2
 
3
3
  High-performance [JSONata](https://jsonata.org/) implementation in Rust, with Python bindings.
4
4
 
5
- > Much of this project was built with human guidance using Claude Code. There was no performant
6
- > JSONata implementation in Python, so the goal was to port JSONata to Rust (with a PyO3 wrapper
7
- > for Python) and see how fast it could go. The answer: faster than V8 for most expression
8
- > workloads, and faster than the next pure-Rust implementation.
5
+ Much of this project was built using Claude Code with significant human oversight. There was no performant
6
+ JSONata implementation in Python, so the goal was to port JSONata to Rust (with a PyO3 wrapper
7
+ for Python) and see how fast it could go. The answer: faster than V8 for most expression
8
+ workloads, and faster than the next pure-Rust implementation.
9
+
10
+ Many, many thanks to the incredible work of all the maintainers of the [JSONata](https://github.com/jsonata-js/jsonata) reference library. JSONata is a very powerful, well-designed, and useful language that has made an impact on many projects. This project leverages their outstanding work to extend that capability to Python and Rust and would not be possible without that project. The implementation in Rust was strongly influenced by their implementation. The 1600+ tests they created provided the scaffolding and validation for all of this project. This project will continue to follow and be a derivative of the reference project as the JSONata reference library evolves.
11
+
12
+ Release versions will follow the reference jsonata-js project major and minor release numbers, but not necessarily patches. This will make it easier for adopters of this library to understand each release's JSONata API compatibility. As an example, 2.1.7 should be compliant with 2.1.x jsonata-js tests, but may have fixes specific to this library. If a patch release for jsonata-js is relevant for this project, it will be included in a patch release that may or may not follow the patch numbers of the upstream project.
9
13
 
10
14
  [![Crates.io](https://img.shields.io/crates/v/jsonata-core.svg)](https://crates.io/crates/jsonata-core)
11
15
  [![PyPI version](https://badge.fury.io/py/jsonatapy.svg)](https://pypi.org/project/jsonatapy/)
@@ -46,10 +50,10 @@ let result = Evaluator::new().evaluate(&ast, &data)?;
46
50
  ```toml
47
51
  # Cargo.toml
48
52
  [dependencies]
49
- jsonata-core = "2.1.2" # pure Rust, no Python dependency
53
+ jsonata-core = "2.1.6" # pure Rust, no Python dependency
50
54
 
51
55
  # Optional: disable SIMD for constrained targets
52
- jsonata-core = { version = "2.1.2", default-features = false }
56
+ jsonata-core = { version = "2.1.6", default-features = false }
53
57
  ```
54
58
 
55
59
  ---
@@ -79,10 +83,10 @@ print(result) # 2450
79
83
 
80
84
  # Pre-convert data once for maximum throughput
81
85
  data = jsonatapy.JsonataData(large_dataset)
82
- result = expr.evaluate_with_data(data) # 4–15x faster than evaluate(dict)
86
+ result = expr.evaluate_with_data(data) # 3–15x faster than evaluate(dict)
83
87
  ```
84
88
 
85
- Supports Python 3.10, 3.11, 3.12, 3.13 on Linux, macOS (Intel & ARM), and Windows.
89
+ Supports Python 3.10, 3.11, 3.12, 3.13, 3.14 on Linux, macOS (Intel & ARM), and Windows.
86
90
 
87
91
  ---
88
92
 
@@ -103,58 +107,25 @@ See [official JSONata docs](https://docs.jsonata.org/) for the full language ref
103
107
  ## Performance
104
108
 
105
109
  `jsonata-core` passes **1682/1682** JSONata reference tests and is the fastest JSONata
106
- implementation available in either Rust or Python.
107
-
108
- ### Pure Rust (Criterion benchmarks, no Python overhead)
109
-
110
- | Category | jsonata-core | vs jsonata-rs |
111
- |----------|-------------|----------------|
112
- | Simple path lookup | 81 ns | ~40x faster |
113
- | Arithmetic expression | 140 ns | ~40x faster |
114
- | Conditional | 106 ns | ~30x faster |
115
- | String operations | 126–284 ns | ~30x faster |
116
- | $sum (100 elements) | 287 ns | ~70x faster |
117
- | Filter predicate (100 objects) | 7.9 µs | ~50x faster |
118
- | Realistic workload (100 products) | 9–44 µs | ~40x faster |
110
+ implementation available in either Rust or Python:
119
111
 
120
- Run the benchmarks yourself:
121
- ```bash
122
- cargo bench --no-default-features --features simd
123
- ```
112
+ - **~6x faster on average** than the JavaScript reference implementation (V8), across all
113
+ benchmark categories — up to ~16x for complex transformations and string operations
114
+ - **~40x faster** than jsonata-rs (the next pure-Rust JSONata implementation) on pure-Rust
115
+ Criterion benchmarks with no Python overhead on either side (`cargo bench`)
116
+ - **hundreds of times faster** than jsonata-python, even when it reuses its fastest
117
+ (`Context`-based) repeated-evaluation path
124
118
 
125
- ### Python path (`jsonatapy`)
126
-
127
- `jsonatapy` is the fastest Python JSONata implementation by a large margin, and faster than
128
- the JavaScript reference implementation for most pure expression workloads:
129
-
130
- | Category | vs JavaScript (V8) | vs jsonata-python |
131
- |----------|--------------------|-------------------|
132
- | Simple paths | **5–8x faster** (array index access: roughly tied) | ~20–40x faster |
133
- | Conditionals | **15x faster** | ~40x faster |
134
- | String operations | **8–15x faster** | ~30–45x faster |
135
- | Complex transformations | **5–15x faster** | ~20–40x faster |
136
- | Higher-order functions | **12–19x faster** | ~50–70x faster |
137
- | Array-heavy workloads | **~1–3x slower to ~4x faster**, depending on access pattern | ~10–50x faster |
138
-
139
- ### The Python boundary
140
-
141
- For large array workloads, the dominant cost is converting Python dicts to Rust values
142
- on each `evaluate()` call — not expression evaluation itself. Two API paths avoid this:
119
+ For large array workloads, pre-convert data once with `jsonatapy.JsonataData` and reuse it
120
+ across queries — this avoids the Python↔Rust conversion cost that otherwise dominates:
143
121
 
144
122
  ```python
145
- # Path 1: Pre-convert data once, reuse across many queries (4–15x faster than evaluate(dict))
146
123
  data = jsonatapy.JsonataData(large_dataset)
147
- result = expr.evaluate_with_data(data)
148
-
149
- # Path 2: Data arrives as a raw JSON string — pass it directly
150
- result_str = expr.evaluate_json(raw_json_string)
124
+ result = expr.evaluate_with_data(data) # 3–15x faster than evaluate(dict)
151
125
  ```
152
126
 
153
- With pre-converted data, realistic workloads (filtering, transforming, aggregating over
154
- 100-object arrays) run **~5–8x faster than V8**, not slower — even the raw `evaluate(dict)`
155
- path without pre-conversion is roughly at parity with V8 (0.5–2x either direction).
156
-
157
- See [Performance docs](docs/performance.md) for full benchmark results and methodology.
127
+ See [Performance docs](docs/performance.md) for the full category-by-category breakdown and
128
+ benchmark methodology.
158
129
 
159
130
  ---
160
131
 
@@ -163,7 +134,7 @@ See [Performance docs](docs/performance.md) for full benchmark results and metho
163
134
  - **1682/1682 JSONata reference tests passing**
164
135
  - **Pure Rust core** — no JavaScript runtime, no Node.js dependency
165
136
  - **Optional Python bindings** — PyO3/maturin, zero-copy where possible
166
- - **Cross-platform** — Linux, macOS (Intel & ARM), Windows; Python 3.10–3.13
137
+ - **Cross-platform** — Linux, macOS (Intel & ARM), Windows; Python 3.10–3.14
167
138
  - **SIMD-accelerated JSON parsing** — via `simd-json` (optional feature)
168
139
 
169
140
  ---
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "jsonatapy"
7
- version = "2.1.6"
7
+ version = "2.2.1"
8
8
  description = "High-performance Python/Rust implementation of JSONata query and transformation language"
9
9
  authors = [
10
10
  {name = "txjmb", email = "txjmb@users.noreply.github.com"}