Type-safe DTOs for clean architecture in Python, built on Pydantic v2
Project description
Potato
Type-safe DTOs for clean architecture in Python
Potato is a Python library that enforces clean separation between your domain models and external data representations. Built on Pydantic v2, it provides type-safe Data Transfer Objects (DTOs) with class-definition-time validation via metaclasses.
Features
- Type Safety: Class-definition-time validation via metaclasses
- Unidirectional Data Flow: Separate
ViewDTO(outbound) andBuildDTO(inbound) - Field Mapping: Map domain fields to different names using
Field(source=...) - Computed Fields: Add derived fields with
@computeddecorator - Auto Fields: Handle auto-generated fields with
Auto[T] - Private Fields: Protect sensitive fields with
Private[T](never exposed in DTOs) - Aggregates: Compose multiple domains with field-based aggregates
- Nested ViewDTOs: Auto-build nested ViewDTO types
- ViewDTO Inheritance: Extend ViewDTOs for summary/detail patterns
- Partial Updates:
BuildDTOwithpartial=Trueandapply_to() - Field Transforms: Transform values with
Field(transform=...) - Field Visibility: Control visibility with
Field(visible=...) - Lifecycle Hooks:
@before_buildand@after_builddecorators - Immutability: ViewDTOs are frozen by default
Quick Example
from potato import Domain, ViewDTO, BuildDTO, Field, Auto, Private, computed
# Define your domain model
class User(Domain):
id: Auto[int] # Auto-managed field
username: str
email: str
password_hash: Private[str] # Never exposed in DTOs
# Create a ViewDTO for API responses (outbound)
class UserView(ViewDTO[User]):
id: int
login: str = Field(source=User.username) # Map username -> login
email: str
@computed
def display_name(self, user: User) -> str:
return f"@{user.username}"
# Create a BuildDTO for API requests (inbound)
class UserCreate(BuildDTO[User]):
username: str
email: str
# 'id' (Auto) and 'password_hash' (Private) are excluded
# Usage - Outbound
user = User(id=1, username="alice", email="alice@example.com", password_hash="hashed")
view = UserView.from_domain(user)
print(view.login) # "alice"
print(view.display_name) # "@alice"
# Usage - Inbound
dto = UserCreate(username="bob", email="bob@example.com")
user = dto.to_domain(id=2, password_hash="hashed_value") # Provide auto & private fields
Installation
pip install potato
Or with uv:
uv add potato
Documentation
- Quickstart Guide - Get started in 5 minutes
- Philosophy - Understand the philosophy and design
- ViewDTO Guide - Outbound data flow
- BuildDTO Guide - Inbound data flow
- Aggregates - Multi-domain composition
- Validation - Class-definition-time validation
- Examples - Real-world use cases
Why Potato?
Modern applications need clear boundaries between:
- External data (API requests, database records)
- Domain logic (business models and rules)
- External representations (API responses, serialized data)
Potato enforces these boundaries with:
- Type-safe DTOs that prevent coupling
- Explicit transformations that are easy to trace
- Class-definition-time validation that catches errors early
- Immutable views that prevent accidental mutations
Development
# Install dependencies
uv sync
# Run tests
uv run pytest
# Type check
uv run mypy src/
# Run all checks
uv run pytest && uv run mypy src/
License
MIT
Ready to get started? -> Quickstart Guide
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 potato_dto-0.1.0.tar.gz.
File metadata
- Download URL: potato_dto-0.1.0.tar.gz
- Upload date:
- Size: 239.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42bb84ad4a72e2c8aa6180c6f950a68ad032d981fd617b42445c802d61f91ec4
|
|
| MD5 |
d676116c393fca6833b90cefa1043edf
|
|
| BLAKE2b-256 |
0a913a7a74c923d607f93717ce77470fee22895301ffeda865563810fd4407d8
|
File details
Details for the file potato_dto-0.1.0-py3-none-any.whl.
File metadata
- Download URL: potato_dto-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d472a957a408c859572345c961a6839cdb31eecbb9031680356851451ac8b8c6
|
|
| MD5 |
907ceec15df06311ada6d35d45d106e5
|
|
| BLAKE2b-256 |
601746f1ffbb52e0c2262153c9a6b8b327b6b4f4fc197a759f9c52851610a981
|