Skip to main content

Query, shape, and patch JSON in one expression — at Rust speed.

Project description

jetro

Query, shape, and patch JSON in one expression — at Rust speed.

Python bindings for jetro, a JSON query, transform, and patch DSL. Filter, project, group, aggregate, write back to deeply nested data, and pattern-match, all in a single expression. Streaming with demand propagation, structural bitmap index for deep search, and a complete patch surface (.set / .modify / .delete).

Install

pip install jetro

Wheels are published for CPython 3.9+ on linux (x86_64, aarch64), macOS (universal2), and windows (x86_64). Building from source requires a Rust toolchain.

Quickstart

from jetro import Jetro, JetroEngine

j = Jetro.from_str('{"books":[{"title":"a","price":12},{"title":"b","price":7}]}')

j.collect("$.books.len()")                          # 2
j.collect("$.books.filter(price > 10).map(title)")  # ["a"]
j.collect("$.books.map(price).sum()")               # 19

JetroEngine amortises parsing and planning across many queries:

eng = JetroEngine()
for doc in stream_of_jsons:
    payload = eng.collect_bytes(doc, "$.users.filter(active).map(email)")
    ...

Pattern matching

j = Jetro.from_str('{"u": {"role": "admin", "id": 9}}')

j.collect("""
    match $.u with {
        {role: "admin", id: i} -> {tag: "a", n: i},
        {role: "user",  id: i} -> {tag: "u", n: i},
        _                      -> {tag: "x"}
    }
""")
# {"tag": "a", "n": 9}

Deep search:

j.collect("""
    $..match {
        {tag: "click", id: i} -> i,
        _                     -> false
    }
""")

Performance

jetro outperforms several comparable Python JSON DSL on the same queries, and matches or beats hand-rolled Python on compound workloads. Numbers below are median wall-clock per iteration on a 403 KB JSON document with 1000 users and ~5–50 orders each. Each library is queried in its own idiomatic single expression for the same semantic workload.

Warm path (cached parse + cached plan)

The document is parsed once; subsequent queries hit JetroEngine's plan cache. Mirrors a long-running process answering many queries against the same document.

Workload jetro jmespath jsonpath-ng pyjq glom (py)
users.filter(active).map(email) 86 µs 537 µs 2 899 µs 18 829 µs 32 µs
users.filter(role=="admin").len() 37 µs 1 237 µs 1 682 µs 18 951 µs 29 µs
top-5 active users by score 43 µs 931 µs 2 165 µs 20 643 µs 84 µs
sum of order totals (active users) 129 µs 1 704 µs 11 051 µs 22 290 µs 177 µs
orders with total > 100 498 µs 7 798 µs 11 219 µs 24 624 µs 221 µs
group users by role, count 73 µs n/a n/a 20 610 µs 68 µs
users with any open order ≥ 50 2 601 µs 14 642 µs 816 µs* 28 032 µs 379 µs

The glom (py) column is hand-written Python list / generator expressions over an already-parsed dict, included as a "no DSL, maximum-speed Python" reference.

Cold path (parse + query per iteration)

Every iteration re-parses the raw bytes, then runs the query. Mirrors the typical web-server pattern of "receive JSON request, run query, return result" where parse cost dominates. jetro's simd-json bytes→tape parser is several times faster than json.loads, so the gap to several other library widens substantially.

Workload jetro jmespath jsonpath-ng pyjq glom (py)
users.filter(active).map(email) 574 µs 3 828 µs 15 984 µs 23 526 µs 3 340 µs
top-5 active users by score 538 µs 4 214 µs 15 016 µs 25 131 µs 3 405 µs
group users by role, count 547 µs n/a n/a 25 037 µs 3 339 µs

In the cold path jetro is ~6× faster than hand-rolled Python and 7–46× faster than every other DSL because parse cost dominates and simd-json beats json.loads by a wide margin.

Reproduce with:

pip install -r benches/requirements.txt
python benches/compare.py

Errors

from jetro import JetroParseError, JetroEvalError

JetroParseError covers JSON parse failures; JetroEvalError covers runtime query errors. Both subclass JetroError.

API

Class Method Notes
Jetro from_bytes(data) -> Jetro accepts bytes / bytearray / memoryview
Jetro from_str(text) -> Jetro accepts str
Jetro collect(expr) -> Any evaluates against this document
JetroEngine collect(doc, expr) -> Any reuses cached plan
JetroEngine collect_bytes(data, expr) -> Any parses + queries in one call
JetroEngine clear_cache() drops cached plans

Language reference

See the upstream SYNTAX.md for the full language surface.

Building from source

maturin develop --release
pytest

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jetro-0.1.1.tar.gz (21.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

jetro-0.1.1-cp39-abi3-win_amd64.whl (2.3 MB view details)

Uploaded CPython 3.9+Windows x86-64

jetro-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ x86-64

jetro-0.1.1-cp39-abi3-manylinux_2_28_aarch64.whl (2.4 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ ARM64

jetro-0.1.1-cp39-abi3-macosx_11_0_arm64.whl (2.2 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

File details

Details for the file jetro-0.1.1.tar.gz.

File metadata

  • Download URL: jetro-0.1.1.tar.gz
  • Upload date:
  • Size: 21.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.13.1

File hashes

Hashes for jetro-0.1.1.tar.gz
Algorithm Hash digest
SHA256 bf52b5994a350a42d6d601bcab8e3b836292404e638a48b0b2b3b433d34b210f
MD5 03d69693560683a50084deef550fcb6d
BLAKE2b-256 e340ede2f11c7496783eb71029813e57d84b4c8ba42973aa1e730b38c32b80ad

See more details on using hashes here.

File details

Details for the file jetro-0.1.1-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: jetro-0.1.1-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 2.3 MB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.13.1

File hashes

Hashes for jetro-0.1.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 5c136c27b693c2f2e7ef22b505f54722f50c041e3014ed69e912d9b95b0b9a38
MD5 ec27355d88744004bdd625cbf76b452a
BLAKE2b-256 6aed680ae1302852c0b3bb6252c5a596040b42903a6bfb789d9142b84fb22966

See more details on using hashes here.

File details

Details for the file jetro-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for jetro-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 a400e185dbd600b563ab4c0919b441e26ae24643dab13f15192c36dfc1e76358
MD5 7b2956d2aedef78f0960d0c4aef0e0aa
BLAKE2b-256 3ee5fe36610d09c737a60658f9ef1236bbab56241367de1a9cfdde7aead94555

See more details on using hashes here.

File details

Details for the file jetro-0.1.1-cp39-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for jetro-0.1.1-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 445338dd7ece70551c904b32eacfd575bf813b253292fb811ec77fa05fa2f447
MD5 747963bf5ce7b573b0bd610d266d9e76
BLAKE2b-256 f3872161d7b8a74244b48119f09ba4dfcac40951ca0ac297663440001d2d0711

See more details on using hashes here.

File details

Details for the file jetro-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for jetro-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6c8bdade87b30c110969551f37cef84ae3726ba44ccd32f851118455788cb844
MD5 97e148f0195ba557194a3493e11a015a
BLAKE2b-256 95715e4701bf0b21cb7decce679d717b0ca28f360753fe6d17cad0310cd31240

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page