Skip to main content

partial-json-stream

pypi python tests zero deps

A streaming JSON parser that yields partial valid trees as tokens arrive.

Python port of @mukundakatta/streamparse. Built for LLM tool-call payloads, structured-output streams, and any place json.loads waits too long.

from partial_json_stream import JsonStreamParser

p = JsonStreamParser()

p.push('{"name":"Cl')
p.snapshot().value      # {'name': 'Cl'}

p.push('aude","tools":[1,2')
p.snapshot().value      # {'name': 'Claude', 'tools': [1, 2]}

p.push(']}')
p.end()
p.snapshot().complete   # True

Every snapshot is valid JSON. Synthetic closure of in-progress strings, numbers, and containers means you can render it directly, persist it, or round-trip it through json.loads(json.dumps(...)).

Why

Every Python LLM project ships its own broken version of this. They wait for the full payload (slow), or hand-roll json.loads in a try/except on a growing buffer (O(n²) and useless until the very last byte), or use ad-hoc regex.

partial-json-stream is the version you should reuse.

Install

pip install partial-json-stream

Zero runtime dependencies. Python 3.9+.

API

JsonStreamParser(lenient=True, max_depth=256, max_string_length=None)

Lenient mode (default) tolerates the LLM-isms you actually see in production:

  • trailing commas: {"a": 1,}
  • single-quoted strings: {'a': 'hi'}
  • unquoted keys: {a: 1, b: 2}
  • ```json code fences
  • // line and /* block */ comments
  • prose before/after the JSON: Sure! Here it is: {...}

Set lenient=False for strict RFC 8259 mode.

parser.push(chunk: str) -> None

Feed in more bytes.

parser.end() -> None

Signal end of input. Lenient mode silently closes any open containers.

parser.snapshot() -> Snapshot

Take a snapshot. Always returns valid JSON.

@dataclass
class Snapshot:
    value: Any
    complete: bool
    path: list             # cursor location, e.g. ['tools', 2, 'input', 'path']
    bytes_in: int
    confidence: float      # 0..1

parser.on(event, fn)

Subscribe to events. Returns an unsubscribe function.

event callback signature when
field (path, value) every leaf commit
container (path, value) every {} or [] close
partial (snapshot) every push()
complete (value) once, when top-level value closes
error (err) on syntax error (suppresses raise)

parse_partial(text: str, lenient=True) -> Any

One-shot helper for a possibly-truncated blob.

from partial_json_stream import parse_partial

truncated = '{"type":"tool_use","name":"edit","input":{"path":"a/b.ts","cont'
parse_partial(truncated)
# {'type': 'tool_use', 'name': 'edit', 'input': {'path': 'a/b.ts', 'cont': None}}

Real-world usage

Recover a dropped tool call

from partial_json_stream import parse_partial

# The connection dropped before the model finished writing its tool call.
partial = '{"type":"tool_use","name":"edit_file","input":{"path":"a.ts","patches":[{"line":10,"op":"insert","content":"print('

value = parse_partial(partial)
# value['input']['patches'][0] is fully usable.

Stream Anthropic tool calls

from partial_json_stream import JsonStreamParser

parser = JsonStreamParser()

@parser.on("partial", lambda snap: ui.update(snap.value))

for chunk in client.messages.stream(...).text_stream:
    parser.push(chunk)
parser.end()

License

MIT, by Mukunda Katta.

Metadata

Release files for partial-json-stream 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for partial-json-stream 1.0.0
File Size Uploaded Provenance
partial_json_stream-1.0.0.tar.gz 13.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for partial-json-stream 1.0.0
File Interpreter ABI Platform
partial_json_stream-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.1 kB

Release files / partial_json_stream-1.0.0.tar.gz

Download URL partial_json_stream-1.0.0.tar.gz
Size 13.2 kB
Tags Source
SHA-256 checksum
How to use checksums
332455e4bacb3b2affd24d7af04178450ed8ee87a3d279b781313ddfc7f2e740
BLAKE2b-256 checksum
How to use checksums
5958cc793d3106d3ed1b6b48d9607cc69973cf0dde59d1b88f98f532011cdae2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / partial_json_stream-1.0.0-py3-none-any.whl

Download URL partial_json_stream-1.0.0-py3-none-any.whl
Size 9.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
07f36b47d9bcb436f4d31d5a039733222bedccae2ead3f74ed9b4c74ffca1714
BLAKE2b-256 checksum
How to use checksums
8610ca97941654c8459b0c12b2c8d7b8d12304a4a57de143567552e03ba89a52
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Security for partial-json-stream 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page