Python
The python format generates Python TypedDict classes for static type checking.
Basic Example
OpenAPI Schema:
components:
schemas:
User:
type: object
description: A user in the system
required:
- id
- email
properties:
id:
type: string
description: Unique identifier
email:
type: string
format: email
name:
type: string
role:
$ref: '#/components/schemas/UserRole'
UserRole:
type: string
description: The role of a user
enum: [admin, user, guest]Generated Python:
# Generated by an automated build step. Do not edit.
from typing import TypedDict, NotRequired, Literal, Union, List, Dict, Any
from enum import Enum
class User(TypedDict):
"""A user in the system"""
id: str
"""Unique identifier"""
email: str
name: NotRequired[str]
role: NotRequired["UserRole"]
"""The role of a user"""
class UserRole(str, Enum):
"""The role of a user"""
ADMIN = "admin"
USER = "user"
GUEST = "guest"Configuration
{
"outputs": [
{
"path": "./backend/types/api.py",
"format": "python",
"contents": ["api:*"]
}
]
}Type Mapping
| OpenAPI Type | OpenAPI Format | Python |
|---|---|---|
string | - | str |
string | date | str |
string | date-time | str |
string | email | str |
string | uuid | str |
integer | - | int |
integer | int32 | int |
integer | int64 | int |
number | - | float |
number | float | float |
number | double | float |
boolean | - | bool |
array | - | List[T] |
object | - | TypedDict |
object | (no properties) | Dict[str, Any] |
null | - | None |
Required vs Optional Fields
Required fields are defined normally, optional fields use NotRequired:
class User(TypedDict):
id: str # Required
name: NotRequired[str] # OptionalPython Version
NotRequired requires Python 3.11+. For older versions, sparktype generates compatible syntax using total=False.
Enums
With generateEnums: true (default for Python):
class UserRole(str, Enum):
ADMIN = "admin"
USER = "user"
GUEST = "guest"With generateEnums: false:
UserRole = Literal["admin", "user", "guest"]Enum member names are derived from values:
"admin"→ADMIN"some-value"→SOME_VALUE"SomeValue"→SOMEVALUE
Nullable Fields
Nullable fields use union with None:
properties:
nickname:
type: string
nullable: trueclass User(TypedDict):
nickname: NotRequired[str | None]References
References become quoted forward references:
class Post(TypedDict):
author: "User" # Forward referenceThis allows circular references and ordering flexibility.
Docstrings
Schema descriptions become docstrings:
class User(TypedDict):
"""A user in the system"""
id: str
"""Unique identifier for the user"""
email: str
"""User's email address"""Composition
allOf (Inheritance)
Python TypedDicts support inheritance:
allOf:
- $ref: '#/components/schemas/BaseEntity'
- type: object
properties:
name:
type: stringclass Product(BaseEntity):
name: NotRequired[str]oneOf / anyOf (Union)
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'Pet = Union["Dog", "Cat"]Usage Examples
With FastAPI
from fastapi import FastAPI
from .types.api import User, CreateUserRequest
app = FastAPI()
@app.post("/users")
async def create_user(request: CreateUserRequest) -> User:
# Type checking enforced
return {
"id": "123",
"email": request["email"],
"name": request.get("name")
}With Type Checkers
Run mypy or pyright to catch type errors:
mypy app/
pyright app/Creating Instances
TypedDicts are used like regular dictionaries:
from .types.api import User
# Type-checked dictionary
user: User = {
"id": "123",
"email": "user@example.com",
"name": "John"
}
# Access fields
print(user["email"])
# Optional field access
name = user.get("name", "Anonymous")Validation
TypedDicts provide static type checking only. For runtime validation, consider:
Limitations
No Namespaces
Python format doesn't support namespaces. Use separate output files instead:
"outputs": [
{ "path": "./types/users.py", "contents": ["users:*"] },
{ "path": "./types/products.py", "contents": ["products:*"] }
]Forward References
All type references use quotes for forward reference compatibility:
author: "User" # Not: author: UserPython Version Requirements
| Feature | Minimum Version |
|---|---|
| TypedDict | 3.8 |
| NotRequired | 3.11 |
Union syntax (|) | 3.10 |
Best Practices
Module Organization
Create an __init__.py to re-export types:
# types/__init__.py
from .users import User, UserRole
from .products import ProductType Aliases
Create aliases for common patterns:
from typing import Dict, Any
JSON = Dict[str, Any]Combining with Pydantic
For runtime validation, create Pydantic models alongside TypedDicts:
from pydantic import BaseModel
from .types.api import User as UserDict
class User(BaseModel):
id: str
email: str
name: str | None = None
def to_dict(self) -> UserDict:
return self.model_dump()See Also
- Python TypedDict Documentation
- Configuration Options
- Go Format - Alternative backend format