Skip to content

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

class Entity(ReconstructMixin, BaseGuarded)

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_emitter is available as a PrivateField.

RootEntity

class RootEntity(Entity)

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 BoundedContext type checking).
  • Services and Commands/Queries can reference RootEntity but not non-root Entity.

ValueObject

class ValueObject(ReconstructMixin, BaseSealed)

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 Entity or RootEntity (enforced by BoundedContext).
  • Mutation is always blocked (BaseSealed).

Service

class Service(BaseBehaviour)

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 by BoundedContext).
  • _event_emitter is available as a PrivateField.

Event

class Event(BaseSealed)

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

class IntegrationEvent(Event)

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.

from aod.schema import App, AutoDoc, BoundedContext, Infrastructure, Module

BoundedContext

class 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

class App

Top-level application container.

Constructor

App(name: str, modules: Iterable[Module], description: str = "")
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

class Module

Groups a bounded context with its infrastructure layer.

Constructor

Module(name: str, context: BoundedContext, infrastructure: Infrastructure)
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

class 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

class 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

PrivateField(default: Any = Unset(), *, default_factory: Callable[[], Any] | None = None) -> Any

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

class UseCase(BaseOperation)

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:

  1. uow.begin() starts a transaction.
  2. Events are collected via EventCollector during execution.
  3. On success: uow.commit(), events logged on each declared logger, events published on each declared event bus.
  4. On failure: uow.rollback(), exception logged on each declared logger, exception re-raised.
  5. If commit fails: uow.rollback(), commit failure logged on each declared logger, exception re-raised.

Field Validation

  • Fields must be Port subclasses.
  • Recommended field types: Commandport[TCommand] and QueryPort[TQuery].
  • Session and AsyncSession are not allowed (raise InvalidUseCasePortFieldError).
  • BaseHandler and AsyncBaseHandler are also rejected.

AsyncUseCase

class AsyncUseCase(BaseOperation)

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

class Port(BaseGuarded)

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

class CommandPort(HandlerProtocol, Generic[TCommand])

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

class QueryPort(HandlerProtocol, Generic[TQuery])

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

class Logger(Port)

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

from aod.application.async_ import Logger

Same interface as Logger but all methods are async.

EventBus

class EventBus(Port)

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

from aod.application.async_ import EventBus

Same interface but publish is async.

Cache

class Cache(Port)

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

from aod.application import CacheManager
from aod.application.cache import 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.

with CacheManager(cache):
    result = use_case.run(...)  # handler reads through cache

The AdapterContainer.adapt() method wraps operations with CacheManager automatically when caches are configured — you rarely need it directly.

AsyncCache

from aod.application.async_ import Cache

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

from aod.application import CacheKey

CacheKey(BaseGuarded) — Abstract base for cache key definitions. Subclass via ContractCacheKey (for Query/Command patterns) or OperationCacheKey (for operation-based patterns).

ContractCacheKey

from aod.application import 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

from aod.application import OperationCacheKey

OperationCacheKey(CacheKey, Generic[TOperation]) — Maps a UseCase/Projection operation to a cache key and lists which operations invalidate it.

CacheInvalidation

from aod.application import CacheInvalidation

CacheInvalidation(BaseSealed) — Base invalidation descriptor. Subclass via ContractCacheInvalidation or OperationCacheInvalidation.

ContractCacheInvalidation

from aod.application import 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

from aod.application import OperationCacheInvalidation

Frozen dataclass pairing an operation type with a key extraction function. Used inside OperationCacheKey.invalidate().

Command

class Command(BaseSealed, Generic[TEntity, TResult])

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 Entity types (even inside list[Entity], Optional[Entity], etc.).
  • The generic TEntity argument is validated to be a RootEntity subclass at class creation time.

Query

class Query(BaseSealed, Generic[TEntity, TResult])

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.
  • TResult is validated to contain at least one RootEntity type.

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

class Session(Port)

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

class AsyncSession(Port)

Same interface as Session but execute, query, begin, commit, rollback, close are async. is_dirty() is sync.

ReadProjection

class ReadProjection(ReadProjectionBase)

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

class WriteProjection(WriteProjectionBase)

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

class Projection(ReadProjection, WriteProjection)

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

class AsyncReadProjection(AsyncReadProjectionBase)

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

class AsyncWriteProjection(AsyncWriteProjectionBase)

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

class AsyncProjection(AsyncReadProjection, AsyncWriteProjection)

Combined async read and write projection. Both read and write are async.

CommandHandler

class CommandHandler(BaseHandler, AppCommandHandler, Generic[TCommand])

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

class QueryHandler(BaseHandler, AppQueryHandler, Generic[TQuery])

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

class AsyncCommandHandler(AsyncBaseHandler, AppAsyncCommandHandler, Generic[TCommand])

Constructor

AsyncCommandHandler(**fields)

Methods

Method Signature Description
handle abstractmethod async handle(self, command: TCommand) -> object Async handle a command.

AsyncQueryHandler

class AsyncQueryHandler(AsyncBaseHandler, AppAsyncQueryHandler, Generic[TQuery])

Constructor

AsyncQueryHandler(**fields)

Methods

Method Signature Description
handle abstractmethod async handle(self, query: TQuery) -> object Async handle a query.

AdapterContainer

class AdapterContainer(BaseBehaviour)

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

build(cls: type[T], **kwargs: Any) -> T

Create domain object skipping validation.

Parameter Type Description
cls type[T] The class to instantiate.
**kwargs Any Field values.

events_of

events_of(obj: BaseGuarded) -> list[Event]

Extract events from a domain object.

Parameter Type Description
obj BaseGuarded Entity, ValueObject, or Service.

assert_event_emitted

assert_event_emitted(events: Sequence[Event], event_type: type[Event], **attrs: Any) -> Event

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(events: Sequence[Event]) -> None

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

FakeDomain(model_cls: type[T], **defaults: Any)

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

spy_session(session_cls: type[Session | AsyncSession]) -> type

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

from aod.testing.doubles.application.async_ import SpyLogger, SpyEventBus, SpyCache

Same names as sync variants. All methods that perform I/O are async.

spy_adapter_container

spy_adapter_container(container: AdapterContainer) -> AdapterContainer

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

session_stub(session_cls: type[Session | AsyncSession]) -> type

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

port_stub(port_cls: type[Port]) -> type

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