ISONantic
DEPRECATED: This package has been merged into
ison-py. Please useison_parser.validationinstead.pip install ison-py# Old (deprecated) from isonantic import TableModel, Field # New (recommended) from ison_parser.validation import TableModel, FieldThis package will no longer receive updates. All new features and bug fixes will be made to
ison-py.
ISONantic - A Pydantic-like data validation library for ISON format.
Features
- Pydantic-like models for ISON data validation
- Type-safe parsing of LLM structured outputs
- Reference resolution across ISON blocks
- Custom validators and computed fields
- Schema generation for LLM prompts
- Error recovery for malformed LLM outputs
Installation
pip install isonantic
Quick Start
Define Models
from isonantic import TableModel, ObjectModel, Field, Reference
class Team(TableModel):
__ison_block__ = "table.teams"
id: int = Field(primary_key=True)
name: str
budget: float
class User(TableModel):
__ison_block__ = "table.users"
id: int = Field(primary_key=True)
name: str
email: str
team: Reference[Team] # Reference to Team by ID
Parse ISON Data
from isonantic import ISONDocument, parse_ison
ison_data = """
table.teams
id name budget
1 Engineering 500000
2 Marketing 250000
table.users
id name email team
1 Alice alice@example.com :1
2 Bob bob@example.com :2
"""
# Parse with validation
doc = ISONDocument()
doc.register(Team, User)
doc.parse(ison_data)
# Access typed data
users = doc.get_all(User)
for user in users:
print(f"{user.name} - Team: {user.team.name}") # Reference auto-resolved!
Parse LLM Output
from isonantic import parse_llm_output, ParseResult
# LLM may return partial or malformed ISON
llm_response = """
Here's the data you requested:
table.products
id name price
1 Widget 9.99
2 Gadget 19.99
The products are ready.
"""
result: ParseResult = parse_llm_output(llm_response, [Product])
if result.success:
products = result.data[Product]
else:
print(f"Errors: {result.errors}")
Schema for Prompts
from isonantic import prompt_for_model
# Generate ISON schema for LLM prompts
prompt = prompt_for_model(User)
print(prompt)
# Output:
# table.users
# id:int name:string email:string team:ref
# <rows>
Model Types
TableModel
For tabular data with multiple rows:
class Product(TableModel):
__ison_block__ = "table.products"
id: int = Field(primary_key=True)
name: str
price: float
ObjectModel
For single key-value configurations:
class Config(ObjectModel):
__ison_block__ = "object.config"
timeout: int = 30
debug: bool = False
api_key: str
MetaModel
For metadata blocks:
class DocumentMeta(MetaModel):
__ison_block__ = "meta.document"
title: str
version: str
created: str
Field Options
from isonantic import Field, Reference, LazyReference
class User(TableModel):
# Primary key
id: int = Field(primary_key=True)
# Required field
name: str = Field()
# Optional with default
active: bool = Field(default=True)
# Reference to another model
team: Reference[Team]
# Lazy reference (resolved on access)
manager: LazyReference[User] = None
# Constrained field
age: int = Field(ge=0, le=150)
# Pattern validation
email: str = Field(pattern=r'^[\w.]+@[\w.]+$')
Validators
from isonantic import TableModel, validator, root_validator, computed
class Order(TableModel):
__ison_block__ = "table.orders"
id: int = Field(primary_key=True)
quantity: int
unit_price: float
@computed
def total(self) -> float:
return self.quantity * self.unit_price
@validator('quantity')
def validate_quantity(cls, v):
if v <= 0:
raise ValueError('Quantity must be positive')
return v
@root_validator
def validate_order(cls, values):
if values.get('total', 0) > 10000:
raise ValueError('Order total exceeds limit')
return values
Reference Resolution
ISONantic automatically resolves references between blocks:
# ISON data with references
ison = """
table.departments
id name
D1 Engineering
D2 Sales
table.employees
id name dept
E1 Alice :D1
E2 Bob :D2
"""
doc = ISONDocument()
doc.register(Department, Employee)
doc.parse(ison)
emp = doc.get(Employee, "E1")
print(emp.dept.name) # "Engineering" - auto-resolved!
Error Handling
from isonantic import parse_ison_safe, ValidationError
try:
result = parse_ison_safe(data, [User, Team])
if result.has_errors:
for error in result.errors:
print(f"Error: {error}")
# Access valid data even with partial errors
users = result.data.get(User, [])
except ValidationError as e:
print(f"Validation failed: {e}")
Use Cases
- LLM Structured Output - Parse and validate AI-generated data
- Configuration Files - Type-safe config loading
- API Responses - Validate ISON API data
- Data Pipelines - Transform and validate ISON streams
- RAG Systems - Parse retrieved ISON documents
Comparison with Pydantic
| Feature | ISONantic | Pydantic |
|---|---|---|
| Format | ISON | JSON |
| Token efficiency | High | Lower |
| Cross-record refs | Built-in | Manual |
| LLM optimization | Yes | No |
| Schema generation | ISON-native | JSON Schema |
Test Results
All tests passing:
============================= test session starts =============================
platform win32 -- Python 3.12.7, pytest-8.4.1
tests/test_isonantic.py::TestBasicModels::test_create_simple_model PASSED
tests/test_isonantic.py::TestBasicModels::test_model_with_reference PASSED
tests/test_isonantic.py::TestBasicModels::test_field_constraints PASSED
tests/test_isonantic.py::TestBasicModels::test_string_pattern_validation PASSED
tests/test_isonantic.py::TestBasicModels::test_min_max_length PASSED
tests/test_isonantic.py::TestBasicModels::test_choices_validation PASSED
tests/test_isonantic.py::TestValidators::test_field_validator PASSED
tests/test_isonantic.py::TestValidators::test_root_validator PASSED
tests/test_isonantic.py::TestValidators::test_computed_field PASSED
tests/test_isonantic.py::TestParsing::test_parse_single_model PASSED
tests/test_isonantic.py::TestParsing::test_parse_with_references PASSED
tests/test_isonantic.py::TestParsing::test_parse_safe PASSED
tests/test_isonantic.py::TestParsing::test_parse_null_values PASSED
tests/test_isonantic.py::TestDocument::test_parse_document PASSED
tests/test_isonantic.py::TestDocument::test_reference_resolution PASSED
tests/test_isonantic.py::TestDocument::test_reference_validation PASSED
tests/test_isonantic.py::TestDocument::test_document_serialization PASSED
tests/test_isonantic.py::TestLLMParsing::test_parse_clean_llm_output PASSED
tests/test_isonantic.py::TestLLMParsing::test_parse_llm_with_extra_text PASSED
tests/test_isonantic.py::TestLLMParsing::test_parse_llm_code_block PASSED
tests/test_isonantic.py::TestLLMParsing::test_llm_parse_error PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_generate_model_schema PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_prompt_for_model PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_json_schema_generation PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_json_schema_with_constraints PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_json_schema_with_pattern PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_json_schema_with_choices PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_json_schema_with_reference PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_json_schema_json_output PASSED
tests/test_isonantic.py::TestSchemaGeneration::test_pydantic_v1_compatibility PASSED
tests/test_isonantic.py::TestSerialization::test_model_to_dict PASSED
tests/test_isonantic.py::TestSerialization::test_model_with_reference_to_dict PASSED
tests/test_isonantic.py::TestSerialization::test_model_to_ison_table PASSED
tests/test_isonantic.py::TestSerialization::test_model_copy PASSED
tests/test_isonantic.py::TestEdgeCases::test_empty_ison PASSED
tests/test_isonantic.py::TestEdgeCases::test_missing_required_field PASSED
tests/test_isonantic.py::TestEdgeCases::test_extra_fields_ignored PASSED
tests/test_isonantic.py::TestEdgeCases::test_quoted_strings_with_spaces PASSED
tests/test_isonantic.py::TestEdgeCases::test_special_characters_in_strings PASSED
============================= 39 passed in 0.09s ==============================
Run tests with:
pytest tests/
Links
License
MIT License - see LICENSE for details.
Metadata
Release files for isonantic 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| isonantic-1.1.0.tar.gz | 33.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| isonantic-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 64.1 kB
Release files / isonantic-1.1.0.tar.gz
| Download URL | isonantic-1.1.0.tar.gz |
|---|---|
| Size | 33.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f5e47176f0c31b50dbe1546decab9bc70658e8651bb15a67830e3517c829e5ae
|
|
BLAKE2b-256 checksum How to use checksums |
359c4f34a3222af9882a7314484c99c8d2c1e637ed6aad6e3bac98a7abcd2668
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / isonantic-1.1.0-py3-none-any.whl
| Download URL | isonantic-1.1.0-py3-none-any.whl |
|---|---|
| Size | 30.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dec2714c75c18ac23591eb5c4c30f3ea10e6936f7899c3f6582a20bd9095589f
|
|
BLAKE2b-256 checksum How to use checksums |
4a23f382142ed0f91697cc243d29a34f5ffcb9621561a137f42d10f9711b81e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|