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.3.tar.gz (22.0 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.3-cp39-abi3-win_amd64.whl (2.3 MB view details)

Uploaded CPython 3.9+Windows x86-64

jetro-0.1.3-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.3-cp39-abi3-manylinux_2_28_aarch64.whl (2.4 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ ARM64

jetro-0.1.3-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.3.tar.gz.

File metadata

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

File hashes

Hashes for jetro-0.1.3.tar.gz
Algorithm Hash digest
SHA256 43799f562c31a208cd2fc957e848a232e2aa848fd1aea9b2cd1de78ea5ee8da2
MD5 0f3c2125bb501a10a9da55bd0091b321
BLAKE2b-256 e057842cd83696ed7b9f223677383bcf49f4b11aaa75fbc6a9b1dc06783e18fd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: jetro-0.1.3-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.3-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 07f47361f3012e36b989bac39ed8dd0361e8b1074df63d77ba0871ad9f2ce93e
MD5 66c13e21b290271c128fce6c66ba2a9c
BLAKE2b-256 804d5086bb4173e37b70e165a51752743562bb5d87c4b1d74a4486e059aaccaf

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for jetro-0.1.3-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 5e40a220c022d4166b9fbf65035b9dc1620029921e3bc2b9b5d9456cbe06f0a0
MD5 3fe092b908ec34c82bcd9b1c707aa474
BLAKE2b-256 16cbb108eaea1ef19dec32eccb88db8f0a285b401487bff589811ae2c0f4bae2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for jetro-0.1.3-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 a621e49adcd671b74621fe21af77a3d850ded593de457ad78554efae84baaafa
MD5 e489b3983ee9e4bcc2de0c8cefdafebd
BLAKE2b-256 b83cff643fdfcd8b10e8cc169e7940ea5b3603daca10eaae9e5abeb4df9521ec

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for jetro-0.1.3-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b2495129e4d71a9a9e7ca7255de6e9aa26b636343d9ee3e08c1e386aeb6ddd45
MD5 6a03996ef70ab41de76073bfad09c179
BLAKE2b-256 d432b942b1da193a885601cb3755af14979789509cca73d9dc6897a74c0aef6a

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