Skip to main content

JSON schema generation and data validation, with native support for LLM function-calling formats

Project description

Buildantic: A library for JSON schema generation and data validation, with native support for LLM function-calling formats.


buildantic version buildantic CI status buildantic codecov buildantic license

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 input being 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 FieldInfo to 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.

TypeDescriptor aliased as descript can 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'}
    """
    

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

buildantic-0.0.1.tar.gz (17.0 kB view details)

Uploaded Source

Built Distribution

buildantic-0.0.1-py3-none-any.whl (18.8 kB view details)

Uploaded Python 3

File details

Details for the file buildantic-0.0.1.tar.gz.

File metadata

  • Download URL: buildantic-0.0.1.tar.gz
  • Upload date:
  • Size: 17.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.10 Linux/6.5.0-1025-azure

File hashes

Hashes for buildantic-0.0.1.tar.gz
Algorithm Hash digest
SHA256 f6ab67384a20f9356f1665830075b46af29f076ccf0ed833ba140d62bf52c825
MD5 4bf1f425bf2811ed41cd368576450238
BLAKE2b-256 bc9e0f3a270a46938cc8cec5bff1e4154f6e4dde8a120a65291c3a4ee5321a19

See more details on using hashes here.

File details

Details for the file buildantic-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: buildantic-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 18.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.10 Linux/6.5.0-1025-azure

File hashes

Hashes for buildantic-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 43a0d3107559671c9785a58c5388ac6c5c3865c7c26c06ea3388851e1cda6d2b
MD5 ecbf04d3075b3d213df23f145a33e44a
BLAKE2b-256 ca592a309043fd4775c8f1f2583b6d86c3fabe60508dc9f7233c5c8d35244aca

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page