API Reference¶
Comprehensive reference for all publicly importable classes, grouped by layer.
Domain Layer¶
from aod.domain import Entity, RootEntity, ValueObject, Service
from aod.domain import Field, PrivateField
from aod.events import Event, IntegrationEvent
from aod.domain.validation import AfterValidator, BeforeValidator, field_invariance, invariance, mutable, get_base_model
Entity¶
Base class for mutable domain objects with identity.
Constructor¶
Entity(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Any |
Keyword arguments matching declared fields. All fields are required unless they have defaults. |
Methods¶
| Method | Signature | Description |
|---|---|---|
reconstruct |
classmethod reconstruct(**kwargs) -> Self |
Create an instance skipping validation. Available via ReconstructMixin. |
copy |
copy(**overrides) -> Self |
Create a copy with optional field overrides. |
__post_init__ |
__post_init__(self) |
Optional hook called after __init__. Runs in mutation context. |
Mutation Rules¶
- Public methods can mutate fields (auto-wrapped with mutation context).
- Direct field mutation from outside raises
MutationForbiddenException. _event_emitteris available as aPrivateField.
RootEntity¶
Aggregate root marker class. Inherits all Entity behavior.
Constructor¶
Same as Entity.
Constraints¶
- Cannot be nested as a field type in other entities (enforced by
BoundedContexttype checking). - Services and Commands/Queries can reference
RootEntitybut not non-rootEntity.
ValueObject¶
Immutable, identity-less value object.
Constructor¶
ValueObject(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Any |
Keyword arguments matching declared fields. All fields are required unless they have defaults. |
Methods¶
| Method | Signature | Description |
|---|---|---|
reconstruct |
classmethod reconstruct(**kwargs) -> Self |
Create an instance skipping validation. |
Constraints¶
- Fields cannot reference
EntityorRootEntity(enforced byBoundedContext). - Mutation is always blocked (
BaseSealed).
Service¶
Stateless domain service with event emission capability.
Constructor¶
Service(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Any |
Keyword arguments matching declared fields. |
Methods¶
Public methods are auto-wrapped with mutation context (can mutate fields).
Constraints¶
- Method parameters and return types cannot reference non-root
Entity(enforced byBoundedContext). _event_emitteris available as aPrivateField.
Event¶
Immutable domain event with auto-timestamp.
Constructor¶
Event(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Any |
Keyword arguments matching declared fields. |
Fields¶
| Field | Type | Description |
|---|---|---|
emitted_at |
datetime |
Auto-set to datetime.now(timezone.utc) on construction. init=False. |
IntegrationEvent¶
Marker subclass of Event for events that cross bounded context boundaries.
Constructor¶
Same as Event. Inherits emitted_at auto-timestamp.
Schema Layer¶
Schema classes for introspection and documentation generation.
BoundedContext¶
Groups related domain types together.
Constructor¶
BoundedContext(
aggregate_roots: Iterable[RootEntityType] | None = None,
services: Iterable[ServiceType] | None = None,
use_cases: Iterable[UseCaseType] | None = None,
*,
name: str | None = None,
)
| Parameter | Type | Default | Description |
|---|---|---|---|
aggregate_roots |
Iterable[type[RootEntity]] \| None |
None |
Root entity classes to include. |
services |
Iterable[type[Service]] \| None |
None |
Service classes to include. |
use_cases |
Iterable[type[UseCase] \| type[AsyncUseCase]] \| None |
None |
Use case classes to include. |
name |
str \| None |
None |
Optional name for the context. |
Attributes¶
| Attribute | Type | Description |
|---|---|---|
aggregate_roots |
tuple[type[RootEntity], ...] |
Registered aggregate roots. |
entities |
tuple[type[Entity], ...] |
All discovered entities. |
value_objects |
tuple[type[ValueObject], ...] |
All discovered value objects. |
services |
tuple[type[Service], ...] |
Registered services. |
use_cases |
tuple[type[UseCase] \| type[AsyncUseCase], ...] |
Registered use cases. |
contracts |
tuple[type[Command] \| type[Query], ...] |
All contracts from use cases. |
ports |
tuple[type[Port], ...] |
All ports from use cases. |
contracts_by_root |
dict[RootEntityType, list[ContractType]] |
Contracts grouped by root entity. |
name |
str \| None |
Context name. |
Type Checking¶
When constructed, runs validation:
- All aggregate_roots must be RootEntity subclasses.
- All services must be Service subclasses.
- Recursively discovers nested entities and value objects from root entity fields.
- Validates: no non-root entities nested in root entities, no entities in value objects, no non-root entities in service method signatures.
App¶
Top-level application container.
Constructor¶
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
— | Application name. |
modules |
Iterable[Module] |
— | One or more modules composing bounded contexts with infrastructure. |
description |
str |
"" |
Optional application description. |
Validation¶
Raises DuplicateDomainTypeError if the same entity or service class appears in multiple contexts across modules.
Module¶
Groups a bounded context with its infrastructure layer.
Constructor¶
| Parameter | Type | Description |
|---|---|---|
name |
str |
Module name. |
context |
BoundedContext |
The bounded context for this module. |
infrastructure |
Infrastructure |
Infrastructure configuration for this module. |
Validation¶
Raises MissingHandlerError if any contract has no matching handler. Raises MissingPortError if any port has no implementation.
Infrastructure¶
Configuration for infrastructure handlers, ports, and sessions.
Constructor¶
Infrastructure(handlers: Iterable[type] | None = None, ports: Iterable[type] | None = None, sessions: Iterable[type] | None = None)
| Parameter | Type | Default | Description |
|---|---|---|---|
handlers |
Iterable[type] \| None |
None |
Handler classes to register. |
ports |
Iterable[type] \| None |
None |
Port classes to register. |
sessions |
Iterable[type] \| None |
None |
Session classes to register. |
AutoDoc¶
Generates a complete zensical documentation site from an App.
Constructor¶
AutoDoc(app: App, output_dir: str | Path, site_name: str | None = None, site_description: str | None = None, repo_url: str | None = None)
| Parameter | Type | Default | Description |
|---|---|---|---|
app |
App |
— | The application to document. |
output_dir |
str \| Path |
— | Output directory for generated site. |
site_name |
str \| None |
None |
Site name (defaults to app name). |
site_description |
str \| None |
None |
Site description. |
repo_url |
str \| None |
None |
Repository URL for edit links. |
Domain Layer (continued)¶
Field¶
Field(
default: Any = ...,
*,
default_factory: Callable[[], Any] | None = ...,
gt: SupportsGt | None = ...,
ge: SupportsGe | None = ...,
lt: SupportsLt | None = ...,
le: SupportsLe | None = ...,
multiple_of: float | None = ...,
strict: bool | None = ...,
min_length: int | None = ...,
max_length: int | None = ...,
pattern: str | re.Pattern[str] | None = ...,
allow_inf_nan: bool | None = ...,
max_digits: int | None = ...,
decimal_places: int | None = ...,
init: bool = True,
) -> Any
Pydantic field wrapper with all standard constraints.
PrivateField¶
Pydantic PrivateAttr wrapper. Fields are not part of the public API surface — excluded from validation models, serialization, and __init__.
Validation Decorators¶
from aod.domain.validation import field_invariance, invariance, AfterValidator, BeforeValidator, mutable
| Decorator | Description |
|---|---|
field_invariance(field_name) |
Validator that runs on a specific field after Pydantic validation. |
invariance |
Model-level validator that runs after all field validators. |
AfterValidator |
Pydantic AfterValidator wrapper. |
BeforeValidator |
Pydantic BeforeValidator wrapper. |
mutable |
Marks a method to bypass the can_mutate() guard on entities (inherits mutation context from caller). |
get_base_model |
Returns the constrained Pydantic BaseModel for any Entity, RootEntity or ValueObject. Field access is type-safe. Use cast(BaseModel, dto) to call Pydantic methods (model_dump_json, etc.) |
Application Layer¶
from aod.application import UseCase, Port, Logger, EventBus, Cache, CacheManager, CacheKey, CacheInvalidation, ContractCacheKey, OperationCacheKey, ContractCacheInvalidation, OperationCacheInvalidation, Command, Query
from aod.application import CommandPort, QueryPort
from aod.application import ApplicationException
from aod.application.async_ import UseCase, Logger, EventBus, Cache
from aod.application.async_ import CommandPort, QueryPort
UseCase¶
Base class for synchronous application use cases.
Constructor¶
UseCase(**fields)
| Parameter | Type | Description |
|---|---|---|
**ports |
Port |
Additional port dependencies declared on the subclass. |
Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
events |
list[Event] |
[] |
Events collected during the last run() call. init=False. |
_loggers |
list[Logger \| AsyncLogger] |
[] |
Collected logger ports. Private. |
_event_buses |
list[EventBus \| AsyncEventBus] |
[] |
Collected event bus ports. Private. |
Methods¶
| Method | Signature | Description |
|---|---|---|
run |
abstractmethod run(self, *args, **kwargs) -> Any |
Execute the use case. Auto-wrapped with EventCollector, transaction, logging, and event publishing. |
Auto-Wrapping Behavior¶
When run() is called:
uow.begin()starts a transaction.- Events are collected via
EventCollectorduring execution. - On success:
uow.commit(), events logged on each declared logger, events published on each declared event bus. - On failure:
uow.rollback(), exception logged on each declared logger, exception re-raised. - If commit fails:
uow.rollback(), commit failure logged on each declared logger, exception re-raised.
Field Validation¶
- Fields must be
Portsubclasses. - Recommended field types:
Commandport[TCommand]andQueryPort[TQuery]. SessionandAsyncSessionare not allowed (raiseInvalidUseCasePortFieldError).BaseHandlerandAsyncBaseHandlerare also rejected.
AsyncUseCase¶
Constructor¶
AsyncUseCase(**fields)
| Parameter | Type | Description |
|---|---|---|
**ports |
Port |
Additional port dependencies declared on the subclass. |
Methods¶
| Method | Signature | Description |
|---|---|---|
run |
abstractmethod async run(self, *args, **kwargs) -> Any |
Async execute the use case. Same auto-wrapping as sync but uses should_await for all port calls. |
Port¶
Abstract base class for defining dependency interfaces.
- No constructor parameters.
- Subclasses declare abstract methods and fields.
- Public methods are auto-wrapped with mutation context.
CommandPort¶
Application-layer handler port for write operations. UseCases declare CommandPort[Command] as fields.
Methods¶
| Method | Signature | Description |
|---|---|---|
handle |
abstractmethod handle(self, command: TCommand) -> TResult |
Execute the command. |
Type Parameters¶
| Parameter | Constraint | Description |
|---|---|---|
TCommand |
Must be a Command subclass |
The command type this port handles. |
Infrastructure provides concrete implementations via CommandHandler[C].
QueryPort¶
Application-layer handler port for read operations. UseCases declare QueryPort[Query] as fields.
Methods¶
| Method | Signature | Description |
|---|---|---|
handle |
abstractmethod handle(self, query: TQuery) -> TResult |
Execute the query. |
Type Parameters¶
| Parameter | Constraint | Description |
|---|---|---|
TQuery |
Must be a Query subclass |
The query type this port handles. |
Infrastructure provides concrete implementations via QueryHandler[Q].
Logger¶
Synchronous logging port.
Methods¶
| Method | Signature | Description |
|---|---|---|
debug |
abstractmethod debug(self, msg: str, **context: object) |
Log at debug level. |
info |
abstractmethod info(self, msg: str, **context: object) |
Log at info level. |
warning |
abstractmethod warning(self, msg: str, **context: object) |
Log at warning level. |
error |
abstractmethod error(self, msg: str, **context: object) |
Log at error level. |
Parameters¶
| Parameter | Type | Description |
|---|---|---|
msg |
str |
The log message. |
**context |
object |
Additional structured context. |
AsyncLogger¶
Same interface as Logger but all methods are async.
EventBus¶
Synchronous event publishing port.
Methods¶
| Method | Signature | Description |
|---|---|---|
publish |
abstractmethod publish(self, *events: Event) |
Publish one or more domain events. |
Parameters¶
| Parameter | Type | Description |
|---|---|---|
*events |
Event |
Domain events to publish. |
AsyncEventBus¶
Same interface but publish is async.
Cache¶
Synchronous cache port.
Methods¶
| Method | Signature | Description |
|---|---|---|
get |
abstractmethod get(self, key: str) -> Any |
Retrieve a value by key. |
set |
abstractmethod set(self, key: str, value: Any, ttl: float \| None = None) |
Store a value with optional TTL. |
delete |
abstractmethod delete(self, key: str) |
Remove a value by key. |
Parameters¶
| Parameter | Type | Description |
|---|---|---|
key |
str |
Cache key. |
value |
Any |
Value to cache. |
ttl |
float \| None |
Time-to-live in seconds. None means no expiry. |
CacheManager¶
CacheManager is a context manager that activates cache context for the duration of a block. Wraps a list of Cache/AsyncCache instances. Inside the context, get_cache_context() returns a context that routes cache operations to the registered caches.
The AdapterContainer.adapt() method wraps operations with CacheManager automatically when caches are configured — you rarely need it directly.
AsyncCache¶
Same interface but get, set, and delete are async.
Warning: AsyncCache only works in async operations (AsyncUseCase, AsyncReadProjection, AsyncWriteProjection). Sync UseCase/Projection silently skip async cache operations — reads return None and writes are discarded.
CacheKey¶
CacheKey(BaseGuarded) — Abstract base for cache key definitions. Subclass via ContractCacheKey (for Query/Command patterns) or OperationCacheKey (for operation-based patterns).
ContractCacheKey¶
ContractCacheKey(CacheKey, Generic[TQuery]) — Maps a Query to a cache key and lists which Command types invalidate it.
Abstract Methods¶
| Method | Signature | Description |
|---|---|---|
key |
abstractmethod key(self, query: TQuery) -> str |
Compute the cache key string from a query. |
invalidate |
abstractmethod invalidate(self) -> list[CacheInvalidation] |
Return invalidation rules for this key (list of ContractCacheInvalidation). |
OperationCacheKey¶
OperationCacheKey(CacheKey, Generic[TOperation]) — Maps a UseCase/Projection operation to a cache key and lists which operations invalidate it.
CacheInvalidation¶
CacheInvalidation(BaseSealed) — Base invalidation descriptor. Subclass via ContractCacheInvalidation or OperationCacheInvalidation.
ContractCacheInvalidation¶
Frozen dataclass pairing a Command type with a key extraction function. Used inside ContractCacheKey.invalidate().
Fields¶
| Field | Type | Description |
|---|---|---|
target_type |
type[Command] |
The command class that triggers invalidation. |
key_fn |
Callable[[Any], str] |
Function that extracts the cache key from a command instance. |
OperationCacheInvalidation¶
Frozen dataclass pairing an operation type with a key extraction function. Used inside OperationCacheKey.invalidate().
Command¶
Immutable command contract for write operations.
Constructor¶
Command(**fields)
Type Parameters¶
| Parameter | Constraint | Description |
|---|---|---|
TEntity |
Must be RootEntity subclass |
The aggregate root this command targets. |
TResult |
Any | The result type. |
Constraints¶
- Fields cannot reference non-root
Entitytypes (even insidelist[Entity],Optional[Entity], etc.). - The generic
TEntityargument is validated to be aRootEntitysubclass at class creation time.
Query¶
Immutable query contract for read operations.
Constructor¶
Query(**fields)
Type Parameters¶
| Parameter | Constraint | Description |
|---|---|---|
TEntity |
Must be RootEntity subclass |
The aggregate root this query targets. |
TResult |
Must contain a RootEntity |
The result type must include at least one RootEntity (e.g. User, list[User], tuple[int, User \| None]). |
Constraints¶
- Same field restrictions as
Command. TResultis validated to contain at least oneRootEntitytype.
Infrastructure Layer¶
from aod.infrastructure import Session, AsyncSession
from aod.infrastructure import ReadProjection, WriteProjection, Projection
from aod.infrastructure import AsyncReadProjection, AsyncWriteProjection, AsyncProjection
from aod.infrastructure import CommandHandler, QueryHandler
from aod.infrastructure import AsyncCommandHandler, AsyncQueryHandler
from aod.infrastructure import AdapterContainer
from aod.infrastructure import InfrastructureException
Session¶
Synchronous database session abstraction.
Methods¶
| Method | Signature | Description |
|---|---|---|
execute |
abstractmethod execute(self, operation: object) -> object |
Execute a write operation. |
query |
abstractmethod query(self, operation: object) -> object |
Execute a read operation. |
begin |
abstractmethod begin(self) -> None |
Start a new transaction. |
commit |
abstractmethod commit(self) -> None |
Commit the transaction. Wrapped to raise CommitOutsideUnitOfWorkError if no _CommitContext. |
rollback |
abstractmethod rollback(self) -> None |
Roll back the transaction. |
close |
abstractmethod close(self) -> None |
Release resources. |
is_dirty |
abstractmethod is_dirty(self) -> bool |
Check for uncommitted changes. |
AsyncSession¶
Same interface as Session but execute, query, begin, commit, rollback, close are async. is_dirty() is sync.
ReadProjection¶
Synchronous read projection.
Constructor¶
ReadProjection(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Port \| Session |
Fields with concrete session types (e.g., session: PostgresSession) and port dependencies. |
Methods¶
| Method | Signature | Description |
|---|---|---|
read |
abstractmethod read(self, model: Any) -> Any |
Execute read logic. Auto-wrapped with event collection, logging, and event bus publish. |
WriteProjection¶
Synchronous write projection.
Constructor¶
WriteProjection(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Port \| Session |
Fields with concrete session types (e.g., session: PostgresSession) and port dependencies. |
Methods¶
| Method | Signature | Description |
|---|---|---|
write |
abstractmethod write(self, model: Any) -> Any |
Execute write logic. Auto-wrapped with CommitContext, transaction begin, event collection, rollback on failure, logging, and event bus publish. |
Projection¶
Combined read and write projection.
Constructor¶
Same as ReadProjection and WriteProjection.
Methods¶
Both read(self, model: Any) -> Any and write(self, model: Any) -> Any.
AsyncReadProjection¶
Constructor¶
AsyncReadProjection(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Port \| Session \| AsyncSession |
Fields with concrete session types and port dependencies. |
Methods¶
| Method | Signature | Description |
|---|---|---|
read |
abstractmethod async read(self, model: Any) -> Any |
Async read. |
AsyncWriteProjection¶
Constructor¶
AsyncWriteProjection(**fields) — Accepts fields with concrete session types (e.g., session: AsyncPostgresSession) and port dependencies.
Methods¶
| Method | Signature | Description |
|---|---|---|
write |
abstractmethod async write(self, model: Any) -> Any |
Async write. |
AsyncProjection¶
Combined async read and write projection. Both read and write are async.
CommandHandler¶
Synchronous command handler for a specific command type.
Constructor¶
CommandHandler(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Any | Fields declared on the subclass (e.g. session, ports) |
Methods¶
| Method | Signature | Description |
|---|---|---|
handle |
abstractmethod handle(self, command: TCommand) -> object |
Handle a command. Returns an implementation-specific result. |
QueryHandler¶
Synchronous query handler for a specific query type.
Constructor¶
QueryHandler(**fields)
| Parameter | Type | Description |
|---|---|---|
**fields |
Any | Fields declared on the subclass (e.g. session, ports) |
Methods¶
| Method | Signature | Description |
|---|---|---|
handle |
abstractmethod handle(self, query: TQuery) -> object |
Handle a query. |
AsyncCommandHandler¶
Constructor¶
AsyncCommandHandler(**fields)
Methods¶
| Method | Signature | Description |
|---|---|---|
handle |
abstractmethod async handle(self, command: TCommand) -> object |
Async handle a command. |
AsyncQueryHandler¶
Constructor¶
AsyncQueryHandler(**fields)
Methods¶
| Method | Signature | Description |
|---|---|---|
handle |
abstractmethod async handle(self, query: TQuery) -> object |
Async handle a query. |
AdapterContainer¶
Dependency injection container. Can be used directly or subclassed.
Constructor¶
AdapterContainer(**fields)
| Parameter | Type | Default | Description |
|---|---|---|---|
sessions |
set[type[Session] \| type[AsyncSession]] |
set() |
Session classes to manage. |
handlers |
list[type[CommandHandler \| QueryHandler \| AsyncCommandHandler \| AsyncQueryHandler]] |
[] |
Handler classes to register. |
ports |
dict[type[Port], Port] |
{} |
Type-based port resolution fallback. |
**fields |
Port |
— | Custom ports registered by field name. Any keyword argument that is a Port instance is registered. |
_ports_by_name |
dict[str, Port] |
{} |
Private index of registered ports by field name. |
_sessions_needed |
dict |
{} |
Private cache of instantiated sessions. |
Methods¶
| Method | Signature | Description |
|---|---|---|
get_session |
get_session(self, session_cls: type) -> Session \| AsyncSession |
Retrieve or instantiate a session. Raises SessionNotFoundError. |
get_handler |
get_handler(self, contract: type[Command \| Query]) -> handler |
Find handler by command/query type. Raises HandlerNotFoundError. |
get_port |
get_port(self, name: str) -> Port |
Find port by registered field name. Raises PortNotFoundError. |
with_adapters |
with_adapters(self, **overrides) -> Self |
Create a copy with overridden fields. |
adapt |
adapt(self, operation_cls, **overrides) -> UseCase \| AsyncUseCase \| ProjectionBase |
Create a use case or projection with all dependencies wired. Dispatches to internal methods based on class type. |
Testing Layer¶
from aod.testing import build, events_of, assert_event_emitted, assert_no_events, check_invariant
from aod.testing import FakeDomain
from aod.testing.doubles import (
SpyLogger, SpyEventBus, SpyCache,
port_stub, spy_session, spy_adapter_container,
spy_command_handler, spy_query_handler,
spy_async_command_handler, spy_async_query_handler,
)
from aod.testing.doubles.application.async_ import SpyLogger, SpyEventBus, SpyCache
build¶
Create domain object skipping validation.
| Parameter | Type | Description |
|---|---|---|
cls |
type[T] |
The class to instantiate. |
**kwargs |
Any |
Field values. |
events_of¶
Extract events from a domain object.
| Parameter | Type | Description |
|---|---|---|
obj |
BaseGuarded |
Entity, ValueObject, or Service. |
assert_event_emitted¶
Assert a specific event was emitted.
| Parameter | Type | Description |
|---|---|---|
events |
Sequence[Event] |
Events list from events_of(). |
event_type |
type[Event] |
Expected event class. |
**attrs |
Any |
Field values to match. |
assert_no_events¶
Assert no events were emitted.
| Parameter | Type | Description |
|---|---|---|
events |
Sequence[Event] |
Events list to check. |
check_invariant¶
check_invariant(cls: type, invariant_name: str, data: dict[str, Any] | None = None, **kwargs: Any) -> None
Run a single invariant validator.
| Parameter | Type | Description |
|---|---|---|
cls |
type |
Class defining the invariant. |
invariant_name |
str |
Name of the validator. |
data |
dict[str, Any] \| None |
Field values. |
**kwargs |
Any |
Additional field values. |
FakeDomain¶
Factory for domain objects with auto-generated data.
| Parameter | Type | Description |
|---|---|---|
model_cls |
type[T] |
Entity, RootEntity, or ValueObject class. |
**defaults |
Any |
Default field values. |
Methods¶
| Method | Signature | Description |
|---|---|---|
__call__ |
__call__(self, **overrides) -> T |
Build an instance with auto-generated fields for unfilled ones. |
batch |
batch(self, count, overrides_list=None) -> list[T] |
Build multiple instances. |
SpyLogger¶
| Property | Type | Description |
|---|---|---|
entries |
list[LogEntry] |
All logged entries. LogEntry has .level, .msg, .context. |
Methods: debug(msg, **context), info(msg, **context), warning(msg, **context), error(msg, **context).
SpyEventBus¶
| Property | Type | Description |
|---|---|---|
published |
list[Event] |
All published events. |
Method: publish(*events).
SpyCache¶
| Properties | Type | Description |
|---|---|---|
get_calls |
list[str] |
Keys passed to get(). |
set_calls |
list[tuple] |
Arguments passed to set(). |
delete_calls |
list[str] |
Keys passed to delete(). |
Methods: get(key), set(key, value, ttl=None), delete(key).
spy_session¶
Create a stub class from any Session or AsyncSession subclass. Every required and custom method becomes a MagicMock (or AsyncMock for async sessions), and is_dirty() returns False by default.
Async Spy Classes¶
Same names as sync variants. All methods that perform I/O are async.
spy_adapter_container¶
Create a version of a container where sessions and ports are replaced with stubs.
| Method | Signature | Description |
|---|---|---|
get_session_stub |
get_session_stub(session_cls) -> Any |
Returns a stub for the given session class |
get_port_stub |
get_port_stub(name: str) -> Any |
Returns a stub for the port registered under the given field name |
get_handler_stub |
get_handler_stub(handler_cls) -> Any |
Returns a stub for the given handler class |
get_handler |
get_handler(contract) -> Any |
Returns the handler for a contract (handle is a stub) |
stub_use_case |
stub_use_case(cls, *, returns=UNSET, raises=UNSET) |
Configure a use case stub before adapt. returns= stubs instance.run to return the given value; raises= makes it raise. |
stub_projection |
stub_projection(cls, *, read_returns=UNSET, read_raises=UNSET, write_returns=UNSET, write_raises=UNSET) |
Configure a projection stub before adapt. Stubs read() or write() to return or raise. |
adapt |
adapt(operation_cls, **overrides) -> operation |
Same as base container. Creates the operation with injected stubs. Call after stub_use_case or stub_projection to apply the configuration. |
spy_command_handler / spy_query_handler¶
spy_command_handler(*, returns: Any = None, raises: Exception | None = None) -> CommandPort
spy_query_handler(*, returns: Any = None, raises: Exception | None = None) -> QueryPort
spy_async_command_handler(*, returns: Any = None, raises: Exception | None = None) -> AsyncCommandPort
spy_async_query_handler(*, returns: Any = None, raises: Exception | None = None) -> AsyncQueryPort
Factory functions that create handler port spies. Each call returns a fresh instance with its own handle() mock — no shared state.
| Parameter | Type | Description |
|---|---|---|
returns |
Any |
Value that handle() returns on every call. Default: None. |
raises |
Exception \| None |
Exception that handle() raises on every call. Takes precedence over returns. |
These implement CommandPort/QueryPort directly so they pass the UseCase port check without __skip_port_check__. Use in manual-DI tests:
spy = spy_command_handler(returns=user)
uc = CreateUserUseCase(save_user=spy)
uc.run(name="Alice")
assert spy.handle.called
session_stub¶
Create a stub class from any Session or AsyncSession subclass. Every required method becomes a MagicMock (or AsyncMock for async sessions), and is_dirty() returns False by default.
port_stub¶
Create a stub class from any Port subclass. Every public method records calls and lets you configure return values.
Stub Control¶
Every stub method is a unittest.mock.MagicMock (or AsyncMock for async methods):
| Property / Method | Description |
|---|---|
.return_value = value |
Always return this value |
.side_effect = exc |
Raise an exception |
.side_effect = [v1, v2] |
Return different values on successive calls |
.called |
Whether the method was called |
.call_count |
Number of calls |
.call_args_list |
List of call objects — each has .args and .kwargs |
Exceptions¶
from aod.exceptions import (
DomainException, MutationForbiddenException, InvarianceException,
InvalidEntityTypeError, InvalidRootEntityTypeError, InvalidNestedTypeError,
InvalidServiceParameterError, DuplicateDomainTypeError, ModelValidationError,
ClassExpectedError, InvalidCommandFieldTypeError, InvalidQueryResultTypeError,
InvalidGenericTypeArgError, InvalidServiceTypeError,
ApplicationException, UnresolvableEntityError, CommitOutsideUnitOfWorkError,
InvalidUseCasePortFieldError, InvalidHandlerPortFieldError,
InfrastructureException, HandlerResultTypeError, HandlerModelError,
PortNotFoundError, SessionNotFoundError,
DuplicateHandlerError, HandlerNotFoundError,
)
DomainException Hierarchy¶
| Exception | Parent | Description |
|---|---|---|
DomainException |
Exception |
Base for all domain errors. |
MutationForbiddenException |
DomainException |
Mutation attempted outside allowed context. |
InvarianceException |
DomainException, ValueError |
Field/model invariance violated. |
InvalidEntityTypeError |
DomainException |
Not an Entity subclass. |
InvalidRootEntityTypeError |
DomainException |
Entity but not RootEntity. |
InvalidNestedTypeError |
DomainException |
Entity field references forbidden domain type. |
InvalidServiceParameterError |
DomainException |
Service param/return type has disallowed type. |
DuplicateDomainTypeError |
DomainException |
Type registered in multiple contexts. |
ModelValidationError |
DomainException |
Pydantic validation failed. Wraps ValidationError. |
ClassExpectedError |
DomainException |
Instance given where class required. |
InvalidCommandFieldTypeError |
DomainException |
Command/Query field references non-root Entity. |
InvalidQueryResultTypeError |
DomainException |
Query TResult does not include a RootEntity. |
InvalidGenericTypeArgError |
DomainException |
Generic argument fails its constraint. |
InvalidServiceTypeError |
DomainException |
Not a Service subclass. |
ApplicationException Hierarchy¶
| Exception | Parent | Description |
|---|---|---|
ApplicationException |
Exception |
Base for application errors. |
UnresolvableEntityError |
ApplicationException |
Cannot determine RootEntity from Command/Query. |
CommitOutsideUnitOfWorkError |
ApplicationException |
Commit outside a Transaction context. |
InvalidUseCasePortFieldError |
ApplicationException |
UseCase field is not a Port subclass. |
InvalidHandlerPortFieldError |
ApplicationException |
HandlerProtocol port missing generic type argument. |
InfrastructureException Hierarchy¶
| Exception | Parent | Description |
|---|---|---|
InfrastructureException |
Exception |
Base for infrastructure errors. |
HandlerResultTypeError |
InfrastructureException |
Handler returned wrong type. |
HandlerModelError |
InfrastructureException |
Handler missing required field. |
PortNotFoundError |
InfrastructureException |
No port of requested type registered. |
SessionNotFoundError |
InfrastructureException |
No session of requested type registered. |
DuplicateHandlerError |
InfrastructureException |
Duplicate handler for same contract. |
HandlerNotFoundError |
InfrastructureException |
No handler for given contract. |
Next Steps¶
Sessions
Database abstraction
Projections
Read/write data efficiently
Container
Dependency injection
Testing Utilities
Testing with spies