Skip to main content

Pydantic Custom Types

Use any type with pydantic, without any of the hassle

Installation

You can install this package with pip.

$ pip install pydantic-custom-type-adapter

Links

Documentation

Source Code - GitHub

PyPI - pydantic-custom-type-adapter

Usage

The pydantic-custom-type-adapter package provides a simple way to integrate custom types with Pydantic models through the PydanticAdapter class. This adapter handles serialization and deserialization of your custom types, making them fully compatible with Pydantic's validation system.

By using PydanticAdapter, you can seamlessly integrate any custom type with Pydantic's validation system, without having to modify the original type or create complex serialization logic.

Basic usage

To use a custom type with Pydantic:

  1. Import the necessary components:
from typing import Annotated
from pydantic import BaseModel
from pydantic_custom_type_adapter import PydanticAdapter
  1. Create an adapter for your custom type:
from my_module import MyCustomType

# Define how to parse from JSON and dump to JSON
MyCustomTypeAnnotation = Annotated[
    MyCustomType,
    PydanticAdapter(
        type=MyCustomType,
        parse=MyCustomType.from_string,  # Convert string to MyCustomType
        dump=str  # Convert MyCustomType to string
    )
]
  1. Use the custom type in your Pydantic model:
class MyModel(BaseModel):
	custom_field: MyCustomTypeAnnotation

Complete example

Here's a complete example with a custom Email type:

from typing import Annotated
from pydantic import BaseModel
from pydantic_custom_type_adapter import PydanticAdapter

class Email:
    def __init__(self, address: str):
        if "@" not in address:
            raise ValueError("Invalid email address")
        self.address = address

    def __str__(self) -> str:
        return self.address

# Create the adapter
EmailType = Annotated[Email, PydanticAdapter(type=Email, parse=Email, dump=str)]

# Use in a model
class User(BaseModel):
    name: str
    email: EmailType

# Create a model instance
user = User(name="John Doe", email="john@example.com")
# or with an already constructed Email instance
user = User(name="Jane Doe", email=Email("jane@example.com"))

# Serialize to JSON
json_data = user.model_dump_json()
print(json_data)  # {"name": "John Doe", "email": "john@example.com"}

# Deserialize from JSON
user_dict = {"name": "Alice", "email": "alice@example.com"}
user = User.model_validate(user_dict)
print(user.email.address)  # alice@example.com

Working with complex types

The PydanticAdapter also works with complex types that need custom serialization to JSON:

from datetime import datetime, timezone
from typing import Annotated, Any, Self

from pydantic import BaseModel
from pydantic_custom_type_adapter import PydanticAdapter

class Timestamp:
    def __init__(self, dt: datetime):
        self.datetime = dt

    @classmethod
    def parse(cls, data: dict[str, Any]) -> Self:
        return cls(datetime.fromisoformat(data["iso"]))

    def to_dict(self) -> dict[str, Any]:
        return {
            "iso": self.datetime.isoformat(),
            "unix": int(self.datetime.timestamp())
        }

# Create the adapter with dict serialization
TimestampType = Annotated[
    Timestamp,
    PydanticAdapter(
        type=Timestamp,
        parse=Timestamp.parse,
        dump=lambda ts: ts.to_dict()
    )
]

class Event(BaseModel):
    name: str
    timestamp: TimestampType

# Create and use the model
event = Event(
    name="Server Started",
    timestamp=Timestamp(datetime.now(timezone.utc))
)

# Serialize to JSON - timestamp will be a dictionary with iso and unix fields
json_data = event.model_dump_json()
print(json_data)

Multiple adapters for different contexts

You can create multiple annotations for the same type to handle different serialization formats:

from typing import Annotated, Self
from pydantic import BaseModel
from pydantic_custom_type_adapter import PydanticAdapter

class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @classmethod
    def from_string(cls, value: str) -> Self:
        x, y = map(float, value.split(","))
        return cls(x, y)

    @classmethod
    def from_dict(cls, data: dict) -> Self:
        return cls(data["x"], data["y"])

    def to_string(self) -> str:
        return f"{self.x},{self.y}"

    def to_dict(self) -> dict:
        return {"x": self.x, "y": self.y}

# String representation adapter
PointString = Annotated[
    Point,
    PydanticAdapter(
        type=Point,
        parse=Point.from_string,
        dump=lambda p: p.to_string()
    )
]

# Dictionary representation adapter
PointDict = Annotated[
    Point,
    PydanticAdapter(
        type=Point,
        parse=Point.from_dict,
        dump=lambda p: p.to_dict()
    )
]

# Use different representations in different models
class LocationString(BaseModel):
    position: PointString

class LocationDict(BaseModel):
    position: PointDict

Metadata

Release files for pydantic-custom-type-adapter 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pydantic-custom-type-adapter 0.0.1
File Size Uploaded
pydantic_custom_type_adapter-0.0.1.tar.gz 38.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pydantic-custom-type-adapter 0.0.1
File Interpreter ABI Platform
pydantic_custom_type_adapter-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 54.9 kB

Release files / pydantic_custom_type_adapter-0.0.1.tar.gz

Download URL pydantic_custom_type_adapter-0.0.1.tar.gz
Size 38.4 kB
Tags Source
SHA-256 checksum
How to use checksums
c9fb6dca33d4251b5b5927153e697ab7900992f34c6be7859c40ee8c3660e706
BLAKE2b-256 checksum
How to use checksums
03e4f1290a8227b54509f755b410d7cf003019f43a4fe92363429c1f250a7e7c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.17

Release files / pydantic_custom_type_adapter-0.0.1-py3-none-any.whl

Download URL pydantic_custom_type_adapter-0.0.1-py3-none-any.whl
Size 16.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e1912c6e977e1886998aaed0ee6a6dc2bedb04c456d04795febad64e178f05aa
BLAKE2b-256 checksum
How to use checksums
32e69a7dbc1a494f590053df56d5b1f3fbade4db66d1281205dc5738a71111f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.17

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page