Skip to content

📜 Cicerone

Turn OpenAPI schemas into Pydantic models

Package version codecov PyPI - License

Cicerone parses OpenAPI schemas into Pydantic models for introspection and traversal.

It's fast, minimal, fully typed, and pythonic.

Features

  • Tested at scale: We run tests against 4000+ real schemas from APIs.guru OpenAPI Directory.
  • Pydantic models: All models are type-safe.
  • Multiple input formats: Files, URLs, or in-memory data.
  • OpenAPI 3.x support: Works with OpenAPI 3.0 and 3.1 specifications.
  • Minimal dependencies: Just Pydantic and pyyaml. Everything else is stdlib.
  • Simple API: Easy to use, hard to misuse.
  • Modern Python: Fully typed with 100% test coverage.

Installation

pip

pip install cicerone

uv

uv add cicerone

Quick Start

Parsing Specifications

from cicerone import parse as cicerone_parse

# From a file
file_spec = cicerone_parse.parse_spec_from_file("openapi.yaml")

# From a URL
url_spec = cicerone_parse.parse_spec_from_url("https://api.example.com/openapi.json")

# From a dictionary
dict_spec = cicerone_parse.parse_spec_from_dict({"openapi": "3.0.0", ...})

# From JSON string
json_spec = cicerone_parse.parse_spec_from_json('{"openapi": "3.0.0", ...}')

# From YAML string
yaml_spec = cicerone_parse.parse_spec_from_yaml('openapi: "3.0.0"\n...')

Exploring the schema

from cicerone import parse as cicerone_parse

spec = cicerone_parse.parse_spec_from_file('tests/fixtures/petstore_openapi3.yaml')

print("OpenAPISpec:", spec)
>>> OpenAPISpec: <OpenAPISpec: 'Test API' v3.0.0, 2 paths, 2 schemas>

print("Paths:", spec.paths)
>>> Paths: <Paths: 2 paths, 3 operations [/users, /users/{userId}]>

print("PathItem:", spec.paths["/users"])
>>> PathItem: <PathItem: /users [GET, POST]>

print("Operation:", spec.operation_by_operation_id("listUsers"))
>>> Operation: <Operation: GET /users, id=listUsers, 'List all users', tags=['users']>

print("Components:", spec.components)
>>> Components: <Components: 2 schemas [User, Error]>

print("Schema:", spec.components.get_schema("User"))
>>> Schema: <Schema: type=object, 5 properties, required=['id', 'username', 'email']>

user = spec.components.get_schema("User")
print(f"User properties: {list(user.properties.keys())}")
>>> User properties: ['id', 'username', 'email', 'age', 'roles']

Resolving References

Resolve $ref references to their typed objects:

from cicerone import parse as cicerone_parse

spec = cicerone_parse.parse_spec_from_file('tests/fixtures/petstore_openapi3.yaml')

# Resolve a reference to get a typed Schema object
# follow_nested=True will recursively resolve all nested $refs
user_schema = spec.resolve_reference('#/components/schemas/User', follow_nested=True)
print(f"User schema type: {user_schema.type}")
>>> User schema type: object
print(f"Required fields: {user_schema.required}")
>>> Required fields: ['id', 'username', 'email']