Skip to main content

Fast and type-safe JSON stream parser

Project description

jsonversation

A Python library for streaming JSON parsing that enables real-time processing of JSON data as it arrives. Perfect for handling large JSON responses, streaming APIs, or any scenario where you need to process JSON data progressively.

Installation

Coming soon!

Key Features

  • Streaming JSON Parsing: Process JSON data as it arrives, without waiting for complete payloads
  • Type-Safe Models: Define strongly-typed data structures with automatic validation
  • Real-time Callbacks: React to data changes as they happen with customizable callbacks
  • Progressive Updates: Handle partial JSON data and incremental updates seamlessly

Quick Start

Basic Usage

import jsonversation as jv


# Define your data structure
class ChatMessage(jv.Object):
    role: jv.String
    content: jv.String
    timestamp: jv.String
    token_count: jv.Atomic[int]
    is_complete: jv.Atomic[bool]


# Create a parser
message = ChatMessage()

# Process streaming JSON data
json_chunk1 = '{"role": "assistant", "content": "Hello'
json_chunk2 = ' world!", "timestamp": "2024-01-01T12:00:00Z", "token_count": 42, "is_complete": true}'

with jv.Parser(message) as parser:
    parser.push(json_chunk1)
    print(message.content.get_value())  # "Hello"

    parser.push(json_chunk2)
    print(message.content.get_value())  # "Hello world!"
    print(message.role.get_value())  # "assistant"
    print(message.token_count.get_value())  # 42
    print(message.is_complete.get_value())  # True

Real-time Callbacks

import jsonversation as jv


class StreamingResponse(jv.Object):
    message: jv.String
    tokens: jv.List[jv.String]


response = StreamingResponse()


# Set up real-time callbacks
def on_message_update(chunk: str):
    print(f"New text: {chunk}")


def on_new_token(token: jv.String):
    print(f"New token: {token.get_value()}")


def on_message_complete(full_message: str):
    print(f"Complete message: {full_message}")


response.message.on_append(on_message_update)
response.tokens.on_append(on_new_token)
response.message.on_complete(on_message_complete)

# Simulate streaming data
with jv.Parser(response) as parser:
    parser.push('{"message": "The quick')
    parser.push(' brown fox", "tokens": ["The", "quick"]}')

Working with Atomic Types

The Atomic class handles primitive types that arrive as complete values rather than streaming text:

import jsonversation as jv


class APIResponse(jv.Object):
    message: jv.String
    status_code: jv.Atomic[int]
    success: jv.Atomic[bool]
    response_time: jv.Atomic[float]


response = APIResponse()


# Set up callbacks for atomic values
def on_status_change(status: int | None):
    if status:
        print(f"Status code: {status}")
        if status >= 400:
            print("Error response detected!")


def on_completion(success: bool | None):
    if success is not None:
        print(f"Request {'succeeded' if success else 'failed'}")


response.status_code.on_complete(on_status_change)
response.success.on_complete(on_completion)

# Process JSON with atomic values
with jv.Parser(response) as parser:
    parser.push('{"message": "Request completed", "status_code": 200')
    parser.push(', "success": true, "response_time": 1.23}')
    # Callbacks will be triggered when atomic values are completed

print(response.status_code.get_value())  # 200
print(response.success.get_value())  # True
print(response.response_time.get_value())  # 1.23

Complex Nested Structures

import jsonversation as jv


class Author(jv.Object):
    name: jv.String
    email: jv.String


class Comment(jv.Object):
    id: jv.String
    text: jv.String
    author: Author


class BlogPost(jv.Object):
    title: jv.String
    content: jv.String
    author: Author
    comments: jv.List[Comment]
    tags: jv.List[jv.String]


# Create and use the parser
post = BlogPost()

# Process complex JSON
complex_json = """
{
    "title": "Streaming JSON in Python",
    "content": "This is a comprehensive guide...",
    "author": {
        "name": "Jane Doe",
        "email": "jane@example.com"
    },
    "comments": [
        {
            "id": "1",
            "text": "Great article!",
            "author": {
                "name": "John Smith",
                "email": "john@example.com"
            }
        }
    ],
    "tags": ["python", "json", "streaming"]
}
"""

with jv.Parser(post) as parser:
    parser.push(complex_json)
    # Access nested data
    print(post.title.get_value())  # "Streaming JSON in Python"
    print(post.author.name.get_value())  # "Jane Doe"
    print(post.comments.get_value()[0].text.get_value())  # "Great article!"
    print([tag.get_value for tag in post.tags.get_value()])  # ["python", "json", "streaming"]

AsyncIO

Jsonversation supports async callbacks as well. The API is very similar between the sync/async classes, with the only difference being that the async module supports async callback functions.

Example

import asyncio
import jsonversation.aio as jv


class StreamingResponse(jv.Object):
    message: jv.String
    tokens: jv.List[jv.String]


response = StreamingResponse()


# Set up real-time callbacks
async def on_message_update(chunk: str):
    await asyncio.sleep(0.001)
    print(f"New text: {chunk}")


async def on_new_token(token: jv.String):
    await asyncio.sleep(0.001)
    print(f"New token: {token.get_value()}")


async def on_message_complete(full_message: str):
    await asyncio.sleep(0.001)
    print(f"Complete message: {full_message}")


response.message.on_append(on_message_update)
response.tokens.on_append(on_new_token)
response.message.on_complete(on_message_complete)


async def run():
    async with jv.Parser(response) as parser:
        await parser.push('{"message": "The quick')
        await parser.push(' brown fox", "tokens": ["The", "quick"]}')


asyncio.run(run())

API Reference

Core Classes

  1. Parser(obj: Object)

    Main parser class for processing streaming JSON data.

    Methods:

    • push(chunk: str) - Process a chunk of JSON data
  2. Object

    Base class for defining structured data models.

    Methods:

    • update(value: dict) - Update object with dictionary data
  3. String

    String field type with streaming capabilities.

    Properties:

    • value - Get current string value

    Methods:

    • on_append(callback) - Register callback for new text chunks
    • on_complete(callback) - Register callback for completion
    • update(value: str) - Update with new string value
  4. List[T]

    List field type for collections of items.

    Properties:

    • value - Get current list of items

    Methods:

    • on_append(callback) - Register callback for new items
    • on_complete(callback) - Register callback for completion
    • update(value: list) - Update with new list data

Requirements

  • Python 3.9+
  • jiter (for JSON parsing)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

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

jsonversation-0.1.1.tar.gz (8.7 kB view details)

Uploaded Source

Built Distribution

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

jsonversation-0.1.1-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: jsonversation-0.1.1.tar.gz
  • Upload date:
  • Size: 8.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for jsonversation-0.1.1.tar.gz
Algorithm Hash digest
SHA256 136d46e28245d89d9f5c68fc994d8ffd74ae0f27bb036ea74000908fc6a41fae
MD5 665de7379f959e309f9590cb57a49d56
BLAKE2b-256 390be80fe563a04719ebf25c853f4eb205fec598a3abff7a80a8fc8e0f2c48c7

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonversation-0.1.1.tar.gz:

Publisher: publish.yml on Parli/jsonversation

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonversation-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: jsonversation-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for jsonversation-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0737dd66e980cbbf8cce10b49c3b2e7ab81a9638971e04f28b5747b05159a7d4
MD5 2eac99116fd4ff18b1164ea94ecc8699
BLAKE2b-256 b0b6e55ab2eef44dc6eb1698a0bb3e8998d092b47fd21d5b8b99347bf330b4fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonversation-0.1.1-py3-none-any.whl:

Publisher: publish.yml on Parli/jsonversation

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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