Use any type with pydantic, without any of the hassle
Project description
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
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:
- Import the necessary components:
from typing import Annotated
from pydantic import BaseModel
from pydantic_custom_type_adapter import PydanticAdapter
- 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
)
]
- 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
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 pydantic_custom_type_adapter-0.0.1.tar.gz.
File metadata
- Download URL: pydantic_custom_type_adapter-0.0.1.tar.gz
- Upload date:
- Size: 38.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9fb6dca33d4251b5b5927153e697ab7900992f34c6be7859c40ee8c3660e706
|
|
| MD5 |
62824f416522b3389485a6f03df05369
|
|
| BLAKE2b-256 |
03e4f1290a8227b54509f755b410d7cf003019f43a4fe92363429c1f250a7e7c
|
File details
Details for the file pydantic_custom_type_adapter-0.0.1-py3-none-any.whl.
File metadata
- Download URL: pydantic_custom_type_adapter-0.0.1-py3-none-any.whl
- Upload date:
- Size: 16.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1912c6e977e1886998aaed0ee6a6dc2bedb04c456d04795febad64e178f05aa
|
|
| MD5 |
a992ba18e7fd1fb1cf0d066bb0bde996
|
|
| BLAKE2b-256 |
32e69a7dbc1a494f590053df56d5b1f3fbade4db66d1281205dc5738a71111f1
|