Entities¶
Overview¶
Entities are the core data models in enrichmcp. They extend Pydantic's BaseModel
with additional capabilities for relationships and introspection.
EnrichModel Base Class¶
All entities must inherit from EnrichModel
:
from enrichmcp import EnrichModel
from pydantic import Field
class MyEntity(EnrichModel):
id: int = Field(description="Unique identifier")
Class Methods¶
relationship_fields() -> set[str]
¶
Returns the names of all relationship fields in the model.
relationships() -> set[Relationship]
¶
Returns all relationship instances in the model.
describe() -> str
¶
Generate a human-readable description of the model instance.
user = User(id=1, name="John")
print(user.describe())
# # User
# User account.
#
# ## Fields
# - **id** (int): User ID
# - **name** (str): Username
#
# ## Relationships
# - **orders** → list[Order]: User's orders
Creating Entities¶
Basic Entity¶
@app.entity
class Product(EnrichModel):
"""Product in our catalog."""
id: int = Field(description="Product ID")
name: str = Field(description="Product name")
price: float = Field(description="Price in USD")
stock: int = Field(description="Available quantity")
Entity with Relationships¶
@app.entity
class Customer(EnrichModel):
"""Customer account."""
id: int = Field(description="Customer ID")
email: str = Field(description="Email address")
# One-to-many relationship
orders: list["Order"] = Relationship(description="Customer's orders")
# One-to-one relationship
profile: "Profile" = Relationship(description="Customer profile")
Entity with Validation¶
from pydantic import field_validator
@app.entity
class Product(EnrichModel):
"""Product with validation."""
name: str = Field(description="Product name")
price: float = Field(description="Price in USD")
@field_validator("price")
@classmethod
def price_must_be_positive(cls, v: float) -> float:
if v <= 0:
raise ValueError("Price must be positive")
return v
Field Types¶
Basic Types¶
name: str = Field(description="Text field")
age: int = Field(description="Integer field")
price: float = Field(description="Decimal field")
is_active: bool = Field(description="Boolean field")
Optional Fields¶
Date/Time Fields¶
from datetime import date, datetime
birth_date: date = Field(description="Date of birth")
created_at: datetime = Field(description="Creation timestamp")
Enum Fields¶
from enum import Enum
class Status(str, Enum):
ACTIVE = "active"
INACTIVE = "inactive"
status: Status = Field(description="Account status")
Collection Fields¶
tags: list[str] = Field(description="List of tags", default_factory=list)
metadata: dict[str, Any] = Field(description="Arbitrary metadata", default_factory=dict)
Mutable Fields¶
Fields are immutable unless mutable=True
:
@app.entity
class Customer(EnrichModel):
id: int = Field(description="ID")
email: str = Field(mutable=True, description="Email")
# Customer.PatchModel is generated automatically
Serialization¶
EnrichModel automatically excludes relationship fields when serializing:
user = User(id=1, email="john@example.com")
# Relationships excluded from dict
data = user.model_dump()
# {"id": 1, "email": "john@example.com"}
# Relationships excluded from JSON
json_str = user.model_dump_json()
# '{"id": 1, "email": "john@example.com"}'
Computed Properties¶
Add derived data using properties:
@app.entity
class Order(EnrichModel):
"""Order with computed total."""
subtotal: float = Field(description="Subtotal")
tax_rate: float = Field(description="Tax rate")
@property
def tax(self) -> float:
"""Calculate tax amount."""
return self.subtotal * self.tax_rate
@property
def total(self) -> float:
"""Calculate total."""
return self.subtotal + self.tax
Best Practices¶
- Always include docstrings - The class docstring becomes the entity description
- Describe every field - All fields must have descriptions
- Use meaningful names -
customer_email
notce
- Group related fields - Consider nested models for complex data
- Add validation - Use Pydantic validators for business rules
Complete Example¶
from datetime import datetime
from enum import Enum
from enrichmcp import EnrichModel, Relationship
from pydantic import Field, field_validator
class OrderStatus(str, Enum):
PENDING = "pending"
SHIPPED = "shipped"
DELIVERED = "delivered"
@app.entity
class Order(EnrichModel):
"""Customer order with validation and relationships."""
# Basic fields
id: int = Field(description="Order ID")
status: OrderStatus = Field(description="Order status", default=OrderStatus.PENDING)
# Amounts
subtotal: float = Field(description="Order subtotal")
tax_rate: float = Field(description="Tax rate (0.08 = 8%)", ge=0.0, le=1.0)
shipping: float = Field(description="Shipping cost", ge=0.0)
# Timestamps
created_at: datetime = Field(description="Order creation time", default_factory=datetime.now)
shipped_at: datetime | None = Field(default=None, description="When order was shipped")
# Relationships
customer: "Customer" = Relationship(description="Customer who placed the order")
items: list["OrderItem"] = Relationship(description="Items in the order")
# Computed properties
@property
def tax(self) -> float:
"""Calculate tax amount."""
return round(self.subtotal * self.tax_rate, 2)
@property
def total(self) -> float:
"""Calculate order total."""
return round(self.subtotal + self.tax + self.shipping, 2)
# Validation
@field_validator("subtotal", "shipping")
@classmethod
def amounts_positive(cls, v: float) -> float:
if v < 0:
raise ValueError("Amount cannot be negative")
return v