static-refl
A Python library for static type reflection with full type safety.
Overview
static-refl provides compile-time type introspection and runtime serialization capabilities for Python 3.12.5+. It analyzes type annotations to generate efficient serializers and deserializers without requiring manual schema definitions.
Features
- Type Reflection: Extract structured type information from Python type hints
- JSON Serialization: Type-safe conversion between Python objects and JSON-compatible dictionaries
- Generic Type Support: Full support for generic dataclasses and TypedDicts with type parameters
- Field Renaming: Automatic case conversion (camelCase, kebab-case, snake_case, etc.)
- Complex Types: Support for datetime, UUID, bytes, complex numbers, and nested structures
- Union Types: Handle discriminated unions and optional fields
- Zero Runtime Overhead: Reflection happens at the type level with cached results
Installation
pip install static-refl
Quick Start
from dataclasses import dataclass
import static_refl as sr
@dataclass
class User:
id: int
name: str
email: str | None = None
# Serialize to dict
user = User(id=1, name="Alice", email="alice@example.com")
# to avoid reflection overhead, cache the schema first with:
# user_schema = sr.json.Schema[User]
# user_schema.to_untyped(user)
data = sr.json.Schema[User].to_untyped(user)
# {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'}
# Deserialize from dict
user_copy = sr.json.Schema[User].to_typed(data)
assert user == user_copy
Advanced Usage
Field Renaming
Use @refl_options to automatically convert field names:
from dataclasses import dataclass
import static_refl as sr
@sr.refl_options(rename_all="kebab-case")
@dataclass
class Config:
api_key: str
max_retries: int
config = Config(api_key="secret", max_retries=3)
data = sr.json.Schema[Config].to_untyped(config)
# {'api-key': 'secret', 'max-retries': 3}
Supported case conversions:
kebab-casesnake_casecamelCaselowercaseUPPERCASE
Custom Field Names
Use @refl_rename for specific field mappings:
@sr.refl_rename(user_id="userId", created_at="createdAt")
@dataclass
class Document:
user_id: int
created_at: str
Generic Types
Full support for generic dataclasses:
from dataclasses import dataclass
from typing import Generic, TypeVar
import static_refl as sr
T = TypeVar('T')
@dataclass
class Container[T]:
value: T
items: list[T]
# Works with concrete type parameters
int_container = Container(value=42, items=[1, 2, 3])
data = sr.json.Schema[Container[int]].to_untyped(int_container)
result = sr.json.Schema[Container[int]].to_typed(data)
Complex Nested Structures
from dataclasses import dataclass
import datetime
import static_refl as sr
@dataclass
class Address:
street: str
city: str
@dataclass
class Person:
name: str
born: datetime.date
addresses: dict[str, Address]
person = Person(
name="Bob",
born=datetime.date(1990, 1, 1),
addresses={
"home": Address(street="123 Main St", city="Springfield"),
"work": Address(street="456 Office Rd", city="Shelbyville")
}
)
data = sr.json.Schema[Person].to_untyped(person)
person_copy = sr.json.Schema[Person].to_typed(data)
JSON Serialization Options
Customize serialization behavior with JsonSerdeOptions:
from static_refl.json import JsonSerdeOptions, UUIDEncoding
import uuid
options = JsonSerdeOptions(
keep_bytes=True, # Don't base64-encode bytes
keep_complex=True, # Keep complex numbers as-is
uuid_encoding=UUIDEncoding.hex # Encode UUIDs as hex strings
)
data = sr.json.Schema[MyClass].to_untyped(obj, options=options)
UUID encoding options:
UUIDEncoding.hex- Encode as hex string (default)UUIDEncoding.bytes- Encode as bytesUUIDEncoding.object- Keep as UUID object
Supported Types
Primitive Types
int,float,str,boolbytes,complexdatetime.datetime,datetime.dateuuid.UUID
Collection Types
list[T],tuple[T, ...],set[T]dict[K, V]- Fixed-length tuples:
tuple[int, str, bool] - Variadic tuples:
tuple[int, str, ...]
Structured Types
dataclass(with@dataclassdecorator)TypedDict(with required/optional fields)
Special Types
T | None(Optional types)Union[A, B, C](Discriminated unions)Literal[1, 2, 3](Literal types)Any(Untyped values)- Generic type parameters
API Reference
Core Functions
refl(tp: type) -> TypeId
Reflect on a type and return its type descriptor.
from static_refl import refl
type_id = refl(list[int])
print(type_id) # array[!int]
Decorators
@refl_options(rename_all=None)
Configure serialization options for a class.
@refl_rename(**kwargs)
Map specific field names to serialization keys.
JSON Schema
Schema[T].to_untyped(obj: T, options=None) -> dict | list
Serialize a typed object to JSON-compatible structure.
Schema[T].to_typed(data: dict | list, options=None) -> T
Deserialize JSON-compatible structure to typed object.
Type Reflection
The core refl() function returns a TypeId object representing the structure:
from static_refl import refl
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
type_id = refl(Point)
print(type_id) # Point
print(type_id.structure.fields)
# (FieldDef(name='x', serde_name='x', type=!float, nullable=False),
# FieldDef(name='y', serde_name='y', type=!float, nullable=False))
Requirements
- Python >= 3.12.5
- casefy >= 1.1.0
Development
Running Tests
pytest
License
See LICENSE file for details.
Metadata
Release files for static-refl 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| static_refl-0.3.0.tar.gz | 22.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| static_refl-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.9 kB
Release files / static_refl-0.3.0.tar.gz
| Download URL | static_refl-0.3.0.tar.gz |
|---|---|
| Size | 22.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
776e4d0acfff98e6c9592ff51cc146d23f4b4dd46a1e9707aa311620d06487ac
|
|
BLAKE2b-256 checksum How to use checksums |
ad3676a7bb7c8a51d3057bf1e26b7b3c69524f8ec46d9ae7160dd96035ff9794
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Release files / static_refl-0.3.0-py3-none-any.whl
| Download URL | static_refl-0.3.0-py3-none-any.whl |
|---|---|
| Size | 15.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7cb11a64e48c6574ad00a302df4d97f983a4114e71268c7072392e499e6f76f8
|
|
BLAKE2b-256 checksum How to use checksums |
f2953596875c7cafc669984e2163a639695f045a6eaf0a55635e09bc9c1f959e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|