Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions examples/jiter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# jiter Examples

Each sub-directory contains a self-contained example. The order in
which the examples are to appear is specified in `order.json` (an
array of directory names in the expected order).

In each example directory you'll find:

* `config.toml` - must conform to the specification outlined here:
https://docs.pyscript.net/latest/user-guide/configuration/ This is
parsed and ultimately turned into a JSON representation as part of
the package's API object.
* `setup.py` - Python code for contextual and environmental setup,
NOT SEEN BY THE END USER, but is run before the `code.py` code is
evaluated. Allows us to create useful (IPython) shims, avoid
repeating boilerplate and whatnot.
* `code.py` - the actual code added to the editor which forms the
practical example of using the package.
54 changes: 54 additions & 0 deletions examples/jiter/from_json_basics/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
A first look at jiter, a fast JSON parser from the Pydantic team.

The whole API is essentially one function: `jiter.from_json`. It takes
a `bytes` object (not a `str`) and returns native Python values, just
like the standard library's `json.loads`. See the project page for
details: https://github.com/pydantic/jiter
"""
from IPython.core.display import display, HTML

import jiter


# jiter.from_json expects bytes -- note the leading `b`.
weather_report = b"""
{
"station": "Kew Gardens",
"recorded_at": "2026-04-12T09:00:00Z",
"temperature_c": 14.2,
"humidity_pct": 71,
"observers": ["Ada", "Grace", "Lin"],
"is_raining": false
}
"""

heading("1. Parse JSON bytes into a Python dict")
note(
"jiter returns ordinary Python values: dicts, lists, strings, "
"numbers, booleans, and None. Below, we parse a small weather "
"report and pull values out by key."
)

report = jiter.from_json(weather_report)

display(report, append=True)
note(
f"Station: <strong>{report['station']}</strong>. "
f"Temperature: <strong>{report['temperature_c']} °C</strong>. "
f"Observers: <strong>{', '.join(report['observers'])}</strong>."
)

heading("2. The string cache")
note(
"By default, jiter caches parsed strings to speed up repeated "
"keys and values. You can inspect and reset that cache."
)

# Parse a few records that share keys, so the cache gets a workout.
for _ in range(5):
jiter.from_json(weather_report)

note(f"String cache size after parsing: <code>{jiter.cache_usage()}</code> bytes.")
jiter.cache_clear()
note(f"After <code>cache_clear()</code>: <code>{jiter.cache_usage()}</code> bytes.")
1 change: 1 addition & 0 deletions examples/jiter/from_json_basics/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages = ["jiter"]
41 changes: 41 additions & 0 deletions examples/jiter/from_json_basics/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
Shim IPython's display API onto PyScript so example code written in a
Jupyter/IPython idiom runs unmodified in the browser.
"""

import sys
import types
import js
from pyscript import window, HTML, display as _display

js.alert = window.alert


def display(*args, **kwargs):
"""Wrap pyscript.display so output lands in the example target."""
return _display(
*args, **kwargs, target=__pyscript_display_target__,
)


ipython = types.ModuleType("IPython")
core = types.ModuleType("IPython.core")
core_display = types.ModuleType("IPython.core.display")
core_display.display = display
core_display.HTML = HTML
ipython.core = core
core.display = core_display
ipython.get_ipython = lambda: None
ipython.display = core_display
sys.modules["IPython"] = ipython
sys.modules["IPython.core"] = core
sys.modules["IPython.core.display"] = core_display
sys.modules["IPython.display"] = core_display


def heading(text, level=2):
display(HTML(f"<h{level}>{text}</h{level}>"), append=True)


def note(text):
display(HTML(f"<p>{text}</p>"), append=True)
5 changes: 5 additions & 0 deletions examples/jiter/order.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
"from_json_basics",
"partial_json_streaming",
"precision_and_duplicates"
]
46 changes: 46 additions & 0 deletions examples/jiter/partial_json_streaming/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# ---------------------------------------------------------------------
# Partial JSON: parsing a stream that hasn't finished arriving.
# ---------------------------------------------------------------------

heading("Parsing partial JSON as it streams in")
note(
"When you're reading JSON from a network response (think: an LLM "
"token stream), you often want to render what you have so far. "
"jiter's <code>partial_mode</code> handles a truncated payload "
"without raising."
)

# Imagine these are progressively longer prefixes of a single response
# arriving over the wire, one chunk at a time.
full_response = (
b'{"model": "demo-1", "choices": ['
b'{"role": "assistant", "content": "Hello, traveller! Welcome to jiter."}'
b']}'
)
checkpoints = [full_response[:n] for n in (20, 55, 95, len(full_response))]

heading("Default: incomplete input is an error", level=3)
try:
jiter.from_json(checkpoints[1])
except ValueError as exc:
note(f"Got <code>ValueError</code>: {exc}")

heading("partial_mode=True: drop the trailing incomplete value", level=3)
note(
"Useful when you want a clean, fully-formed object so far. The "
"still-arriving last field is silently omitted."
)
for i, chunk in enumerate(checkpoints, start=1):
parsed = jiter.from_json(chunk, partial_mode=True)
display(HTML(f"<strong>After chunk {i} ({len(chunk)} bytes):</strong>"), append=True)
display(parsed, append=True)

heading('partial_mode="trailing-strings": keep the in-flight string', level=3)
note(
"Perfect for showing a token-by-token assistant reply: the "
"partially-received string is included as-is."
)
for i, chunk in enumerate(checkpoints, start=1):
parsed = jiter.from_json(chunk, partial_mode="trailing-strings")
display(HTML(f"<strong>After chunk {i}:</strong>"), append=True)
display(parsed, append=True)
1 change: 1 addition & 0 deletions examples/jiter/partial_json_streaming/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages = ["jiter"]
20 changes: 20 additions & 0 deletions examples/jiter/partial_json_streaming/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Lighter setup for the second example: same names, no IPython shim."""
import js
from pyscript import window, HTML, display as _display

js.alert = window.alert


def display(*args, **kwargs):
return _display(*args, **kwargs, target=__pyscript_display_target__)


def heading(text, level=2):
display(HTML(f"<h{level}>{text}</h{level}>"), append=True)


def note(text):
display(HTML(f"<p>{text}</p>"), append=True)


import jiter
59 changes: 59 additions & 0 deletions examples/jiter/precision_and_duplicates/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# ---------------------------------------------------------------------
# Numeric precision and strict-mode options.
# ---------------------------------------------------------------------
import jiter
from decimal import Decimal


heading("Decimals and duplicate-key detection")
note(
"When JSON carries money or scientific values, the default "
"<code>float</code> conversion can lose precision. jiter lets "
"you opt into <code>Decimal</code> output. Separately, "
"<code>catch_duplicate_keys</code> turns a silent overwrite "
"into a loud error."
)

# A ledger entry whose amount has more digits than a 64-bit float
# can faithfully store.
ledger_entry = b'{"account": "ACME-001", "amount": 1234567890.1234567890}'

heading("Default: amount comes back as a float", level=3)
default_parse = jiter.from_json(ledger_entry)
display(default_parse, append=True)
note(
f"Type: <code>{type(default_parse['amount']).__name__}</code>. "
f"Notice the trailing digits have been rounded."
)

heading('float_mode="decimal": exact decimal arithmetic', level=3)
decimal_parse = jiter.from_json(ledger_entry, float_mode="decimal")
display(decimal_parse, append=True)
note(
f"Type: <code>{type(decimal_parse['amount']).__name__}</code>. "
f"Now we can sum many of these without drift."
)

# Add up 1000 copies to show Decimal stays exact.
total = sum(
jiter.from_json(ledger_entry, float_mode="decimal")["amount"]
for _ in range(1000)
)
note(f"Sum of 1000 entries (Decimal): <code>{total}</code>")

heading("Catching duplicate keys", level=3)
note(
"By default, JSON parsers silently let later keys win. That can "
"hide bugs in upstream data. Pass <code>catch_duplicate_keys=True</code> "
"to fail fast instead."
)

suspect_payload = b'{"user_id": 1, "user_id": 2, "name": "Robin"}'

permissive = jiter.from_json(suspect_payload)
note(f"Permissive parse (last value wins): <code>{permissive}</code>")

try:
jiter.from_json(suspect_payload, catch_duplicate_keys=True)
except ValueError as exc:
note(f"Strict parse raised <code>ValueError</code>: {exc}")
1 change: 1 addition & 0 deletions examples/jiter/precision_and_duplicates/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages = ["jiter"]
18 changes: 18 additions & 0 deletions examples/jiter/precision_and_duplicates/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Lighter setup: same names, no IPython shim."""
import js
from pyscript import window, HTML, display as _display

js.alert = window.alert


def display(*args, **kwargs):
return _display(*args, **kwargs, target=__pyscript_display_target__)


def heading(text, level=2):
display(HTML(f"<h{level}>{text}</h{level}>"), append=True)


def note(text):
display(HTML(f"<p>{text}</p>"), append=True)