Define business entities, declare relationships, let the framework assemble your data.
pip install pydantic-resolve
Components map 1:1 to Clean Architecture — dependency direction always points inward.
Define business entities and relationships independent of any framework or database — the stable core everything else derives from.
Automate data assembly orchestration — resolve loads missing data with batching, post computes derived fields after the tree is ready.
Abstract data sources behind a unified interface. Swap SQLAlchemy for Django or Tortoise ORM — Entity and Response stay untouched.
Replace manual loops with declarative data loading.
# Sprint has 10 tasks, each needs owner
for task in sprint.tasks:
task.owner = await get_user(task.owner_id)
# 10 queries!
class TaskView(BaseModel):
owner_id: int
owner: Optional[UserView] = None
def resolve_owner(self, loader=Loader(user_loader)):
return loader.load(self.owner_id)
# 1 query!
class UserEntity(BaseModel, BaseEntity):
id: int
name: str
class TaskEntity(BaseModel, BaseEntity):
__relationships__ = [
Relationship(fk='owner_id', target=UserEntity, loader=user_loader),
]
id: int
name: str
owner_id: int
class StoryEntity(BaseModel, BaseEntity):
__relationships__ = [
Relationship(fk='id', target=list[TaskEntity], loader=task_loader),
]
id: int
name: str
class TaskSummary(DefineSubset):
__subset__ = (TaskEntity, ('id', 'name'))
owner: Optional[UserEntity] = None # implicit match, no AutoLoad
class StoryView(DefineSubset):
__subset__ = (StoryEntity, ('id', 'name'))
tasks: list[TaskSummary] = [] # implicit match
@router.get("/stories")
async def get_stories():
stories = [StoryView.model_validate(s)
for s in await get_stories_from_db()]
return await Resolver().resolve(stories)
[
{
"id": 1,
"name": "Sprint 1",
"tasks": [
{
"id": 101,
"name": "Implement login",
"owner": { "id": 1, "name": "Alice" }
}
]
}
]
Start simple, scale as needed. Each concept builds on the last.
From loading related data to generating GraphQL APIs — all in one library.
Auto-batch queries via DataLoader pattern. 100 lookups become 1 query.
Compute derived fields after all nested data is resolved. Counts, aggregates, formatting.
ExposeAs, SendTo, Collector — pass context down or aggregate data up without traversal code.
Centralize relationship declarations. Reuse across models, GraphQL, and MCP services.
Auto-generate GraphQL schema and resolvers from your ER Diagram.
Expose GraphQL APIs to AI agents via Model Context Protocol.
Works with your existing frameworks and ORMs.
Every feature is covered — from core resolution to ER Diagram, cross-layer data flow, and edge cases.
Entity-First architecture keeps your API independent of database changes. No more cascade refactoring.
Every commit passes automated CI. Python 3.10–3.13 compatible with continuous integration.
Define entities, declare relationships, let the framework assemble. Start from resolve_*, scale to ER Diagram when ready.