Flexible structural typing and runtime validation for Python
Project description
Duckdantic 🦆
Duckdantic is a Python library for flexible structural typing and runtime validation. It provides a powerful way to define structural types (traits) and check whether objects satisfy them at runtime, without requiring inheritance or type annotations.
✨ Features
- 🦆 True Duck Typing: Check object structures at runtime without inheritance
- 🏗️ Trait-Based Validation: Define reusable structural requirements
- 🔧 Framework Agnostic: Works with Pydantic, dataclasses, TypedDict, and plain objects
- 🎯 Flexible Policies: Customize type checking behavior to your needs
- 🚀 High Performance: Intelligent caching and optimized field normalization
- 🎨 Intuitive API: Clean, Pythonic interface with excellent IDE support
- 🔌 ABC Integration: Use traits with
isinstance()andissubclass()
📦 Installation
pip install duckdantic
For Pydantic support:
pip install "duckdantic[pydantic]"
🚀 Quick Start
Basic Usage
from duckdantic import TraitSpec, FieldSpec, satisfies
# Define a trait
PersonTrait = TraitSpec(
name="Person",
fields=(
FieldSpec("name", str, required=True),
FieldSpec("age", int, required=True),
)
)
# Check if objects satisfy the trait
class Employee:
def __init__(self, name: str, age: int, employee_id: str):
self.name = name
self.age = age
self.employee_id = employee_id
emp = Employee("Alice", 30, "EMP001")
assert satisfies(emp, PersonTrait) # ✅ True - has required fields
Duck API (Recommended)
The Duck API provides a more ergonomic interface, especially when working with Pydantic models:
from pydantic import BaseModel
from duckdantic import Duck
class User(BaseModel):
name: str
email: str
age: int
class Person(BaseModel):
name: str
age: int
# Create a duck type from a Pydantic model
PersonDuck = Duck(Person)
# Check if instances satisfy the duck type
user = User(name="Bob", email="bob@example.com", age=25)
assert isinstance(user, PersonDuck) # ✅ True - has required fields
# Convert between compatible types
person = PersonDuck.convert(user) # Creates Person(name="Bob", age=25)
Method Checking
from duckdantic import MethodSpec, methods_satisfy
# Define method requirements
DrawableMethods = [
MethodSpec("draw", params=[int, int], returns=None),
MethodSpec("get_color", params=[], returns=str),
]
class Circle:
def draw(self, x: int, y: int) -> None:
pass
def get_color(self) -> str:
return "red"
assert methods_satisfy(Circle, DrawableMethods) # ✅ True
ABC Integration
from duckdantic import TraitSpec, FieldSpec, abc_for
# Define a trait
ConfigTrait = TraitSpec(
name="Config",
fields=(
FieldSpec("host", str),
FieldSpec("port", int),
)
)
# Create an ABC from the trait
ConfigABC = abc_for(ConfigTrait)
# Use with isinstance
@ConfigABC.register
class ServerConfig:
host: str = "localhost"
port: int = 8080
assert isinstance(ServerConfig(), ConfigABC) # ✅ True
🎯 Use Cases
- API Validation: Ensure objects have required fields before processing
- Plugin Systems: Define interfaces without requiring inheritance
- Type Bridges: Convert between similar types from different libraries
- Testing: Create test doubles that satisfy production interfaces
- Configuration: Validate configuration objects from various sources
📚 Documentation
For comprehensive documentation, visit https://pr1m8.github.io/duckdantic/
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Inspired by structural typing concepts from TypeScript and Go interfaces
- Built to complement Pydantic's excellent runtime validation
- Thanks to all contributors and users of the library
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file duckdantic-1.0.1.tar.gz.
File metadata
- Download URL: duckdantic-1.0.1.tar.gz
- Upload date:
- Size: 479.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
695a310899cf5de8f4d77e0a554db9f26aca1b72d13a9484ab90473135220fbd
|
|
| MD5 |
f902de76fbbb3bb7c6fcd12d7c3a85ab
|
|
| BLAKE2b-256 |
069004dc69b5624a45852bacd3e826775a928da7e3bc7c25657f3c90e365d811
|
File details
Details for the file duckdantic-1.0.1-py3-none-any.whl.
File metadata
- Download URL: duckdantic-1.0.1-py3-none-any.whl
- Upload date:
- Size: 32.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a51c4c0603d6aa89b7caf2fecf6ccc5e5728e752012306c577e11a227089c135
|
|
| MD5 |
f3fe7e13ed0a2489987cec9f451cc43d
|
|
| BLAKE2b-256 |
c77212cf8c86a6c2701e66b2137894983a00079ea98ebdbdd06b5e76b63f4dcb
|