Skip to main content

Flexible structural typing and runtime validation for Python

Project description

Duckdantic 🦆

PyPI Python Version License Tests Documentation

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() and issubclass()

📦 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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

duckdantic-1.0.2.tar.gz (9.4 MB view details)

Uploaded Source

File details

Details for the file duckdantic-1.0.2.tar.gz.

File metadata

  • Download URL: duckdantic-1.0.2.tar.gz
  • Upload date:
  • Size: 9.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.8

File hashes

Hashes for duckdantic-1.0.2.tar.gz
Algorithm Hash digest
SHA256 1f2c492f6d73beaaf69baa407dc6a9bd459739cfb916ae65a99026fff36bd4c7
MD5 5d2505d9569008a2aa13b148e3d22d57
BLAKE2b-256 42ddd74c80b122043b3d3b1b23c924f12ce6737524cae8af88d07bef65d0629b

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