Buildantic: A library for JSON schema generation and data validation, with native support for LLM function-calling formats.
Buildantic streamlines the process of generating schemas from types and OpenAPI specification operations, as well as validating data against these schemas.
Beyond standard JSON Schema generation, It facilitates the creation of schema formats tailored for Large Language Model (LLM) function calling. The supported formats include OpenAI (compatible with most function-calling LLMs), Anthropic, and Gemini.
Buildantic is highly inspired from the talk "Pydantic is all you need" by Jason Liu, author of Instructor library.
Getting Started
pip install -U buildantic
Working with types
TypeDescriptor utilizes pydantic's TypeAdapter internally. The schema generated by the adapter is updated with docstring recursively.
Any type supported by pydantic will work with this descriptor.
Descripting a simple type
import typing as t
from buildantic import TypeDescriptor
descriptor = TypeDescriptor(t.List[str])
-
Get standard JsON schema
print(descriptor.schema) """{'items': {'type': 'string'}, 'type': 'array'}"""
-
Get function calling schema
As function-calling only accepts object input, the simple type is transformed into object type with
inputbeing the only property key.print(descriptor.openai_schema) """ { 'name': 'List', 'parameters': { 'type': 'object', 'properties': { 'input': { 'items': {'type': 'string'}, 'type': 'array' } } } } """
-
Validating a python object
print(descriptor.validate_python(["name", "age"])) # OR output generated from function-calling schema print(descriptor.validate_python({"input": ["name", "age"]})) """['name', 'age']"""
-
Validating a JsON object
print(descriptor.validate_json('["name", "age"]')) # OR output generated from function-calling schema print(descriptor.validate_json('{"input": ["name", "age"]}')) """['name', 'age']"""
Descripting a simple type with custom name and description
Annonate the simple type (non-object type) with pydantic's
FieldInfoto add name and description
import typing as t
from buildantic import TypeDescriptor
from pydantic.fields import Field
descriptor = TypeDescriptor[t.List[str]](
t.Annotated[t.List[str], Field(alias="strings", description="List of string")]
)
print(descriptor.schema)
"""{'items': {'type': 'string'}, 'type': 'array'}"""
print(descriptor.openai_schema)
"""
{
"name": "strings",
"description": "List of string",
"parameters": {
"type": "object",
"properties": {
"input": {"type": "array", "items": {"type": "string"}}
},
"required": ["input"]
}
}
"""
print(descriptor.validate_python(["name", "age"]))
"""['name', 'age']"""
print(descriptor.validate_json('{"input": ["name", "age"]}'))
"""['name', 'age']"""
Descripting an object type
An object type refers to type with properties.
TypedDict, pydantic model, dataclasses and functions are some examples of it.
TypeDescriptoraliased asdescriptcan be used as a decorator.
from buildantic import descript
from typing import Any, Dict, Literal, Tuple
@descript # same as TypeDescriptor(create_user)
async def create_user(
name: str, age: int, role: Literal["developer", "tester"] = "tester"
) -> Tuple[bool, Dict[str, Any]]:
"""
Create a new user
:param name: Name of the user
:param age: Age of the user
:param role: Role to assign.
"""
return (True, {"metadata": [name, age, role]})
print(create_user.gemini_schema)
"""
{
"name": "create_user",
"description": "Create a new user",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string", "description": "Name of the user"
},
"age": {
"type": "integer", "description": "Age of the user"
},
"role": {
"type": "string",
"description": "Role to assign.",
"enum": ["developer", "tester"],
"format": "enum"
}
},
"required": ["name", "age"]
}
}
"""
import asyncio
print(asyncio.run(create_user.validate_python({
"name": "synacktra", "age": 21, "role": "developer"
})))
"""(True, {'metadata': ['synacktra', 21, 'developer']})"""
Creating a registry of type descriptors
from typing import Tuple, Literal
from pydantic import BaseModel
from buildantic import Registry
registry = Registry()
@registry.register
class UserInfo(BaseModel):
"""
User Information
:param name: Name of the user
:param age: Age of the user
:param role: Role to assign.
"""
name: str
age: int
role: Literal["developer", "tester"] = "tester"
@registry.register
def get_coordinates(location: str) -> Tuple[float, float]:
"""Get coordinates of a location."""
return (48.858370, 2.2944813)
-
Getting schema list in different formats
print(registry.schema) print(registry.openai_schema) print(registry.anthropic_schema) print(registry.gemini_schema)
-
Validating a python object
print(registry.validate_python(id="UserInfo", obj={"name": "synacktra", "age": 21})) """name='synacktra' age=21 role='tester'""" print(registry.validate_python(id="get_coordinates", obj={"location": "eiffeltower"})) """(48.85837, 2.2944813)"""
-
Validating a JsON object
print(registry.validate_json(id="UserInfo", data='{"name": "synacktra", "age": 21}')) """name='synacktra' age=21 role='tester'""" print(registry.validate_json(id="get_coordinates", data='{"location": "eiffeltower"}')) """(48.85837, 2.2944813)"""
-
Accessing descriptor from registry instance
get_coords_descriptor = registry["get_coordinates"]
Working with OpenAPI Specification
OpenAPI operations are loaded as operation descriptors in the OpenAPIRegistry.
Validation methods returns a RequestModel, after which you can use your favorite
http client library to finally make request to the API.
-
Loading the specification as a registyr
from buildantic.registry import OpenAPIRegistry openapi_registry = OpenAPIRegistry.from_file("/path/to/petstore-v3.json_or_yml") # or openapi_registry = OpenAPIRegistry.from_url( "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/refs/heads/main/examples/v3.0/petstore.json" )
-
Get list of operations
print(openapi_registry.ids) """['listPets', 'createPets', 'showPetById']"""
-
Accessing specific operation descriptor from registry
print(openapi_registry["listPets"].schema) """ { 'type': 'object', 'description': 'List all pets', 'properties': { 'limit': { 'type': 'integer', 'maximum': 100, 'format': 'int32', 'description': 'How many items to return at one time (max 100)' } } } """ print(openapi_registry["createPets"].schema) { 'type': 'object', 'description': 'Create a pet', 'properties': { 'requestBody': { 'type': 'object', 'properties': { 'id': {'type': 'integer', 'format': 'int64'}, 'name': {'type': 'string'}, 'tag': {'type': 'string'} } } }, 'required': ['requestBody'] }
-
Getting schema list in different formats
print(registry.schema) print(registry.openai_schema) print(registry.anthropic_schema) print(registry.gemini_schema)
-
Validating a python object
print(openapi_registry.validate_python(id="listPets", obj={"limit": 99})) """ path='/pets' method='get' queries={'limit': 99} encoded_query='limit=99' headers=None cookies=None body=None """ print(openapi_registry.validate_python(id="listPets", obj={"limit": 101})) # This will raise `jsonschema.exceptions.ValidationError` exception
-
Validating a JsON object
print(openapi_registry.validate_json( id="createPets", data='{"requestBody": {"id": 12, "name": "rocky", "tag": "dog"}}' )) """ path='/pets' method='post' queries=None encoded_query=None headers=None cookies=None body={'id': 12, 'name': 'rocky', 'tag': 'dog'} """
Metadata
Release files for buildantic 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| buildantic-0.0.1.tar.gz | 17.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| buildantic-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.8 kB
Release files / buildantic-0.0.1.tar.gz
| Download URL | buildantic-0.0.1.tar.gz |
|---|---|
| Size | 17.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f6ab67384a20f9356f1665830075b46af29f076ccf0ed833ba140d62bf52c825
|
|
BLAKE2b-256 checksum How to use checksums |
bc9e0f3a270a46938cc8cec5bff1e4154f6e4dde8a120a65291c3a4ee5321a19
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.7.1 CPython/3.11.10 Linux/6.5.0-1025-azure
|
Release files / buildantic-0.0.1-py3-none-any.whl
| Download URL | buildantic-0.0.1-py3-none-any.whl |
|---|---|
| Size | 18.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
43a0d3107559671c9785a58c5388ac6c5c3865c7c26c06ea3388851e1cda6d2b
|
|
BLAKE2b-256 checksum How to use checksums |
ca592a309043fd4775c8f1f2583b6d86c3fabe60508dc9f7233c5c8d35244aca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.7.1 CPython/3.11.10 Linux/6.5.0-1025-azure
|