Skip to main content

Convert Python typing annotations, Pydantic v2 models, and dataclasses into a compact, human-readable schema

Project description

SimpleSpec

License Python 3.11+ PyPI version

Convert Python typing annotations, Pydantic v2 models, and dataclasses into a compact, human‑readable schema specification.

Features

  • 🔍 Clear, readable type strings - Modern Python syntax (e.g., list[T], dict[K, V], Union via |)
  • 📝 Preserve constraints and descriptions - Field descriptions and validation constraints
  • 🏗️ First-class Pydantic & dataclass support - Referenced types with proper handling
  • 🔄 Deterministic naming - Collision handling for types with same names
  • 🛡️ Depth control - Configurable limits for cyclic/recursive structures
  • Fast and lightweight - Minimal dependencies

Quick Start

Installation

# Using uv (recommended)
uv add simplespec

# Using pip
pip install simplespec

Basic Usage

from pydantic import BaseModel, Field
from simplespec import generate_simple_spec

class Address(BaseModel):
    street: str
    city: str

class User(BaseModel):
    name: str
    age: int = Field(ge=18, description="User's age in years")
    address: Address

spec = generate_simple_spec(User)
print(spec)

Output:

Referenced specs:
Address
    street: str
    city: str
Spec:
User
    name: str
    age: int, User's age in years [ge=18]
    address: Address

API Reference

generate_simple_spec

from simplespec import generate_simple_spec, DepthLimitExceededError, SimpleSpecError

spec = generate_simple_spec(root_type_obj, max_depth: int | None = None)

Parameters:

  • root_type_obj: Any supported type (Pydantic BaseModel class, dataclass type, or typing annotations like list[str], dict[str, int], Union, etc.)
  • max_depth: Optional recursion limit for referenced types (default: 4)

Returns:

  • Spec: A dataclass containing:
    • self: Ref — The root type definition
    • refs: list[Ref] — Referenced Pydantic models/dataclasses, sorted by depth then name

Raises:

  • DepthLimitExceededError — When walking exceeds max_depth
  • SimpleSpecError — For other analysis/build failures

Output Data Structures

@dataclass
class Prop:
    type: str
    description: str | None = None

@dataclass  
class Ref:
    type: str
    description: str | None = None
    properties: dict[str, Prop] = field(default_factory=dict)

@dataclass
class Spec:
    self: Ref
    refs: list[Ref] = field(default_factory=list)

Type Resolution Examples

SimpleSpec normalizes type names to modern Python syntax:

Input Type Output
dict[str, int] "dict[str, int]"
list[User | None] "list[User | None]"
Optional[str] "str | None"
Union[str, int, None] "int | str | None"
tuple[str, int] "tuple[str, int]"
set[int] "set[int]"
Literal['a', 'b'] "Literal['a', 'b']"

Advanced Examples

Recursive Types

class TreeNode(BaseModel):
    value: str
    children: list["TreeNode"] = []
    parent: Optional["TreeNode"] = None

TreeNode.model_rebuild()  # Required for forward references

spec = generate_simple_spec(TreeNode)
print(spec.self.properties["children"].type)  # "list[TreeNode]"

Dataclass Support

from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float = 0.0

class Shape(BaseModel):
    center: Point
    points: list[Point]

spec = generate_simple_spec(Shape)
# Point appears in spec.refs as a referenced type

Complex Constraints

class Product(BaseModel):
    name: str = Field(min_length=1, max_length=100, description="Product name")
    price: float = Field(gt=0, le=10000, description="Price in USD")
    quantity: int = Field(ge=0, multiple_of=1)

spec = generate_simple_spec(Product)
# Constraints appear as: "str, Product name [min_length=1] [max_length=100]"

Development

Setup

# Clone the repository
git clone https://github.com/denizkenan/simplespec.git
cd simplespec

# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install dependencies
uv sync --all-extras

# Install pre-commit hooks
uv run pre-commit install

Running Tests

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=simplespec --cov-report=html

# Run specific test
uv run pytest tests/test_simplespec.py::test_simple_for_primitive_type -v

Code Quality

# Format code
uv run ruff format

# Lint code  
uv run ruff check

# Type check
uv run mypy simplespec

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (uv run pytest)
  6. Run code quality checks (uv run ruff check && uv run mypy simplespec)
  7. Commit your changes (git commit -m 'Add amazing feature')
  8. Push to the branch (git push origin feature/amazing-feature)
  9. Open a Pull Request

Compatibility

  • Python: 3.11+
  • Pydantic: v2.0+
  • Dependencies: pydantic>=2.0.0, annotated-types>=0.6.0

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Acknowledgments

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

simplespec-0.1.0.tar.gz (78.0 kB view details)

Uploaded Source

Built Distribution

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

simplespec-0.1.0-py3-none-any.whl (19.8 kB view details)

Uploaded Python 3

File details

Details for the file simplespec-0.1.0.tar.gz.

File metadata

  • Download URL: simplespec-0.1.0.tar.gz
  • Upload date:
  • Size: 78.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.1

File hashes

Hashes for simplespec-0.1.0.tar.gz
Algorithm Hash digest
SHA256 eebaacb253ba19b6a09023fced1e9414d007e97a57d22395e7dcde28194fb516
MD5 0dc03d5b55153f4435b4dd69840f70c4
BLAKE2b-256 721d0b0155a2ed49bd2f06c7ae93915b73f90e8a4c0cd5d5dabfb817333c0708

See more details on using hashes here.

File details

Details for the file simplespec-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: simplespec-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.1

File hashes

Hashes for simplespec-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 56c3bd1f341ef8198ddbccfcc0a561d198713e62951b11a0f0095d17d8a73243
MD5 7aaa27aca844ccac95f044f0e025790f
BLAKE2b-256 05f478aa93a16160d9fe23ccdac97d0eb5cd35ec690949ff41f9d349ab9e9ef7

See more details on using hashes here.

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