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.

Learn

The jetro book is the best place to start. It includes examples and valuable details throughout.

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.8.tar.gz (22.5 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.8-cp39-abi3-win_amd64.whl (2.5 MB view details)

Uploaded CPython 3.9+Windows x86-64

jetro-0.1.8-cp39-abi3-manylinux_2_28_x86_64.whl (2.8 MB view details)

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

jetro-0.1.8-cp39-abi3-manylinux_2_28_aarch64.whl (2.7 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ ARM64

jetro-0.1.8-cp39-abi3-macosx_11_0_arm64.whl (2.5 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

File details

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

File metadata

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

File hashes

Hashes for jetro-0.1.8.tar.gz
Algorithm Hash digest
SHA256 749217dd4245ea16f26348f4a8bc6d4473ee02b420d4618ef3b609df6d8b4cbf
MD5 168ee31f31fd6b7f56475de0f18fe0b5
BLAKE2b-256 690074feb217675e6967e2f19e6a7c1a495840588f54acd57409aa944ff80077

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for jetro-0.1.8-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 df70318bcb61c8218e8072b99023593fae45a43a4be6e254a88365e7b1f4ae05
MD5 8c5f092107267667a39004dacbb3960a
BLAKE2b-256 ea5ac84f99d2cfdd985b8c0472828b275b96263f5dda911570537948265a15b6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for jetro-0.1.8-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c138dc2812f7728bf69e27ad10adcdb38268412eae07a037a589ef82f4641d69
MD5 0b346a7e79b3a60801d11234e3c157db
BLAKE2b-256 ae75b70faf601cf0757f4e74b5fc170941842ede611ce3c927a1e0f105c8cce0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for jetro-0.1.8-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 f0cda6c1c50916ae6fa6daf8218e836f2a9aa5033134854a7c0f428fb32962e6
MD5 d4d61fc5cf4fb614a44e3cac5b3a0e44
BLAKE2b-256 c89893c7cb26c0427b5938cc4acf154a58284e04f3387a4024f9aa32cf5417a4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for jetro-0.1.8-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 03cd3133c341a81eec3103f163e13e9fd3395b7ab9bc682792a2c2f3510f6613
MD5 6e65dedb612979f25c2faa24c75333b3
BLAKE2b-256 c34dded710127ee0045c20dbfc0c4502eec7b1f9f7068df009d5184bbf2ecd77

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