Interface API¶
Historical execution context¶
See the dedicated Historical Context API reference for the generated signatures and the complete GraphQL directive contract.
Use general_manager.api.as_of(search_date) to make every supported read in an operation use one historical snapshot. The positional and explicit keyword forms are equivalent:
from general_manager.api import as_of, current_as_of_date
with as_of("2022-01-01") as search_date:
assert current_as_of_date() == search_date
with as_of(search_date="2022-01-01"):
project = Project(1)
projects = Project.filter(status="active")
search_date accepts an ISO date or datetime string (including a trailing Z), a datetime.date, or a naive or timezone-aware datetime.datetime. Date-only values become midnight in Django's current timezone. Naive datetimes also use Django's current timezone; aware datetimes retain their timezone. current_as_of_date() returns the active aware datetime, or None outside an as-of context. Nesting is idempotent when both values represent the same instant, even when their timezones differ. Distinct instants during a daylight-saving fold still conflict. A different nested date, or a different explicit date resolved while a context is active, raises HistoricalContextConflictError without changing the outer context. The previous value is restored when the context exits, including when its body raises an exception.
Invalid or unsupported inputs raise InvalidSearchDateError. An explicit search_date passed to a manager or query inside the context must represent the same instant; it cannot override the operation snapshot. Managers and buckets bound to current data or another date likewise raise HistoricalContextConflictError when consumed in the context.
The context is strictly read-only. GeneralManager and direct interface create, update, and delete entry points raise HistoricalMutationError before permission checks, transports, signals, or database writes. ORM-backed interfaces provide historical reads and calculation interfaces propagate the snapshot through their dependencies. Request-backed and custom interfaces are fail-closed unless they explicitly declare supported behavior: their reads raise HistoricalReadNotSupportedError before external loading begins.
Historical many-to-many membership requires django-simple-history through tables. Generated DatabaseInterface models and auto-registered existing models include local many-to-many fields in history registration, but the resulting Historical<Model>_<field> tables must be deployed through the normal Django migration workflow. Only membership changes recorded after those tables are deployed can be reconstructed; scalar history cannot recover pre-rollout membership. If membership or target history is unavailable, a dated relation read fails closed instead of returning current relation data. Generated relations that name a custom through model by an unresolved string cannot be registered when the owner model is created; their historical reads also fail closed. Define and history-track such models explicitly when custom through history is required.
general_manager.interface.base_interface.InterfaceBase ¶
Bases: ABC
Common base API for interfaces backing GeneralManager classes.
__init_subclass__ ¶
__init_subclass__(**kwargs)
Initialize capability-related class state for newly created subclasses.
This method resets per-subclass capability registries and configuration to a clean default, merges configured capability overrides into the class's capability_overrides mapping, and clears the flag that marks configured capabilities as applied. Keyword arguments are forwarded to the superclass implementation.
__init__ ¶
__init__(*args, **kwargs)
Initialize the interface using the provided identification inputs.
Positional arguments are mapped to the interface's declared input fields by position; keyword arguments are matched by name. Inputs are validated and normalized according to the interface's input field definitions and the resulting normalized identification is stored on the instance as self.identification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args | object | Positional identification values corresponding to the interface's input field order. | () |
**kwargs | object | Named identification values matching the interface's input field names. | {} |
set_capability_selection classmethod ¶
set_capability_selection(selection)
Attach a resolved capability selection to the interface and update its active capability names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
selection | CapabilitySelection | The resolved capability selection whose | required |
get_capabilities classmethod ¶
get_capabilities()
Get the capability names attached to this interface class.
Returns:
| Type | Description |
|---|---|
frozenset[CapabilityName] | frozenset[CapabilityName]: A frozenset of capability names registered on the interface class. |
get_capability_handler classmethod ¶
get_capability_handler(name)
Retrieve the capability instance associated with the given capability name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | CapabilityName | The capability identifier to look up. | required |
Returns:
| Type | Description |
|---|---|
'Capability | None' | Capability | None: The capability handler registered for |
iter_capability_configs classmethod ¶
iter_capability_configs()
Iterate configured capability entries declared on the interface.
Returns:
| Type | Description |
|---|---|
Iterable[InterfaceCapabilityConfig] | Iterable[InterfaceCapabilityConfig]: An iterable of capability configuration entries registered on the interface. |
require_capability classmethod ¶
require_capability(name, *, expected_type=None)
Retrieve the configured capability handler for the interface by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | CapabilityName | The capability identifier to look up. | required |
expected_type | type[Capability] | None | If provided, require the returned handler to be an instance of this type. | None |
Returns:
| Name | Type | Description |
|---|---|---|
Capability | 'Capability' | The capability handler instance corresponding to |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the interface has no capability configured under |
TypeError | If |
capability_selection classmethod ¶
capability_selection()
Return the resolved capability selection associated with this interface.
@returns CapabilitySelection if a selection has been set, None otherwise.
parse_input_fields_to_identification ¶
parse_input_fields_to_identification(*args, **kwargs)
Convert positional and keyword inputs into a validated identification mapping for the interface's input fields.
Positional values are assigned in input_fields declaration order before keyword validation. A keyword named <field>_id is accepted when <field> is a declared input; if both are supplied, the _id alias overwrites the canonical value. Positional overflow, duplicate positional-plus-keyword values, and unknown aliases surface as UnexpectedInputArgumentsError through the argument-normalization path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args | object | Positional arguments matched, in order, to the interface's defined input fields. | () |
**kwargs | object | Keyword arguments supplying input values by name. | {} |
Returns:
| Type | Description |
|---|---|
dict[str, object] | dict[str, object]: Mapping of input field names to their validated values. |
Raises:
| Type | Description |
|---|---|
UnexpectedInputArgumentsError | If extra keyword arguments are provided that do not match any input field (after allowing keys suffixed with "_id"). |
MissingInputArgumentsError | If one or more required input fields are not provided. |
CircularInputDependencyError | If input fields declare dependencies that form a cycle and cannot be resolved. |
InvalidInputTypeError | If a provided value does not match the declared type for an input. |
InvalidInputConstraintError | If bounds validation or the configured validator rejects a value. |
InvalidPossibleValuesTypeError | If an input's |
InvalidInputValueError | If a provided value is not in the allowed set defined by an input's |
format_identification staticmethod ¶
format_identification(identification)
Normalise identification data by replacing manager instances with their IDs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identification | dict[str, object] | Raw identification mapping possibly containing manager instances. | required |
Returns:
| Type | Description |
|---|---|
dict[str, object] | dict[str, object]: Identification mapping with nested managers replaced by their identifications. |
create classmethod ¶
create(*args, **kwargs)
Create a new managed record in the underlying data store using the interface's inputs.
This base method is intentionally typed to the capability-level mutation result, currently a dictionary such as {"id": pk}. Capability handlers used with InterfaceBase.create() should return that mapping shape; higher manager layers may convert it to a manager instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args | object | Positional input values corresponding to the interface's defined input fields. | () |
**kwargs | object | Input values provided by name; unexpected extra keywords will be rejected. | {} |
Returns:
| Type | Description |
|---|---|
dict[str, object] | The capability-level create result mapping. |
update ¶
update(*args, **kwargs)
Update the underlying managed record.
Positional and keyword arguments are forwarded unchanged to the configured update capability together with this interface instance. This base method does not combine payload values with identification and does not reject unexpected keywords itself; validation belongs to the update capability.
Returns:
| Type | Description |
|---|---|
object | The updated record or a manager-specific result. |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If this interface does not provide an update capability. |
delete ¶
delete(*args, **kwargs)
Delete the underlying record managed by this interface.
Delegates the deletion to the interface's configured delete capability and executes the operation with observability hooks. Positional and keyword arguments are forwarded unchanged together with this interface instance. This base method does not combine payload values with identification and does not reject unexpected keywords itself; validation belongs to the delete capability.
Returns:
| Type | Description |
|---|---|
object | The result of the delete operation as returned by the delete capability. |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the interface does not provide a delete capability. |
get_data ¶
get_data()
Get the materialized data for this manager.
Returns:
| Type | Description |
|---|---|
object | The materialized data for this manager (implementation-defined). |
Raises:
| Type | Description |
|---|---|
NotImplementedError | if reading is not supported for this manager. |
get_attribute_types classmethod ¶
get_attribute_types()
Retrieve metadata describing each attribute exposed by the manager.
This method delegates entirely to the read capability. It does not build fallback metadata from input_fields.
Returns:
| Type | Description |
|---|---|
dict[str, AttributeTypedDict] | dict[str, AttributeTypedDict]: Mapping from attribute name to its metadata (keys include |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the manager does not provide a read capability implementing |
get_attributes classmethod ¶
get_attributes()
Retrieve attribute values exposed by the interface.
This method delegates entirely to the read capability. It does not build fallback values from input_fields.
Returns:
| Type | Description |
|---|---|
dict[str, object] | dict[str, object]: Mapping of attribute names to their current values. |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the interface does not provide a read capability implementing |
get_graph_ql_properties classmethod ¶
get_graph_ql_properties()
Collect GraphQLProperty descriptors declared on the interface's parent manager class.
Returns:
| Type | Description |
|---|---|
dict[str, GraphQLProperty] | dict[str, GraphQLProperty]: Mapping from attribute name to the corresponding GraphQLProperty instance found on the parent manager class. Returns an empty dict if no parent class is set or none of its attributes are GraphQLProperty instances. |
filter classmethod ¶
filter(**kwargs)
Filter records through the query capability and return its Bucket of matches.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Lookup expressions mapping field lookups (e.g., "name__icontains") to values. | {} |
Returns:
| Type | Description |
|---|---|
'Bucket[GeneralManager]' | Bucket[GeneralManager]: Bucket returned by the query capability, containing records that match the lookup expressions. |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the interface's query capability does not implement filtering. |
exclude classmethod ¶
exclude(**kwargs)
Exclude records through the query capability and return its Bucket of matches.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Lookup expressions accepted by the query capability (e.g., field=value, field__lookup=value). | {} |
Returns:
| Type | Description |
|---|---|
'Bucket[GeneralManager]' | Bucket[GeneralManager]: Bucket returned by the query capability, containing records that do not match the provided lookup expressions. |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the interface's query capability does not implement an |
all classmethod ¶
all()
Retrieve all records through the query capability and return its Bucket.
Returns:
| Type | Description |
|---|---|
'Bucket[GeneralManager]' | Bucket[GeneralManager]: Bucket returned by the query capability, containing every record accessible via this interface. |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the configured query capability does not implement |
handle_interface classmethod ¶
handle_interface()
Provide pre- and post-creation hooks for GeneralManager class construction derived from the interface's lifecycle capability.
Returns:
| Type | Description |
|---|---|
tuple[classPreCreationMethod, classPostCreationMethod] | tuple[classPreCreationMethod, classPostCreationMethod]: - pre-create callable accepting (name, attrs, interface, base_model_class=None) and returning (attrs, interface_class, related_class). - post-create callable accepting (new_class, interface_class, model) and returning None. |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If no lifecycle capability is declared, or if the configured lifecycle capability does not provide callable |
Exception | Exceptions from lifecycle hooks propagate unchanged. Malformed hook return values are not validated here and fail in the caller that consumes the lifecycle tuple. |
get_field_type classmethod ¶
get_field_type(field_name)
Resolve the declared Python type for the named input field.
If a read capability implements get_field_type(), that capability owns the result. Otherwise this method falls back only to declared input_fields.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field_name | str | Name of the input field to look up. | required |
Returns:
| Name | Type | Description |
|---|---|---|
type | type | The Python type declared for the specified field. |
Raises:
| Type | Description |
|---|---|
KeyError | If no input field with the given name is defined. |
InterfaceBase is the capability-driven base for custom interfaces. Subclasses declare input_fields as a mapping of names to Input[...] objects. Positional constructor arguments are mapped to input fields by declaration order, keyword arguments are matched by name, and <name>_id aliases are accepted for declared inputs when the canonical <name> was not already supplied. Positional overflow, duplicate positional-plus-keyword values, alias collisions, and unknown keyword or alias names raise UnexpectedInputArgumentsError. Required inputs that are missing raise MissingInputArgumentsError; circular input dependencies raise CircularInputDependencyError; invalid input types raise InvalidInputTypeError; failed bounds or validators raise InvalidInputConstraintError; invalid possible-values containers raise InvalidPossibleValuesTypeError; and failed possible-value membership raises InvalidInputValueError when possible-value validation is enabled. Possible-value membership is controlled by VALIDATE_INPUT_VALUES; if that setting is unset, membership validation follows settings.DEBUG.
create(), update(), delete(), get_data(), filter(), exclude(), and all() delegate to configured capability handlers. Base create() is typed to the capability-level result mapping, while update(), delete(), and get_data() preserve arbitrary capability results. Query capabilities must return Bucket instances from filter(), exclude(), and all(); manager classes preserve or narrow those bucket types. Missing capabilities raise NotImplementedError. get_attribute_types() and get_attributes() require a read capability and do not synthesize fallbacks from input_fields; get_field_type() delegates to the read capability when present and otherwise falls back only to declared inputs. The base observability executor calls before_operation, then the delegated operation, then after_operation; if before_operation raises the delegated operation is not called, and observer hook exceptions propagate. handle_interface() delegates class creation to the configured lifecycle capability's pre_create and post_create callables, passing only keyword arguments accepted by each callable's signature. Missing lifecycle hooks raise NotImplementedError; lifecycle exceptions and malformed lifecycle return values are not wrapped by InterfaceBase.
general_manager.interface.orm_interface.OrmInterfaceBase ¶
Bases: InterfaceBase, Generic[HistoryModelT]
Common initialization and metadata for ORM-backed interfaces.
Subclasses provide ORM lifecycle capabilities and a Django model type. The base interface defines one required public input field, id, which is cast through Input(int) before becoming identification["id"]. During construction, the interface stores that value as pk, normalizes an optional historical search_date, and loads the current or historical ORM row into the internal _instance attribute through the configured lifecycle capability. Subclasses that override :attr:input_fields must keep an "id" field unless they also override initialization and row loading.
historical_lookup_buffer_seconds is consumed by ORM query support: a search_date must be at least this many seconds before timezone.now() before history tables are queried instead of the current row.
__init__ ¶
__init__(*args, search_date=None, **kwargs)
Initialize the ORM-backed interface for a primary key.
Positional and keyword inputs are parsed by :class:InterfaceBase using :attr:input_fields. The default shape accepts one id value. Naive search_date values are made timezone-aware with Django's current timezone before the row is loaded into the internal _instance cache. Subclasses overriding :attr:input_fields must preserve "id" unless they also replace this initializer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args | object | Raw input values consumed by | () |
search_date | SearchDateInput | None | Optional point-in-time lookup date. | None |
**kwargs | object | Raw named input values consumed by | {} |
Raises:
| Type | Description |
|---|---|
KeyError | If parsed identification does not contain |
DoesNotExist | Propagated from |
TypeError | Propagated from runtime values outside the typed |
Exception | Propagates history capability and Django ORM lookup errors raised by |
normalize_search_date staticmethod ¶
normalize_search_date(search_date)
Return search_date as a timezone-aware datetime.
Naive values are converted with Django's current timezone. Aware values and None are returned unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
search_date | SearchDateInput | None | Datetime to normalize, or | required |
Returns:
| Type | Description |
|---|---|
datetime | None | The timezone-aware datetime, existing aware datetime, or |
handle_custom_fields classmethod ¶
handle_custom_fields(model)
Return custom field names and generated ignore markers for model.
The result is delegated to the configured orm_lifecycle capability. The first list contains discovered custom field names. The second list contains generated ignore markers such as "<field>_value" and "<field>_unit".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model | type[Model] | Model | Model class or model instance to inspect. | required |
Returns:
| Type | Description |
|---|---|
tuple[list[str], list[str]] |
|
Raises:
| Type | Description |
|---|---|
CapabilityNotAvailableError | If the ORM lifecycle capability is not configured. |
TypeError | If the configured capability is not an |
OrmInterfaceBase is the public base for Django ORM-backed interfaces. It inherits InterfaceBase, declares the default input_fields as {"id": Input(int)}, and loads a current or historical ORM row for that primary key into the internal _instance attribute during construction. Pass search_date=... to resolve a point-in-time row; naive datetimes are made timezone-aware with Django's current timezone before lookup. The historical_lookup_buffer_seconds class attribute controls how far in the past a search_date must be before ORM support reads from history tables instead of the current row.
Subclasses normally use DatabaseInterface, ExistingModelInterface, or ReadOnlyInterface rather than subclassing this base directly, but custom ORM interface types can reuse it when they provide the required lifecycle capability configuration. If a custom ORM interface overrides input_fields, preserve "id" unless you also replace initialization and row loading. The underscored helpers such as _from_trusted_orm_instance() and _default_base_model_class() are internal extension hooks for bucket hydration and class creation. Underscored helpers in ORM capability modules follow the same rule even if generated API pages render them; application code should prefer the documented manager, interface, and bucket methods.
handle_custom_fields(model) delegates to the configured ORM lifecycle capability and returns (field_names, ignore_markers), where ignore markers are the generated <field>_value and <field>_unit names. Missing or invalid lifecycle capabilities propagate the capability lookup/type errors.
general_manager.interface.interfaces.database.DatabaseInterface ¶
Bases: OrmInterfaceBase[GeneralManagerModel]
CRUD-capable interface backed by a generated GeneralManager Django model.
Manager subclasses declare Django model fields on this interface. The ORM lifecycle capability turns those declarations into a concrete model and the configured writable ORM capabilities provide query, create, update, delete, history, validation, and observability behavior.
Construction uses OrmInterfaceBase inputs: the default public input is id, and search_date performs inherited point-in-time row lookup. Missing live or historical rows propagate the generated Django model's DoesNotExist exception. Write payload normalization can raise UnknownFieldError for unknown fields, InvalidFieldValueError when assignment raises ValueError, and InvalidFieldTypeError when assignment raises TypeError.
general_manager.interface.interfaces.existing_model.ExistingModelInterface ¶
Bases: OrmInterfaceBase[ExistingModelT]
Writable ORM interface backed by a pre-existing Django model.
Subclasses declare model as either a Django model class or an app-label string accepted by django.apps.apps.get_model(), such as settings.AUTH_USER_MODEL. During manager class creation the existing_model_resolution lifecycle capability resolves that reference, caches the resolved model on the concrete interface, auto-registers database-aware history when needed, applies interface rules, and builds a factory for the legacy model. Auto-registration includes local many-to-many fields. A pre-registered tracker remains compatible on the default database; on a configured non-default alias, its generated history model must carry GeneralManager's database-aware marker or manager creation raises UnsafeHistoryConfigurationError. Interface rules are the optional Meta.rules sequence on the interface. Soft delete is enabled when the resolved model exposes an is_active attribute.
Construction and row loading are inherited from OrmInterfaceBase: the default public input is the wrapped row id parsed by Input(int) plus optional search_date: datetime | None. Naive search dates are made aware with Django's current timezone, and historical lookups follow OrmInterfaceBase.historical_lookup_buffer_seconds. Missing rows propagate the wrapped model's DoesNotExist exception. Invalid or missing model declarations raise the existing-model configuration errors from the resolution capability. Creation, update, delete, query, history, and factory APIs are inherited from the configured writable ORM capabilities and the owning GeneralManager class; this shell class only selects the existing-model lifecycle.
get_field_type classmethod ¶
get_field_type(field_name)
Retrieve the effective type for a wrapped model attribute.
The method first ensures the legacy model has been resolved and cached on this interface class, then delegates to the inherited read-capability lookup. Resolution is class-local: subclasses that declare their own model do not reuse a parent interface's cached _model value. Stored Django fields return the Django field class. Managed relations are relation fields whose related model exposes _general_manager_class; those return that manager class. Generated descriptors are entries in ORM support's descriptor map, including custom fields and generated relation helpers; those return their descriptor metadata "type" value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field_name | str | Name of the field or manager attribute to inspect. | required |
Returns:
| Type | Description |
|---|---|
type[object] | The effective field, manager, or descriptor type exposed for |
type[object] |
|
Raises:
| Type | Description |
|---|---|
MissingModelConfigurationError | If no |
InvalidModelReferenceError | If |
FieldDoesNotExist | If neither the wrapped model nor generated descriptors can describe the field. |
CapabilityNotAvailableError | If required capabilities are absent. |
TypeError | If the configured resolution capability is not an |
ExistingModelInterface is the writable ORM interface for wrapping a Django model that already exists outside GeneralManager. Direct subclasses set model to a Django model class or to an app-label string accepted by Django's app registry, such as settings.AUTH_USER_MODEL or "app_label.ModelName". The existing_model_resolution lifecycle capability resolves that reference during manager class creation, stores the resolved class on the concrete interface as _model and model, registers database-aware simple-history when needed, applies interface rules, and builds a factory for the existing table. Missing model declarations raise MissingModelConfigurationError; invalid strings, non-model classes, and other invalid references raise InvalidModelReferenceError. Auto-registration includes local many-to-many fields and routes base and relation history to the live row's database alias. A pre-existing tracker is accepted on the default alias. On a configured non-default alias its history model must carry GeneralManager's database-aware marker or manager creation raises UnsafeHistoryConfigurationError. Soft delete is enabled when the resolved model exposes an is_active attribute. The simple-history marker is model._meta.simple_history_manager_attribute; interface rules are the optional Meta.rules sequence on the interface. This shell class does not declare separate create/update/delete signatures. Those public operations are the inherited GeneralManager and writable ORM capability APIs documented in the core manager and existing-model guides; ExistingModelInterface selects the existing-model lifecycle for them.
Construction inherits the ORM input contract: pass the wrapped row id, parsed through the default Input(int), and optional search_date: datetime | None. Naive search dates are made aware with Django's current timezone, and history lookup uses historical_lookup_buffer_seconds from OrmInterfaceBase. Missing current or historical rows propagate the wrapped model's DoesNotExist exception. get_field_type(field_name) first lazily resolves this interface's own model, then delegates to ORM read support. Stored model fields return the Django field class, managed relations return the related model's _general_manager_class when present, and generated relation/custom descriptors return their metadata type; fields absent from both the model and descriptor map raise Django's FieldDoesNotExist. A managed relation means a Django relation whose related model has _general_manager_class; generated descriptors are ORM support descriptor-map entries for custom fields and generated relation helpers. The lazy cache is class-local, so a subclass that declares a different model resolves that declaration instead of reusing a parent interface's cached _model.
general_manager.interface.interfaces.read_only.ReadOnlyInterface ¶
Bases: OrmInterfaceBase[GeneralManagerBasisModel]
Capability shell for read-only datasets mirrored into generated models.
Subclasses are declared as a manager's nested Interface and define the Django fields for a generated model. The parent manager, not this class, provides the _data payload as either a JSON string or a list of row dictionaries. The configured read-only lifecycle forces Meta.use_soft_delete = True, generates a model based on GeneralManagerBasisModel, and registers the created manager for startup schema checks and synchronization.
Construction and row loading are inherited from OrmInterfaceBase: the public input is the mirrored row id parsed by Input(int) plus optional search_date: datetime | None. Missing current or historical rows propagate the generated model's DoesNotExist exception. Read, query, history, validation, soft-delete, schema-check, and synchronization behavior comes from READ_ONLY_CAPABILITIES; this shell class does not define separate public mutation methods.
Read-only synchronization can raise the dedicated read-only configuration errors from the management capability when the parent manager is not bound, _data is missing or malformed, no unique row identity can be found, or relation lookups do not resolve exactly one row. Lifecycle and ORM errors propagate unchanged from the capability that raises them. The public manager surface inherited from GeneralManager is construction by id, attribute reads, all(), filter(), exclude(), and history access. Those successful reads and queries return manager instances or buckets of manager instances backed by generated model rows; history access returns the generated model's history queryset. Because no create, update, or delete capability is configured, inherited mutation entry points are not read-only data APIs.
Underscored attributes such as _interface_type and _parent_class are framework wiring, not application configuration. The parent manager's _data payload is the public read-only data source despite its legacy underscore name. Duplicate composite identities in _data are not rejected by the shell; the management capability falls back to full synchronization and processes rows in order for the same identity. Relation lookup dictionaries are flattened into Django __ lookups; zero or multiple matches raise ReadOnlyRelationLookupError, while malformed lookup keys or values propagate the Django query error. For many-to-many payloads, an omitted key leaves the relation unchanged, a present None clears it, and a present list replaces it.
ReadOnlyInterface is the capability shell for static or generated datasets mirrored into a generated Django model. Subclasses normally appear as a manager's nested Interface and declare Django model fields; the parent manager provides _data as either a JSON string or a list of row dictionaries. The read-only lifecycle forces Meta.use_soft_delete = True, generates the model with GeneralManagerBasisModel, and registers the created manager in the read-only startup registry so schema checks and data sync can run during startup.
Construction inherits the ORM input contract: pass the mirrored row id, parsed through default Input(int), and optional search_date: datetime | None. Missing current or historical rows propagate the generated model's DoesNotExist exception. The class itself does not define separate public mutation methods; read/query/history/validation, soft-delete, schema-check, and sync behavior come from READ_ONLY_CAPABILITIES and the owning GeneralManager API. Sync errors such as MissingReadOnlyBindingError, MissingReadOnlyDataError, InvalidReadOnlyDataTypeError, InvalidReadOnlyDataFormatError, MissingUniqueFieldError, and ReadOnlyRelationLookupError are raised by the read-only management capability when the parent/model binding, _data payload, unique row identity, or relation lookups are invalid. The successful public manager surface is construction by id, attribute reads, all(), filter(), exclude(), and history access. These return manager instances, buckets of manager instances, or the generated model's history queryset. READ_ONLY_CAPABILITIES intentionally omits create, update, and delete capabilities, so inherited mutation entry points are not read-only data APIs. _interface_type, _parent_class, and configured_capabilities are framework wiring; the parent manager's _data attribute is the public dataset source despite its legacy underscore name. Duplicate composite identities in _data are not rejected during full synchronization; rows for the same identity are processed in order, so later payload values can overwrite earlier values for that row. Relation lookup dictionaries are flattened into Django __ lookups; zero or multiple matches raise ReadOnlyRelationLookupError, while malformed lookup keys or values propagate the Django query error. For many-to-many fields, an omitted key leaves the relation unchanged, a present None clears it, and a present list replaces it.
general_manager.interface.interfaces.calculation.CalculationInterface ¶
Bases: InterfaceBase
Interface shell for derived managers that expose typed inputs but no storage.
Subclasses normally declare input descriptors as class attributes (project = Input(Project)). During manager-class creation the calculation lifecycle capability scans the concrete interface class's own attributes, skips dunder names, collects values that are Input instances into a fresh input_fields dictionary, and assigns that dictionary to the generated interface subclass. Inherited descriptors and any manually assigned input_fields mapping are not merged by that lifecycle step. The generated interface receives a _parent_class backlink to the manager during post-create.
Resolved values are cached per interface instance in _resolved_input_values. The cache stores the cast result of each input, including manager wrappers for manager-typed inputs, and lives for the lifetime of that interface instance. Manager-typed inputs cache the resolved GeneralManager wrapper object returned by Input.cast(). There is no cross-instance, async, or thread-level invalidation contract for this cache. Query methods all(), filter(), and exclude() are provided by the configured calculation query capability and return CalculationBucket instances. The public get_data() method is backed by the calculation read capability and raises NotImplementedError("Calculations do not store data."). Managers still inherit create(), update(), and delete() from GeneralManager, but calculation interfaces configure no create, update, or delete capability, so those inherited mutation paths are unsupported and fail when they require the missing capability.
general_manager.interface.interfaces.request.RequestInterface ¶
Bases: InterfaceBase
Base interface for request-backed resources with declarative operations.
Subclasses declare RequestField attributes on the interface and request filters, query operations, mutation operations, transports, auth providers, retry policies, serializers, and rules on Meta. Request fields are collected across the subclass MRO so derived interfaces can inherit or override field declarations. Legacy top-level request configuration raises RequestConfigurationError during subclass creation. Declared mutation operations automatically add the corresponding request mutation capabilities.
At subclass creation, Meta.filters, Meta.query_operations, Meta.default_query_operation, Meta.transport, Meta.transport_config, Meta.auth_provider, Meta.retry_policy, Meta.create_operation, Meta.update_operation, Meta.delete_operation, Meta.create_serializer, Meta.update_serializer, Meta.response_serializer, and Meta.rules are copied onto same-named interface class attributes. Omitted values use the class defaults declared below.
Request queries return lazy request buckets through the configured query capability. Instance field reads resolve values from the cached response payload and raise MissingRequestPayloadFieldError when a required declared field is absent.
get_query_operation classmethod ¶
get_query_operation(operation_name=None)
Return a named query operation, falling back to interface-level filters.
None and empty names resolve to default_query_operation. When that default operation is not explicitly declared, this method returns a synthetic operation with path="" and the interface-level filters. Declared operations whose own filters value is None inherit interface-level filters; declared operations with a filter mapping keep that operation-specific mapping.
Raises:
| Type | Description |
|---|---|
UnknownRequestOperationError | If a non-default operation name is not declared. |
query_operation classmethod ¶
query_operation(operation_name, **kwargs)
Build a bucket for a named collection operation declared on the interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
operation_name | str | Name of a configured | required |
**kwargs | object | Lookup values compiled by the request query capability. | {} |
Returns:
| Type | Description |
|---|---|
Bucket[GeneralManager] | A lazy request bucket for the interface's parent manager. |
Raises:
| Type | Description |
|---|---|
UnknownRequestOperationError | If the named operation is not declared. |
NotImplementedError | If the configured query capability does not implement named request operations. |
RequestConfigurationError | If request planning fails for the operation, filters, or transport setup. |
Exception | Request planning errors from the active query capability, including unknown filters, invalid filter values, unsupported excludes, invalid request-fragment locations, and conflicting fragment keys, propagate unchanged. |
set_request_payload_cache ¶
set_request_payload_cache(payload)
Cache the raw response payload used to populate request-backed fields.
Passing None clears the cache. The method does not validate payload shape; individual field reads perform path resolution and required-field checks.
get_mutation_operation classmethod ¶
get_mutation_operation(action)
Return the configured mutation operation for an action.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action | str | One of | required |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If the interface does not declare that mutation operation. |
extract_identification classmethod ¶
extract_identification(payload)
Extract manager identification values from a query payload.
Returns values for every field named in identification_fields, resolving declared request-field source paths where present.
Raises:
| Type | Description |
|---|---|
MissingRequestPayloadFieldError | If a required identification value is absent from the payload. |
resolve_payload_value classmethod ¶
resolve_payload_value(payload, field_name)
Resolve a declared request field from a payload mapping.
Undeclared fields are resolved by their own name. Declared fields use the RequestField source path, return the field default when optional data is missing, and apply the field normalizer when one is configured.
Raises:
| Type | Description |
|---|---|
MissingRequestPayloadFieldError | If a required value is missing. |
execute_request_plan classmethod ¶
execute_request_plan(plan)
Execute a compiled request plan and return normalized payload items.
The configured transport may return either a RequestQueryResult or a decoded request response accepted by default_request_response_normalizer. A callable response_serializer is applied to each normalized item and must return mapping-shaped payloads. Plans with create, update, or delete actions use the corresponding mutation operation; every other action string, including unknown or empty actions, uses the plan's operation_name to resolve a query operation. The plan's path_params are forwarded to the transport as request identification. Auth, retry, metrics, trace, and transport behavior is owned by the configured transport object; errors from those hooks propagate according to that transport implementation.
Raises:
| Type | Description |
|---|---|
MissingRequestTransportError | If no transport is configured. |
RequestSchemaError | If the response serializer returns non-mapping items or the default normalizer rejects the transport payload. |
NotImplementedError | If a create, update, or delete plan targets an undeclared mutation operation. |
UnknownRequestOperationError | If a non-mutation plan targets an undeclared query operation. |
general_manager.interface.interfaces.remote_manager.RemoteManagerInterface ¶
Bases: RequestInterface
Request-backed interface for a remote GeneralManager REST resource.
Direct subclasses read Meta.base_url, optional Meta.base_path, Meta.remote_manager, optional Meta.protocol_version, and optional Meta.websocket_invalidation_enabled when the class is defined. The interface validates that metadata, defaults base_path to /gm when it is omitted, defaults protocol_version to "v1", coerces websocket_invalidation_enabled with bool(...), normalizes base_path, installs the generated GET <base_path>/<remote_manager>/{id} detail query, POST <base_path>/<remote_manager>/query list query, and create/update/delete mutation operations, and configures response normalization for the remote-manager envelope. Generated operations include the X-General-Manager-Protocol-Version header. If a subclass already defines transport_config, its timeout, auth provider, retry policy, metrics backend, and trace backend are preserved while the validated Meta.base_url and response normalizer replace the transport's values.
Configuration errors are raised during direct subclass creation by validate_remote_manager_meta(...). Indirect subclasses are not reconfigured by this class hook. Query execution can additionally raise request operation, schema, transport, serializer, or validator errors from the underlying request interface.
get_websocket_invalidation_url classmethod ¶
get_websocket_invalidation_url()
Return the websocket URL used for remote cache invalidation.
The URL is derived from base_url and the normalized base_path. Class creation validates base_url as http or https before this helper is available on a configured interface. https base URLs become wss and valid http base URLs become ws. A path prefix already present on base_url is stripped of trailing slashes and preserved before <base_path>/ws/<remote_manager>. Query and fragment components from base_url are not preserved; the protocol version is emitted as the version query parameter. This helper does not check websocket_invalidation_enabled by itself.
Returns:
| Type | Description |
|---|---|
str | Absolute websocket URL for this interface's invalidation stream. |
handle_invalidation_event classmethod ¶
handle_invalidation_event(event)
Invalidate cached remote queries when a websocket event matches.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event | Mapping[str, object] | Decoded websocket payload. Only | required |
Returns:
| Type | Description |
|---|---|
bool |
|
bool | requested for the parent manager; |
Raises:
| Type | Description |
|---|---|
AttributeError | If called before the interface is bound to a parent manager class. |
Exception | Propagates cache invalidation backend errors. |
RemoteManagerInterface is the generated-client interface for another GeneralManager service's RemoteAPI exposure. Direct subclasses read Meta.base_url, optional Meta.base_path, Meta.remote_manager, optional Meta.protocol_version, and optional Meta.websocket_invalidation_enabled at class creation time. Omitted Meta.base_path defaults to /gm, omitted Meta.protocol_version defaults to "v1", and Meta.websocket_invalidation_enabled is coerced with bool(...). Only direct subclasses are configured by this class hook; indirect subclasses inherit the already configured values unless they inherit directly from RemoteManagerInterface. The interface validates those values, creates standard detail/list/create/update/delete request operations, installs the protocol version header, and configures response normalization for RemoteAPI envelopes. If a subclass already declares transport_config, timeout, auth, retry, metrics, and trace settings are preserved while the base URL and response normalizer are replaced with the validated remote-manager settings.
get_websocket_invalidation_url() returns the websocket invalidation URL for the interface. Class creation validates base_url as HTTP(S). https base URLs become wss; http base URLs become ws; a path prefix in base_url is stripped of trailing slashes and preserved before <base_path>/ws/<remote_manager>; and protocol_version is emitted as the version query parameter. Query and fragment components from base_url are not preserved. The helper itself does not check websocket_invalidation_enabled; RemoteInvalidationClient performs that enabled check before opening connections. handle_invalidation_event(event) compares only protocol_version, base_path, and resource_name; matching events invalidate local remote-query caches for the parent manager and return True, while non-matching events return False. Cache invalidation errors propagate, and calling it before the interface is bound to a parent manager can raise AttributeError.
Capabilities¶
general_manager.interface.capabilities.base.CapabilityName module-attribute ¶
CapabilityName = Literal[
"read",
"create",
"update",
"delete",
"history",
"validation",
"query",
"orm_support",
"orm_mutation",
"orm_lifecycle",
"calculation_lifecycle",
"notification",
"scheduling",
"access_control",
"observability",
"existing_model_resolution",
"request_lifecycle",
"read_only_management",
"soft_delete",
]
Supported capability identifiers used by interface capability registries.
Capability names are stable string keys. Interfaces store active names in InterfaceBase._capabilities, map them to handler instances in InterfaceBase._capability_handlers, and may use them as override keys in capability_overrides.
general_manager.interface.capabilities.base.Capability ¶
Bases: Protocol
Runtime-checkable protocol implemented by interface capability handlers.
A capability advertises one stable name and can attach or detach behavior from an interface class. Implementations mutate the supplied class in place and return None. Exceptions from concrete implementations propagate; this protocol does not define a normalization layer or idempotency guarantee.
setup ¶
setup(interface_cls)
Attach this capability to the given interface class.
Implementations should modify or extend the provided interface class so that it exposes or enables the capability's behavior, for example by registering methods, attributes, or lifecycle hooks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | Interface class to mutate. | required |
Returns:
| Type | Description |
|---|---|
None |
|
Raises:
| Type | Description |
|---|---|
Exception | Concrete capability implementations define their own validation and setup errors, which propagate unchanged. |
teardown ¶
teardown(interface_cls)
Detach this capability from the given interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | Interface class to mutate. | required |
Returns:
| Type | Description |
|---|---|
None |
|
Raises:
| Type | Description |
|---|---|
Exception | Concrete capability implementations define their own teardown errors, which propagate unchanged. |
general_manager.interface.capabilities.builtin.BaseCapability dataclass ¶
Bases: Capability
Base implementation for capability validation and handler registration.
Subclasses publish a stable capability name and may list class attributes or methods required on the interface class in required_attributes. The dataclass has no instance fields or generated constructor parameters of its own. setup() validates those requirements, converts the interface class's current _capability_handlers mapping to a plain dict or starts from an empty plain dict when that attribute is absent, registers this capability instance under name, and writes the copied mapping back to the class. teardown() performs the inverse copy-and-remove operation with the same plain-dict conversion and also starts from an empty mapping when no registry exists yet.
The base implementation does not call the required attributes and does not validate their signatures; it only checks hasattr(interface_cls, attr). Repeated setup replaces the handler for the same name, and repeated teardown is a no-op once the handler is absent. Missing attributes raise :class:CapabilityBindingError; other attribute access or mapping-copy failures propagate unchanged.
setup ¶
setup(interface_cls)
Validate and register this capability on an interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | The interface class to mutate. | required |
Returns:
| Type | Description |
|---|---|
None | None. The supplied class is mutated in place. |
Raises:
| Type | Description |
|---|---|
CapabilityBindingError | If one or more names in |
Exception | Exceptions raised by |
teardown ¶
teardown(interface_cls)
Remove this capability from an interface class registry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | The interface class to mutate. | required |
Returns:
| Type | Description |
|---|---|
None | None. The supplied class is mutated in place. |
Raises:
| Type | Description |
|---|---|
Exception | Exceptions raised while reading, converting with |
general_manager.interface.capabilities.builtin.ReadCapability dataclass ¶
general_manager.interface.capabilities.builtin.CreateCapability dataclass ¶
general_manager.interface.capabilities.builtin.UpdateCapability dataclass ¶
general_manager.interface.capabilities.builtin.DeleteCapability dataclass ¶
general_manager.interface.capabilities.builtin.HistoryCapability dataclass ¶
general_manager.interface.capabilities.builtin.ValidationCapability dataclass ¶
general_manager.interface.capabilities.builtin.NotificationCapability dataclass ¶
general_manager.interface.capabilities.builtin.SchedulingCapability dataclass ¶
general_manager.interface.capabilities.builtin.AccessControlCapability dataclass ¶
general_manager.interface.capabilities.builtin.ObservabilityCapability dataclass ¶
general_manager.interface.capabilities.exceptions.CapabilityBindingError ¶
Bases: RuntimeError
Raised when a capability cannot be attached to an interface class.
The error keeps the original capability name and failure reason as public attributes and formats str(error) as "Capability '<name>' could not be attached: <reason>". Empty reasons are preserved, including the trailing separator in the formatted message.
__init__ ¶
__init__(capability_name, reason)
Initialize the error with failed binding details.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
capability_name | str | Name of the capability that could not be attached. | required |
reason | str | Explanation of why the attachment failed. The value is stored unchanged and may be an empty or multiline string. | required |
Raises:
| Type | Description |
|---|---|
Exception | Exceptions raised while formatting the message from non-string runtime values propagate if callers bypass static typing. |
general_manager.interface.capabilities.configuration.InterfaceCapabilityConfig dataclass ¶
Declarative entry describing one capability handler construction.
handler is the capability class to instantiate. options=None means no keyword arguments are supplied; a mapping value is converted to a plain dict immediately before construction and expanded as keyword arguments. The config object is immutable, but the original mapping is not copied until :meth:instantiate is called.
instantiate ¶
instantiate()
Instantiate the configured capability handler.
Returns:
| Type | Description |
|---|---|
Capability | Capability instance produced by calling |
Capability | calls the handler with no keyword arguments; any supplied mapping, |
Capability | including an empty or otherwise falsey mapping, is copied into a |
Capability | mutable |
Raises:
| Type | Description |
|---|---|
TypeError | If |
general_manager.interface.capabilities.configuration.CapabilitySet dataclass ¶
Named immutable bundle of concrete capability configuration entries.
The constructor accepts any iterable of :class:InterfaceCapabilityConfig entries and stores it as a tuple. Entries are not copied deeply and are not validated beyond normal iteration; invalid values supplied at runtime remain invalid values in the tuple.
__init__ ¶
__init__(label, entries)
Store bundle entries as an immutable tuple.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label | str | Human-readable bundle label used for documentation and debugging. | required |
entries | Iterable[InterfaceCapabilityConfig] | Iterable of concrete capability configuration entries. | required |
Raises:
| Type | Description |
|---|---|
TypeError | If |
general_manager.interface.capabilities.configuration.flatten_capability_entries ¶
flatten_capability_entries(entries)
Expand capability bundles into a flat immutable tuple.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries | Sequence[CapabilityConfigEntry] | Iterable[CapabilityConfigEntry] | Iterable of | required |
Returns:
| Type | Description |
|---|---|
InterfaceCapabilityConfig | Tuple of concrete capability configurations in input order. Entries are |
... | not deduplicated or validated; repeated capability handlers remain |
tuple[InterfaceCapabilityConfig, ...] | repeated entries. Invalid non- |
tuple[InterfaceCapabilityConfig, ...] | appended unchanged if callers bypass static typing. |
Raises:
| Type | Description |
|---|---|
TypeError | If |
Exception | Exceptions raised while iterating |
general_manager.interface.capabilities.configuration.iter_capability_entries ¶
iter_capability_entries(entries)
Yield concrete capability configurations in order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries | Sequence[CapabilityConfigEntry] | Iterable[CapabilityConfigEntry] | Iterable of | required |
Returns:
| Type | Description |
|---|---|
Iterator[InterfaceCapabilityConfig] | Iterator over concrete capability configuration entries. Entries are not |
Iterator[InterfaceCapabilityConfig] | deduplicated or validated. Invalid non- |
Iterator[InterfaceCapabilityConfig] | are yielded unchanged if callers bypass static typing. |
Raises:
| Type | Description |
|---|---|
TypeError | If |
Exception | Exceptions raised while iterating |
general_manager.interface.capabilities.factory.CAPABILITY_CLASS_MAP module-attribute ¶
CAPABILITY_CLASS_MAP = {
"read": ReadCapability,
"create": CreateCapability,
"update": UpdateCapability,
"delete": DeleteCapability,
"history": HistoryCapability,
"validation": ValidationCapability,
"notification": NotificationCapability,
"scheduling": SchedulingCapability,
"access_control": AccessControlCapability,
"observability": ObservabilityCapability,
}
Default capability handler classes keyed by public capability name.
general_manager.interface.capabilities.factory.CapabilityOverride module-attribute ¶
CapabilityOverride = (
Callable[[], Capability] | type[Capability]
)
Per-name override accepted by :func:build_capabilities.
general_manager.interface.capabilities.factory.build_capabilities ¶
build_capabilities(interface_cls, names, overrides)
Instantiate capability handlers for the supplied names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[object] | Interface class the capabilities will be associated with. This compatibility context is accepted for callers that already have an interface class available; the current implementation does not inspect or pass it to handlers. | required |
names | Iterable[CapabilityName] | Capability names to instantiate. The iterable is consumed once and order is preserved. Duplicate names create duplicate handler instances or call the override once per occurrence. | required |
overrides | Mapping[CapabilityName, CapabilityOverride] | Per-name overrides. When a name exists in this mapping and the value is not | required |
Returns:
| Type | Description |
|---|---|
list[Capability] | A mutable list of capability instances in the same order as |
Raises:
| Type | Description |
|---|---|
KeyError | If a requested name has no non- |
Exception | Exceptions raised while iterating |
general_manager.interface.capabilities.registry.CapabilityRegistry ¶
In-memory registry mapping interface classes to capability declarations.
The registry stores declared capability names separately from concrete capability instances. It is process-local, has no locking, does not validate runtime values beyond normal iterable consumption, and returns defensive immutable views from read methods.
__init__ ¶
__init__()
Initialize empty declaration and instance registries.
_bindings maps interface classes to mutable internal sets of declared capability names. _instances maps interface classes to immutable tuples of concrete capability objects.
register ¶
register(interface_cls, capabilities, *, replace=False)
Record declared capability names for an interface class.
The incoming iterable is consumed exactly once into a temporary set before internal state is changed. Duplicate names collapse. With replace=False the new names are merged into the existing binding; with replace=True the existing binding is replaced, including by an empty iterable. Runtime values are trusted if callers bypass static typing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | Interface receiving the capabilities. | required |
capabilities | Iterable[CapabilityName] | Iterable of capability names to register. Iteration order is not preserved because declaration reads return sets. | required |
replace | bool | Overwrite existing entries instead of merging when true. | False |
Raises:
| Type | Description |
|---|---|
Exception | Exceptions raised while iterating |
get ¶
get(interface_cls)
Retrieve the capability names registered for the given interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | Interface class to look up. | required |
Returns:
| Type | Description |
|---|---|
frozenset[CapabilityName] | A new |
frozenset[CapabilityName] |
|
bind_instances ¶
bind_instances(interface_cls, capabilities)
Record concrete capability instances for the given interface class.
The iterable is consumed once into a tuple before assignment. Instance bindings are independent of declared-name bindings: storing instances does not call register(), and replacing declared names does not remove stored instances.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | Interface class to bind instances to. | required |
capabilities | Iterable['Capability'] | Concrete capability objects to store, preserving iteration order. The tuple replaces any previous instance binding for the same interface. | required |
Raises:
| Type | Description |
|---|---|
Exception | Exceptions raised while iterating |
instances ¶
instances(interface_cls)
Retrieve the concrete capability objects associated with the given interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['InterfaceBase'] | Interface class to look up. | required |
Returns:
| Type | Description |
|---|---|
'Capability' | The stored capability tuple, or an empty tuple when no instances are |
... | bound for the interface. |
snapshot ¶
snapshot()
Return a read-only snapshot of declared capability names.
The returned MappingProxyType wraps a new dictionary, and each value is a frozenset. Later registry mutations do not affect earlier snapshots. Concrete capability instances are not included.
Returns:
| Type | Description |
|---|---|
Mapping[type['InterfaceBase'], frozenset[CapabilityName]] | A read-only mapping of interface classes to immutable declared-name |
Mapping[type['InterfaceBase'], frozenset[CapabilityName]] | sets. |
general_manager.interface.capabilities.orm_utils.payload_normalizer.PayloadNormalizer ¶
Normalize keyword payloads for database-backed interface operations.
__init__ ¶
__init__(model)
Initialize the normalizer for a Django model and cache metadata used for payload normalization.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model | type[Model] | The Django model class whose attributes and fields will be inspected to validate and normalize payload keys and values. | required |
normalize_filter_kwargs ¶
normalize_filter_kwargs(kwargs)
Normalize filter keyword arguments by replacing any general-manager values with their unwrapped identifier or instance.
Returns a new mapping and does not mutate kwargs. Keys are preserved. A "general-manager value" is an actual GeneralManager instance. If prefer_instance resolution cannot find _interface._instance, the manager's identification["id"] is used; malformed manager state such as a missing "id" propagates the underlying exception.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kwargs | PayloadMapping | Mapping of filter keyword names to values which may include general-manager wrappers. | required |
Returns:
| Type | Description |
|---|---|
PayloadMapping | A new dictionary with the same keys and values converted to their unwrapped manager form where applicable. |
validate_keys ¶
validate_keys(kwargs)
Validate that each key in the provided kwargs corresponds to a known attribute or field on the target model.
Known attributes are names present in vars(model), which includes descriptors, properties, methods, and other class attributes declared on the model class. Known fields are names from model._meta.get_fields(), including forward and reverse Django relations. The _list and _id_list aliases are accepted only when their base name is a real local many-to-many field; malformed aliases otherwise validate as their literal key and usually raise UnknownFieldError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kwargs | PayloadMapping | Mapping of payload keys to values; keys ending with "_id_list" will be validated by their base name (suffix removed). | required |
Raises:
| Type | Description |
|---|---|
UnknownFieldError | If any key's base name is not an attribute of the model instance and not a model field name. |
split_many_to_many ¶
split_many_to_many(kwargs)
Mutate a kwargs mapping by moving many-to-many related entries out of it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kwargs | PayloadMapping | Mapping of field lookups where keys for many-to-many relations are expected to end with | required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple | tuple[PayloadMapping, PayloadMapping] | A pair |
Notes
This function mutates the kwargs argument by removing any entries moved into many_kwargs. The first returned mapping is the same object passed in. If both <relation>_list and <relation>_id_list are present, iteration order decides the last canonical value stored in many_kwargs.
split_many_to_many_non_mutating ¶
split_many_to_many_non_mutating(kwargs)
Return separated many-to-many entries without mutating the input mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kwargs | PayloadMapping | Mapping of field lookups where keys for many-to-many relations may use either | required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple | tuple[PayloadMapping, PayloadMapping] | A pair |
Notes
This is the non-mutating counterpart to split_many_to_many(). If both <relation>_list and <relation>_id_list are present, iteration order decides the last canonical value stored in many_kwargs.
normalize_simple_values ¶
normalize_simple_values(kwargs)
Normalize simple (single-valued) payload entries by converting general-manager objects to their identifier form and adjusting keys.
For each key/value in kwargs, if value is recognized as a general-manager instance its identifier is used as the value; when the original key does not end with _id, the key is renamed to {key}_id. Non-manager values are kept unchanged. Returns a new mapping and does not mutate kwargs. Relation-key renaming applies only to forward ForeignKey and OneToOneField names cached from the model metadata. Reverse relations, generic relations, and many-to-many fields are not relation-renamed here. If both a relation key and its <relation>_id key appear, the later normalized key overwrites the earlier value according to input iteration order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kwargs | PayloadMapping | Mapping of field names to single values to normalize. | required |
Returns:
| Type | Description |
|---|---|
PayloadMapping | A new mapping with manager values replaced by their identifiers and keys suffixed with |
normalize_many_values ¶
normalize_many_values(kwargs)
Normalize values intended to represent multi-valued model fields into lists of underlying identifiers or preserved values.
For each key in kwargs: - Keys with value None or models.NOT_PROVIDED are omitted. - Iterable values (except str and bytes) are converted to lists where each item is resolved from manager-like objects to their identifier (or left unchanged if not resolvable). - Non-iterable values are wrapped into a single-item list after the same resolution. Returns a new mapping and preserves incoming keys exactly; it does not canonicalize <relation>_list to <relation>_id_list. Call split_many_to_many() first when canonical many-to-many keys are required. Dictionaries and generators are treated as iterables, so a dict normalizes its keys and a generator is consumed once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kwargs | PayloadMapping | Mapping of field names to values which may be single items or iterables. | required |
Returns:
| Type | Description |
|---|---|
ManyValuePayload | A new mapping where each key maps to a list of resolved items suitable for multi-valued field assignment. |
general_manager.interface.capabilities.core.utils.with_observability is a public helper for wrapping capability operations with optional observability hooks. Its full behavior is described in the Core Observability Utility section below.
general_manager.interface.bundles.calculation.CALCULATION_CORE_CAPABILITIES module-attribute ¶
CALCULATION_CORE_CAPABILITIES = CapabilitySet(
label="calculation_core",
entries=(
InterfaceCapabilityConfig(
CalculationLifecycleCapability
),
InterfaceCapabilityConfig(
CalculationReadCapability
),
InterfaceCapabilityConfig(
CalculationQueryCapability
),
),
)
general_manager.interface.bundles.database.ORM_PERSISTENCE_CAPABILITIES module-attribute ¶
ORM_PERSISTENCE_CAPABILITIES = CapabilitySet(
label="orm_persistence_core",
entries=(
InterfaceCapabilityConfig(
OrmPersistenceSupportCapability
),
InterfaceCapabilityConfig(OrmLifecycleCapability),
InterfaceCapabilityConfig(SoftDeleteCapability),
InterfaceCapabilityConfig(OrmReadCapability),
InterfaceCapabilityConfig(OrmValidationCapability),
InterfaceCapabilityConfig(OrmHistoryCapability),
InterfaceCapabilityConfig(OrmQueryCapability),
InterfaceCapabilityConfig(
LoggingObservabilityCapability
),
),
)
general_manager.interface.bundles.database.ORM_WRITABLE_CAPABILITIES module-attribute ¶
ORM_WRITABLE_CAPABILITIES = CapabilitySet(
label="orm_writable_core",
entries=(
*(entries),
InterfaceCapabilityConfig(OrmMutationCapability),
InterfaceCapabilityConfig(OrmCreateCapability),
InterfaceCapabilityConfig(OrmUpdateCapability),
InterfaceCapabilityConfig(OrmDeleteCapability),
),
)
general_manager.interface.bundles.database.EXISTING_MODEL_CAPABILITIES module-attribute ¶
EXISTING_MODEL_CAPABILITIES = CapabilitySet(
label="existing_model_core",
entries=(
*(entries),
InterfaceCapabilityConfig(
ExistingModelResolutionCapability
),
),
)
general_manager.interface.bundles.database.READ_ONLY_CAPABILITIES module-attribute ¶
READ_ONLY_CAPABILITIES = CapabilitySet(
label="read_only_core",
entries=(
InterfaceCapabilityConfig(
OrmPersistenceSupportCapability
),
InterfaceCapabilityConfig(
ReadOnlyLifecycleCapability
),
InterfaceCapabilityConfig(SoftDeleteCapability),
InterfaceCapabilityConfig(OrmReadCapability),
InterfaceCapabilityConfig(OrmValidationCapability),
InterfaceCapabilityConfig(OrmHistoryCapability),
InterfaceCapabilityConfig(OrmQueryCapability),
InterfaceCapabilityConfig(
LoggingObservabilityCapability
),
InterfaceCapabilityConfig(
ReadOnlyManagementCapability
),
),
)
general_manager.interface.bundles.remote_manager.REMOTE_MANAGER_CAPABILITIES module-attribute ¶
REMOTE_MANAGER_CAPABILITIES = CapabilitySet(
label="remote_manager",
entries=(
InterfaceCapabilityConfig(
RequestLifecycleCapability
),
InterfaceCapabilityConfig(RequestReadCapability),
InterfaceCapabilityConfig(
RequestValidationCapability
),
InterfaceCapabilityConfig(
RemoteManagerQueryCapability
),
InterfaceCapabilityConfig(RequestCreateCapability),
InterfaceCapabilityConfig(RequestUpdateCapability),
InterfaceCapabilityConfig(RequestDeleteCapability),
InterfaceCapabilityConfig(
LoggingObservabilityCapability
),
),
)
general_manager.interface.bundles.request.REQUEST_CORE_CAPABILITIES module-attribute ¶
REQUEST_CORE_CAPABILITIES = CapabilitySet(
label="request_core",
entries=(
InterfaceCapabilityConfig(
RequestLifecycleCapability
),
InterfaceCapabilityConfig(RequestReadCapability),
InterfaceCapabilityConfig(
RequestValidationCapability
),
InterfaceCapabilityConfig(RequestQueryCapability),
InterfaceCapabilityConfig(
LoggingObservabilityCapability
),
),
)
general_manager.interface.bundles.request.REQUEST_MUTATION_CAPABILITIES module-attribute ¶
REQUEST_MUTATION_CAPABILITIES = CapabilitySet(
label="request_mutation",
entries=(
InterfaceCapabilityConfig(RequestCreateCapability),
InterfaceCapabilityConfig(RequestUpdateCapability),
InterfaceCapabilityConfig(RequestDeleteCapability),
),
)
general_manager.interface.bundles.request.REQUEST_CAPABILITIES module-attribute ¶
REQUEST_CAPABILITIES = REQUEST_CORE_CAPABILITIES
CapabilityName is the public literal set of supported capability identifiers. Interfaces use these stable string keys in _capabilities, _capability_handlers, capability_overrides, manifests, and capability registries. Capability is a runtime-checkable protocol for capability handler instances: a handler exposes a class-level name and implements setup(interface_cls) -> None and teardown(interface_cls) -> None. Both methods mutate the supplied interface class in place. Concrete implementations own their validation and error types; the protocol does not normalize exceptions and does not promise idempotency.
BaseCapability is the default base class for concrete capability handlers. It checks every name in required_attributes with hasattr(interface_cls, name); it does not call those attributes or validate their signatures. The dataclass has no instance fields or constructor options of its own. Successful setup() copies the interface class's current _capability_handlers mapping by converting it to a plain dict, or starts from an empty plain dict when no registry exists yet, registers the capability instance under its name, and writes the copied mapping back. teardown() uses the same plain-dict conversion, or starts from an empty mapping when no registry exists yet, removes that name if present, and writes the mapping back; repeated teardown is a no-op. Missing required attributes raise CapabilityBindingError with sorted missing names. The underlying missing-attribute formatter returns "missing required attributes: " for empty input, though setup() only calls it after at least one name is missing. Non-AttributeError failures from hasattr(), registry conversion, and class assignment propagate unchanged. Repeated setup replaces the handler currently stored for the same capability name. ReadCapability, CreateCapability, UpdateCapability, and DeleteCapability require get_data, create, update, and delete respectively. HistoryCapability and ValidationCapability both require get_attribute_types. NotificationCapability, SchedulingCapability, AccessControlCapability, and ObservabilityCapability are marker handlers with no additional requirements beyond registration.
CapabilityBindingError(capability_name, reason) is raised when a capability handler cannot attach to an interface class. The error subclasses RuntimeError, stores capability_name and reason unchanged as public attributes, and formats its message as Capability '<name>' could not be attached: <reason>. Empty and multiline reasons are preserved exactly in the attributes and formatted message. The exceptions module's public export list contains only CapabilityBindingError.
InterfaceCapabilityConfig(handler, options=None) is the public declarative entry used by Interface.configured_capabilities. handler is the capability class. options=None constructs it without keyword arguments; any supplied mapping, including an empty or otherwise falsey mapping, is copied to a plain dict at instantiate() time and expanded as keyword arguments. The config is frozen, but the original mapping is not copied until instantiation. Constructor errors and mapping-conversion errors propagate unchanged.
CapabilitySet(label, entries) names a reusable bundle of concrete InterfaceCapabilityConfig entries. The constructor accepts any iterable and stores entries as an immutable tuple attribute; it does not deep-copy or runtime-validate entry values beyond normal iteration. iter_capability_entries(entries) and flatten_capability_entries(entries) expand CapabilitySet values one level, preserve input order, do not deduplicate, and consume the supplied iterable once. iter_capability_entries() stays lazy for the outer iterable, while flatten_capability_entries() returns a tuple. They do not validate that handlers implement the capability protocol; invalid non-CapabilitySet runtime values are yielded or returned unchanged if callers bypass static typing. Iteration-time exceptions from the supplied iterable propagate unchanged. InterfaceBase performs capability protocol checks when it instantiates and binds configured capabilities. The configuration module's public export list is CapabilityConfigEntry, CapabilitySet, InterfaceCapabilityConfig, flatten_capability_entries, and iter_capability_entries.
CAPABILITY_CLASS_MAP is the default mapping from public CapabilityName values to built-in capability classes used by the legacy capability factory. CapabilityOverride is either a capability class or a zero-argument callable returning a capability instance. build_capabilities(interface_cls, names, overrides) consumes names once, preserves order, returns a mutable list, and creates duplicate instances for duplicate names. A non-None override value for a name takes precedence over CAPABILITY_CLASS_MAP, including for runtime names outside the static CapabilityName vocabulary. The current implementation accepts interface_cls for compatibility but does not inspect it or pass it to handlers. Unknown names without overrides raise KeyError("Unknown capability '<name>'"); iteration, mapping lookup, and handler construction errors propagate unchanged.
CapabilityRegistry is the in-memory registry used by manifest-driven capability builders to track resolved capability declarations and concrete capability instances per interface class. register(interface_cls, capabilities, replace=False) consumes capabilities exactly once into a temporary set before mutating internal state. Duplicate names collapse; replace=False merges into existing declarations; replace=True replaces the existing declaration, including with an empty set. Iteration errors propagate before the registry is changed. get(interface_cls) returns a defensive frozenset, or an empty frozenset for unregistered interfaces. bind_instances(interface_cls, capabilities) consumes concrete capability instances once into an ordered tuple before assignment and replaces only the instance binding for that interface. Declared names and concrete instances are independent: registering names does not clear instances, and binding instances does not register names. instances(interface_cls) returns the stored tuple or an empty tuple. snapshot() returns a MappingProxyType over a newly built mapping of interface classes to frozenset declarations; later registry mutations do not affect prior snapshots, and concrete instances are not included. The registry is process-local, has no locking, and trusts runtime values if callers bypass static typing.
general_manager.interface.manifests.capability_models.CapabilityPlan dataclass ¶
Immutable manifest entry for one interface family.
CapabilityName is the public string-literal capability identifier type exported by general_manager.interface.capabilities. required and optional are normalized to frozenset values and duplicate capability names collapse. A capability may appear in both sets; manifest resolution and builder validation decide how to interpret that combination. flags maps runtime flag names to optional capability names, is copied to a plain dict, and is exposed through a read-only mapping proxy.
__post_init__ ¶
__post_init__()
Normalize required, optional, and flag mapping attributes.
Raises:
| Type | Description |
|---|---|
TypeError | If |
general_manager.interface.manifests.capability_models.CapabilityConfig dataclass ¶
Mutable runtime toggles for optional capability activation.
Capability names use the public CapabilityName string-literal type from general_manager.interface.capabilities. enabled and disabled are mutable sets consumed by ManifestCapabilityBuilder. enabled requests optional capabilities, while disabled removes optional capabilities after flag and manual enables have been validated. If the same optional name appears in both sets, disabled wins; manually enabling a non-optional name still raises in the builder even if that name is also disabled. flags stores arbitrary truth-tested values, not only booleans: is_flag_enabled() applies Python bool(...) coercion and treats missing flags as disabled.
__post_init__ ¶
__post_init__()
Normalize mutable containers owned by this config instance.
The config remains mutable after construction, but external set or mapping objects passed to the constructor are copied so later caller-side mutation does not affect builder resolution.
Raises:
| Type | Description |
|---|---|
TypeError | If |
is_flag_enabled ¶
is_flag_enabled(flag_name)
Return whether flag_name is present with a truthy value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
flag_name | str | Flag key to check. | required |
Returns:
| Type | Description |
|---|---|
bool |
|
bool | flags return |
general_manager.interface.manifests.capability_models.CapabilitySelection dataclass ¶
Immutable result of resolving a plan against runtime config.
Capability names use the public CapabilityName string-literal type from general_manager.interface.capabilities. required, optional, and activated_optional are normalized to frozensets and duplicate capability names collapse. The model intentionally does not validate that activated optional names are present in optional; ManifestCapabilityBuilder owns that validation.
all property ¶
all
Return required plus activated optional capability names.
Returns:
| Type | Description |
|---|---|
frozenset[CapabilityName] | Fresh |
frozenset[CapabilityName] | activated optional capability. Inactive optional names are excluded. |
__post_init__ ¶
__post_init__()
Normalize all selection sets to immutable frozensets.
Raises:
| Type | Description |
|---|---|
TypeError | If any field cannot be iterated or contains unhashable values. |
CapabilityPlan(required=frozenset(), optional=frozenset(), flags={}) is the immutable manifest entry used by CapabilityManifest. required and optional are normalized to frozenset values, so duplicate capability names collapse. A name may appear in both sets; the model stores that state and leaves interpretation to manifest resolution and the builder. flags maps runtime flag names to capability names, is copied to a plain dict, and is exposed as a read-only mapping proxy. Iteration, hashing, and mapping-conversion errors propagate unchanged. All capability-name fields use the public CapabilityName string-literal type exported by general_manager.interface.capabilities.
CapabilityConfig(enabled=set(), disabled=set(), flags={}) is the mutable runtime toggle object passed to ManifestCapabilityBuilder.build(). The constructor copies supplied enabled/disabled sets and the flag mapping, then the instance remains mutable. Flag values are object-valued and truth-tested with Python bool(...); missing flags are disabled. enabled requests optional capabilities, while disabled removes optional capabilities after flag and manual enables have been validated. If the same optional name appears in both sets, disabled wins; manually enabling a non-optional name still raises in the builder even if the name is also disabled. CapabilitySelection(required, optional, activated_optional) is the immutable build result. It normalizes all three fields to frozenset values. Its all property returns required names plus activated optional names and excludes inactive optional names. The model does not validate that activated names are present in optional; the builder is the validation boundary.
general_manager.interface.manifests.capability_builder.ManifestCapabilityBuilder ¶
Resolve and bind manifest-declared capabilities for interface classes.
The builder resolves a CapabilityManifest for one interface class, applies optional-capability configuration, creates handler instances in sorted capability-name order, binds them to the interface, and mirrors the final declaration plus concrete handlers into a CapabilityRegistry. It mutates the interface class by setting its capability selection, capability-name set, and handler mapping. If build fails during resolution, instantiation, attachment, or registry publication, the previous interface selection, names, and handlers are restored. Registry implementations own rollback for any registry-side state they mutate before raising.
registry property ¶
registry
Return the registry receiving declarations and concrete handlers.
Returns:
| Type | Description |
|---|---|
CapabilityRegistry | The |
CapabilityRegistry | fresh registry created by the builder. |
__init__ ¶
__init__(*, manifest=None, registry=None)
Initialize the builder with manifest and registry dependencies.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manifest | CapabilityManifest | None | Manifest used to resolve interface classes. | None |
registry | CapabilityRegistry | None | Registry that receives resolved declarations and concrete capability instances. | None |
build ¶
build(interface_cls, *, config=None)
Resolve, instantiate, attach, and register capabilities.
The manifest is resolved for interface_cls, required capabilities are validated against the config, optional capabilities are activated by flags and manual enables, and disabled optional capabilities are removed. Capability instances are created from selection.all in sorted capability-name order using the interface's capability_overrides, then each handler is bound through InterfaceBase._bind_capability_handler. After successful binding, the registry replaces the interface's declared names and concrete handler tuple.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[InterfaceBase] | Interface class to mutate and register. | required |
config | CapabilityConfig | None | Optional runtime configuration. | None |
Returns:
| Type | Description |
|---|---|
CapabilitySelection | The immutable selection that was attached to the interface. |
Raises:
| Type | Description |
|---|---|
ValueError | If a required capability is disabled, if a flag maps to a non-optional capability when enabled, or if a manual enable is not declared optional for the interface. |
KeyError | If a selected capability has no default class and no override. |
Exception | Exceptions from manifest resolution, config iterables or mappings, override lookup/call, capability construction, handler teardown/setup, startup-hook/system-check registration, or registry publication propagate unchanged. Failures restore the interface's prior capability selection, name set, and handler mapping. Registry implementations own rollback for registry-side state they mutate before raising. |
ManifestCapabilityBuilder(manifest=None, registry=None) resolves a CapabilityManifest for one interface class and binds concrete capability handlers. manifest=None uses the module default manifest; registry=None creates a fresh CapabilityRegistry for the builder. The registry property returns that exact registry object.
build(interface_cls, config=None) resolves the manifest, rejects disabled required capabilities, activates optional capabilities from enabled flags and manual enables, removes disabled optional capabilities, creates handlers in sorted capability-name order using interface_cls.capability_overrides, binds each handler to the interface, then replaces the registry declaration and concrete handler tuple for that interface. A capability present in both enabled and disabled is disabled when it is optional; a non-optional manual enable still raises even if that name also appears in disabled. Unknown selected capability names raise KeyError; invalid optional selections raise ValueError; handler construction, setup/teardown, startup-hook registration, system-check registration, manifest, config, override, and registry errors propagate unchanged. If resolution, instantiation, or attachment fails before registry publication, or if registry publication itself raises, the builder restores the interface's previous selection, capability-name set, and handler mapping. Registry implementations own rollback for any registry-side state they mutate before raising.
with_observability(target, *, operation, payload, func) is the shared wrapper used by capability implementations that emit observability hooks. It is the only public export from general_manager.interface.capabilities.core.utils. The wrapper looks up target.get_capability_handler("observability") when that method exists. If the method is absent or returns None, func() is called directly and the payload is not copied. If a capability is present, the wrapper reads before_operation, after_operation, and on_error with getattr(..., None). Absent hook attributes and attributes set to None are ignored; non-None values are called as hooks, so non-callable values fail when called. It shallow-copies payload into one plain dict after capability lookup and hook-attribute lookup, then passes the same copy to every hook for that invocation. Hook order is before_operation, then func(), then after_operation on success, or on_error when func() raises. before_operation exceptions prevent func() from running; on_error exceptions replace the original func() exception; after_operation exceptions replace the successful result. Exceptions from capability lookup, hook-attribute lookup, payload conversion, hooks, and func() propagate unchanged.
CALCULATION_CORE_CAPABILITIES is the reusable bundle installed by CalculationInterface. Its label is "calculation_core" and its entries are CalculationLifecycleCapability, CalculationReadCapability, and CalculationQueryCapability, in that order. The lifecycle entry publishes the "calculation_lifecycle" capability name used by CalculationInterface.lifecycle_capability_name; the read capability backs attribute access and get_data(), and the query capability backs all(), filter(), and exclude(). The bundle intentionally does not include create, update, delete, or ORM capabilities.
ORM_PERSISTENCE_CAPABILITIES is the shared ORM persistence bundle. Its label is "orm_persistence_core" and its ordered entries install ORM support, ORM lifecycle, soft-delete handling, ORM read, validation, history, query, and logging observability capabilities. ORM_WRITABLE_CAPABILITIES has label "orm_writable_core", starts with the persistence entries in the same order, then adds mutation, create, update, and delete capabilities; this is the bundle installed by DatabaseInterface. EXISTING_MODEL_CAPABILITIES has label "existing_model_core", starts with the writable entries in the same order, then adds ExistingModelResolutionCapability; this is the bundle installed by ExistingModelInterface. READ_ONLY_CAPABILITIES has label "read_only_core" and installs ORM support, read-only lifecycle, soft-delete handling, ORM read, validation, history, query, logging observability, and read-only management capabilities, in that order. The read-only lifecycle capability intentionally publishes the shared "orm_lifecycle" capability name so OrmInterfaceBase lifecycle lookup continues to work. The bundle intentionally omits mutation, create, update, and delete capabilities.
REMOTE_MANAGER_CAPABILITIES is the bundle installed by RemoteManagerInterface. Its label is "remote_manager" and its ordered entries install request lifecycle, request read, request validation, remote manager query, request create, request update, request delete, and logging observability capabilities. RemoteManagerQueryCapability publishes the shared "query" capability name and is also present in RemoteManagerInterface.capability_overrides so request query behavior is replaced by the RemoteAPI-aware query capability.
REQUEST_CORE_CAPABILITIES is the bundle installed by RequestInterface. Its label is "request_core" and its ordered entries install request lifecycle, request read, request validation, request query, and logging observability capabilities. REQUEST_CAPABILITIES is an alias for REQUEST_CORE_CAPABILITIES kept for callers that need the default request-interface bundle. REQUEST_MUTATION_CAPABILITIES has label "request_mutation" and contains request create, request update, and request delete capabilities, in that order. RequestInterface does not install the mutation bundle wholesale by default; during subclass configuration it adds the matching create, update, and delete capability entries only when Meta.create_operation, Meta.update_operation, or Meta.delete_operation is declared and the handler is not already present.
general_manager.interface.capabilities.orm ¶
ORM-backed capability implementations.
HistoryNotSupportedError ¶
Bases: RuntimeError
Raised when historical lookups are requested but not supported.
The error message is "{interface_name} does not support historical queries.".
OrmHistoryCapability dataclass ¶
Bases: BaseCapability
Lookup historical records for ORM-backed interfaces.
get_historical_record ¶
get_historical_record(
interface_cls, instance, search_date=None
)
Retrieve the latest historical record for instance at search_date.
The lookup prefers instance.history when the object exposes a django-simple-history manager. Otherwise it falls back to interface_cls._model.history and derives the primary key from instance.pk, then instance.id, then instance.identification["id"]. A configured database alias is applied before filtering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['OrmInterfaceBase[models.Model]'] | ORM interface class used to resolve the model history manager and capability settings. | required |
instance | object | Model-like or manager-like object to identify in the history table. | required |
search_date | datetime | None | Optional cutoff date; when provided, only records with | None |
Returns:
| Type | Description |
|---|---|
Model | None | Historical model instance, or |
Model | None | manager, or matching historical row is available. |
get_history_queryset_for_manager ¶
get_history_queryset_for_manager(interface_cls, manager)
Return the history queryset scoped to the manager instance's primary key.
The target identifier is derived from manager.pk, then manager.id, then mapping-like manager.identification["id"]. The lookup key defaults to "id" and uses the interface model primary-key field name when it is available as a string. A configured database alias is applied before the filtered queryset is returned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['OrmInterfaceBase[models.Model]'] | ORM interface whose underlying model provides the history manager. | required |
manager | object | Manager-like object exposing | required |
Returns:
| Type | Description |
|---|---|
QuerySet[Model] | History queryset limited to records for the target object. |
Raises:
| Type | Description |
|---|---|
HistoryNotSupportedError | If the interface does not expose a history manager or the manager cannot be scoped to a primary key. |
get_historical_queryset ¶
get_historical_queryset(interface_cls, search_date)
Retrieve a queryset representing the historical state as of the given date.
A configured database alias is applied before calling history.as_of(search_date).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['OrmInterfaceBase[models.Model]'] | ORM interface whose underlying model provides the historical manager. | required |
search_date | datetime | Cutoff datetime for historical snapshot lookup. | required |
Returns:
| Type | Description |
|---|---|
QuerySet[Model] | QuerySet representing the state at |
Raises:
| Type | Description |
|---|---|
HistoryNotSupportedError | If the model does not expose a history manager. |
get_historical_record_by_pk ¶
get_historical_record_by_pk(interface_cls, pk, search_date)
Retrieve the latest historical record for primary key pk at search_date.
The lookup uses the model's history manager, applies any configured database alias, filters by the model primary-key field and history_date <= search_date, orders by history_date, and returns the last row.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['OrmInterfaceBase[models.Model]'] | ORM interface whose underlying model provides the historical manager. | required |
pk | object | Primary key of the target model record. | required |
search_date | datetime | None | Cutoff datetime. If | required |
Returns:
| Type | Description |
|---|---|
Model | None | Historical model instance, or |
Model | None |
|
OrmLifecycleCapability dataclass ¶
Bases: BaseCapability
Handle creation and configuration of ORM-backed interfaces.
pre_create ¶
pre_create(*, name, attrs, interface, base_model_class)
Prepare ORM model, concrete interface class, and factory before the parent class is created.
Creates a Django model class from fields discovered on the provided interface (applying any Meta configuration such as soft-delete and rules), finalizes its metadata, builds a concrete interface subclass bound to that model, and installs a Factory class and Interface class into the provided attrs mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | str | The name to use for the generated model and factory. | required |
attrs | dict[str, object] | The attribute dict for the class being created; will be updated with "Interface", "Factory", and "_interface_type". | required |
interface | type[OrmInterfaceBase[Model]] | The interface class that defines model fields and optional Meta/Factory configuration. | required |
base_model_class | type[GeneralManagerBasisModel] | Base model class to derive the generated model from (may be adjusted for soft-delete support). | required |
Returns:
| Type | Description |
|---|---|
tuple[dict[str, object], type['OrmInterfaceBase[models.Model]'], type[GeneralManagerBasisModel]] | tuple[dict[str, object], type[OrmInterfaceBase[models.Model]], type[GeneralManagerBasisModel]]: - The possibly-modified attrs mapping. - The concrete interface subclass bound to the generated model. - The generated Django model class. |
Raises:
| Type | Description |
|---|---|
Exception | Lifecycle setup errors are not wrapped. Invalid Django model bases or fields, invalid nested Meta attributes, invalid Factory definitions, rule setup errors, and custom field discovery errors propagate from Django, factory_boy, rule construction, or the custom field implementation that raised them. |
post_create ¶
post_create(*, new_class, interface_class, model)
Attach the created interface class and model to each other and assign ORM managers to the new class.
This function links the generated interface and model to the newly created class by setting the interface's parent class and the model's general manager class. It also obtains and assigns the default manager to new_class.objects, and if soft-delete is enabled for the interface, assigns an all_objects manager that includes inactive/soft-deleted records.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_class | type | The class that was just created for the interface (the concrete manager/interface class). | required |
interface_class | type[OrmInterfaceBase] | The concrete interface subclass bound to the model. | required |
model | type[GeneralManagerBasisModel] | None | The ORM model class created for the interface, or None if no model was generated. | required |
describe_custom_fields ¶
describe_custom_fields(model)
List Django Field names declared on the given model and generate ignore markers for each field's value and unit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model | type[Model] | Model | Model class or instance to inspect for attributes that are instances of Django | required |
Returns:
| Name | Type | Description |
|---|---|---|
field_names | list[str] | Names of discovered model fields (uses the field's |
ignore | list[str] | Generated ignore markers in the form |
OrmCreateCapability dataclass ¶
Bases: BaseCapability
Create new ORM instances using capability-driven configuration.
create ¶
create(interface_cls, *args, **kwargs)
Create a new ORM model instance from the provided payload and persist it with optional creator and history metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | OrmInterfaceClass | Interface class that defines the target model and capabilities. | required |
*args | object | Ignored positional arguments kept for manager/capability signature compatibility. Passing positional values has no effect. | () |
**kwargs | object | Field values used to construct the instance. Reserved metadata keys are | {} |
Returns:
| Type | Description |
|---|---|
MutationResult | Capability-level result dictionary containing the new instance |
MutationResult | primary key as |
MutationResult | result and returns the public manager instance from |
MutationResult |
|
Raises:
| Type | Description |
|---|---|
UnknownFieldError | If the normalized payload contains unknown keys. |
InvalidFieldValueError | If field assignment raises |
InvalidFieldTypeError | If field assignment raises |
Exception | Validation, transaction, save, many-to-many, change-reason, history actor, and observability errors are not wrapped. |
OrmDeleteCapability dataclass ¶
Bases: BaseCapability
Delete (or deactivate) ORM instances.
delete ¶
delete(interface_instance, *args, **kwargs)
Delete or deactivate the provided ORM interface instance according to the interface's deletion policy.
If soft-delete is enabled for the interface, the instance is marked inactive (requires the instance to implement SupportsActivation) and saved with an optional history comment indicating deactivation. If soft-delete is not enabled, the instance is hard-deleted inside a database transaction using the support-provided database alias when available; the function attempts to set changed_by_id from creator_id and attaches the provided history comment as the change reason before deletion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_instance | OrmInterfaceInstance | The interface-wrapped model instance to remove. | required |
*args | object | Ignored positional arguments kept for manager/capability signature compatibility. Passing positional values has no effect. | () |
**kwargs | object | Reserved metadata keys are | {} |
Returns:
| Name | Type | Description |
|---|---|---|
MutationResult | MutationResult | Capability-level dictionary containing the primary key under the key |
Raises:
| Type | Description |
|---|---|
MissingActivationSupportError | If soft-delete is enabled but the instance does not implement activation support. |
Exception | Row lookup, history actor lookup, transaction, delete, cache invalidation, change-reason, save, and observability errors are not wrapped. |
OrmMutationCapability dataclass ¶
Bases: BaseCapability
Common utilities to modify ORM instances.
assign_simple_attributes ¶
assign_simple_attributes(interface_cls, instance, kwargs)
Apply simple (non-relational) attribute updates to a Django model instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
instance | Model | The model instance to modify. | required |
kwargs | MutationPayload | Mapping of field names to values; entries with the sentinel | required |
Returns:
| Type | Description |
|---|---|
Model | models.Model: The same instance after attribute assignment. |
Raises:
| Type | Description |
|---|---|
InvalidFieldValueError | If assigning a value raises a |
InvalidFieldTypeError | If assigning a value raises a |
save_with_history ¶
save_with_history(
interface_cls, instance, *, creator_id, history_comment
)
Persist the model instance while recording creator metadata and an optional change reason.
Performs the save inside an atomic transaction using the interface's configured database alias when available, sets changed_by_id on the instance if the attribute exists, runs model validation, and attaches a change reason after a successful save when history_comment is provided.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The interface class used to resolve support capabilities and configuration. | required |
instance | Model | The Django model instance to validate and save. | required |
creator_id | int | None | Identifier of the user or process responsible for the change; assigned to | required |
history_comment | str | None | Optional comment describing the change; attached as a change reason after save when provided. | required |
Returns:
| Name | Type | Description |
|---|---|---|
object | object | The primary key ( |
Raises:
| Type | Description |
|---|---|
InvalidFieldValueError | From prior assignment helpers. |
Exception | Database-alias lookup, history actor lookup, validation, transaction, save, change-reason, and observability errors are not wrapped. |
apply_many_to_many ¶
apply_many_to_many(
interface_cls,
instance,
*,
many_to_many_kwargs,
history_comment
)
Apply many-to-many updates to a model instance's related fields.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | Interface class owning the model (used for observability). | required |
instance | Model | The model instance whose relationships will be updated. | required |
many_to_many_kwargs | ManyToManyPayload | Mapping of normalized many-to-many payload keys to related values. Keys are still expected to use | required |
history_comment | str | None | Optional change reason to attach to the instance's history after updates. | required |
Returns:
| Type | Description |
|---|---|
Model | models.Model: The same model instance after its many-to-many relations have been updated. |
Raises:
| Type | Description |
|---|---|
AttributeError | If the derived relation manager does not exist. |
Exception | Relation |
OrmUpdateCapability dataclass ¶
Bases: BaseCapability
Update existing ORM instances.
update ¶
update(interface_instance, *args, **kwargs)
Update the model instance referenced by the given interface instance with the provided payload, persisting changes and recording history and many-to-many updates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_instance | OrmInterfaceBase | Interface wrapper whose | required |
*args | object | Ignored positional arguments kept for manager/capability signature compatibility. Passing positional values has no effect. | () |
**kwargs | object | Field values to apply; reserved metadata keys are | {} |
Returns:
| Name | Type | Description |
|---|---|---|
MutationResult | MutationResult | Capability-level mapping containing the saved primary key as |
Raises:
| Type | Description |
|---|---|
UnknownFieldError | If the normalized payload contains unknown keys. |
InvalidFieldValueError | If field assignment raises |
InvalidFieldTypeError | If field assignment raises |
Exception | Row lookup, validation, transaction, save, many-to-many, cache invalidation, change-reason, history actor, and observability errors are not wrapped. |
OrmValidationCapability dataclass ¶
Bases: BaseCapability
Validate and normalize payloads used by mutation capabilities.
normalize_payload ¶
normalize_payload(interface_cls, *, payload)
Normalize and split a mutation payload into simple field values and many-to-many relation values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type | The interface class whose schema/normalizer should be used. | required |
payload | MutationPayload | Raw input payload to validate and normalize. | required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple | tuple[MutationPayload, ManyToManyPayload] |
|
Raises:
| Type | Description |
|---|---|
UnknownFieldError | If a payload key is not a known model field or attribute. |
Exception | Payload-normalizer and observability errors are not wrapped. |
OrmPersistenceSupportCapability dataclass ¶
Bases: BaseCapability
Expose shared helpers to work with Django ORM models.
get_database_alias ¶
get_database_alias(interface_cls)
Retrieve the database alias declared on an ORM interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The ORM interface class to inspect for a | required |
Returns:
| Type | Description |
|---|---|
str | None | str | None: The value of the class attribute |
get_manager ¶
get_manager(interface_cls, *, only_active=True)
Obtain the Django manager for the interface's model, selecting between the active (soft-delete filtered) or all manager and honoring the interface's database alias.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | Interface class providing the Django model and optional metadata. | required |
only_active | bool | If True (default), return the active manager; if False, return the unfiltered/all manager. | True |
Returns:
| Type | Description |
|---|---|
Manager[Model] | django.db.models.Manager: The resolved manager for the interface's model. |
Notes
This function also caches the resolved active manager onto interface_cls._active_manager.
get_queryset ¶
get_queryset(interface_cls)
Retrieve an active queryset for the interface's model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The interface class whose underlying Django model will be queried. | required |
Returns:
| Type | Description |
|---|---|
QuerySet[Model] | models.QuerySet: A Django QuerySet containing the model's active records. |
get_payload_normalizer ¶
get_payload_normalizer(interface_cls)
Return a PayloadNormalizer configured for the interface's Django model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | Interface class providing the | required |
Returns:
| Name | Type | Description |
|---|---|---|
PayloadNormalizer | PayloadNormalizer | A normalizer instance bound to the interface's Django |
get_field_descriptors ¶
get_field_descriptors(interface_cls)
Get or build cached field descriptors for the given ORM interface class.
If descriptors are not already present on the interface class, this populates and caches them on the class as _field_descriptors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The ORM interface class to inspect. | required |
Returns:
| Type | Description |
|---|---|
dict[str, FieldDescriptor] | dict[str, FieldDescriptor]: Mapping of field names to their FieldDescriptor. |
resolve_many_to_many ¶
resolve_many_to_many(
interface_instance, field_call, field_name
)
Resolve a many-to-many relationship for an interface instance and return a queryset of the related target records, using historical snapshots when applicable.
If the relation's through/model is a HistoricalChanges subclass, the function: - Locates the corresponding related attribute on the historical model and collects related IDs. - If the target model has no history support or the interface instance has no search date, returns the live target model queryset filtered by those IDs. - If the target model supports history and a search date is present, returns the historical snapshot queryset as of that date filtered by those IDs. If the target field or related attribute cannot be resolved, an empty queryset for the appropriate model is returned. Historical reads fail closed when either the through relation or target model has no usable history; live reads return the original related manager's queryset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_instance | OrmInterfaceBase | The interface wrapper containing the model instance and optional search date. | required |
field_call | str | Attribute name on the instance to access the related manager (e.g., the many-to-many manager accessor). | required |
field_name | str | Field name on the interface's model corresponding to the relation target. | required |
Returns:
| Type | Description |
|---|---|
QuerySet[Model] | models.QuerySet[models.Model]: A queryset of the related target records or their historical snapshots when applicable. |
Raises:
| Type | Description |
|---|---|
AttributeError | If |
FieldDoesNotExist | If |
OrmQueryCapability dataclass ¶
Bases: BaseCapability
Expose DatabaseBucket operations via the capability configuration.
filter ¶
filter(interface_cls, **kwargs)
Builds a DatabaseBucket representing a queryset filtered by the provided lookup kwargs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | Interface class whose model and configuration determine queryset construction. | required |
**kwargs | object | Lookup expressions passed through the payload normalizer; may include | {} |
Returns:
| Name | Type | Description |
|---|---|---|
DatabaseBucket | DatabaseBucket['GeneralManager'] | A container holding the resulting Django queryset (cast to the model's queryset type), the interface's parent class, and the normalized filter kwargs. |
exclude ¶
exclude(interface_cls, **kwargs)
Builds a DatabaseBucket representing a queryset that excludes records matching the provided filter criteria.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The ORM interface class whose model and metadata are used to construct the queryset. | required |
**kwargs | object | Filter lookup expressions to apply as exclusion criteria. May include | {} |
Returns:
| Name | Type | Description |
|---|---|---|
DatabaseBucket | DatabaseBucket['GeneralManager'] | A container holding the resulting Django queryset, the interface's parent class, and the normalized filter dictionary used for the exclusion. |
OrmReadCapability dataclass ¶
Bases: BaseCapability
Fetch ORM instances (or historical snapshots) for interface instances.
get_data ¶
get_data(interface_instance)
Retrieve the current model instance or a historical snapshot for the given ORM interface instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_instance | OrmInterfaceBase | Interface wrapper containing the primary key ( | required |
Returns:
| Type | Description |
|---|---|
Model | The live model instance or a historical record corresponding to |
Raises:
| Type | Description |
|---|---|
DoesNotExist | If no matching live instance or historical record exists. |
get_attribute_types ¶
get_attribute_types(interface_cls)
Return a mapping of field names to copies of their field descriptor metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The ORM interface class whose field descriptors will be queried. | required |
Returns:
| Type | Description |
|---|---|
dict[str, AttributeTypedDict] | dict[str, AttributeTypedDict]: A dict mapping each field name to a shallow copy of that field's |
get_attributes ¶
get_attributes(interface_cls)
Return a mapping of field names to their accessor callables for the given ORM interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The interface class whose model field descriptors will be used. | required |
Returns:
| Type | Description |
|---|---|
dict[str, Callable[[OrmInterfaceInstance], object]] | dict[str, Callable[[OrmInterfaceBase[models.Model]], object]]: A dictionary mapping each field name to a callable that, given an instance, returns that field's value. |
get_field_type ¶
get_field_type(interface_cls, field_name)
Determine the effective type associated with a model field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | Interface class whose underlying Django model contains the field. | required |
field_name | str | Name of the field on the model. | required |
Returns:
| Name | Type | Description |
|---|---|---|
type | type[object] | The Django field class for stored model fields, the related |
type[object] | model's | |
type[object] | descriptor metadata |
Raises:
| Type | Description |
|---|---|
FieldDoesNotExist | If the field is not present on the model and no synthetic descriptor exists for |
SoftDeleteCapability ¶
Bases: BaseCapability
Track whether soft delete behavior should be applied.
__init__ ¶
__init__(enabled=False)
Initialize the soft-delete capability with a default enabled state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled | bool | Initial enabled state for soft-delete; True to enable, False to disable. | False |
setup ¶
setup(interface_cls)
Initialize the capability's soft-delete state for the given interface class.
Determines the default enabled state in this order: 1) use interface_cls._soft_delete_default if present; 2) else use interface_cls._model._meta.use_soft_delete if available; 3) otherwise fall back to the capability's current enabled value. Sets self.enabled to the resulting boolean and then calls the base setup with the same interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[InterfaceBase] | The interface class being configured. | required |
is_enabled ¶
is_enabled()
Indicates whether soft-delete behavior is enabled for this capability.
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True if soft-delete is enabled, False otherwise. |
set_state ¶
set_state(enabled)
Set whether soft-delete is enabled for this capability.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled | bool | True to enable soft-delete behavior, False to disable it. | required |
update_change_reason ¶
update_change_reason(instance, reason)
Update the latest history row on the model instance's database alias.
get_support_capability ¶
get_support_capability(interface_cls)
Resolve and return the "orm_support" capability instance for the given interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type | The ORM interface class to query for the capability. | required |
Returns:
| Name | Type | Description |
|---|---|---|
OrmPersistenceSupportCapability | OrmPersistenceSupportCapability | The resolved persistence support capability instance. |
is_soft_delete_enabled ¶
is_soft_delete_enabled(interface_cls)
Determine whether soft-delete behavior is enabled for the given interface class.
Checks the interface's soft_delete capability first, then the model's _meta.use_soft_delete, and finally the interface's _soft_delete_default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[OrmInterfaceBase] | The interface class to evaluate. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool |
|
OrmLifecycleCapability is the class-creation capability behind generated ORM interfaces such as DatabaseInterface and read-only variants. Its pre_create(name=..., attrs=..., interface=..., base_model_class=...) hook collects Django models.Field attributes declared on the interface. The class creation path reaches that logic through OrmInterfaceBase.handle_custom_fields(); the lifecycle capability method that performs the inspection is describe_custom_fields(model). The hook extracts Meta.use_soft_delete and Meta.rules, builds a generated Django model class, builds a concrete interface subclass bound to that model, and installs attrs["Interface"], attrs["Factory"], and attrs["_interface_type"]. attrs["Factory"] may provide a custom factory definition; otherwise the nested interface.Factory definition is used. The returned tuple is the updated attrs mapping, the concrete OrmInterfaceBase[models.Model] subclass, and the generated model class. Extracting Meta.use_soft_delete and Meta.rules mutates the original nested Meta class by deleting those two attributes before the remaining Meta attributes are attached to the generated Django model.
post_create(new_class=..., interface_class=..., model=...) wires the created manager class back into the interface and model by setting interface_class._parent_class, model._general_manager_class, and the manager objects exposed as new_class.objects. When soft delete is enabled it also sets new_class.all_objects to a manager that includes inactive rows. A None model is a no-op for lifecycle compatibility.
OrmPersistenceSupportCapability centralizes ORM support helpers used by read, query, history, and mutation capabilities. get_database_alias() reads the interface database class attribute. get_manager(interface_cls, only_active=True) returns the selected Django manager, honoring the database alias and soft-delete state, and caches the active manager on the interface. get_queryset() returns get_manager(..., only_active=True).all(). get_payload_normalizer() binds a PayloadNormalizer to the interface model. get_field_descriptors() builds and caches descriptor metadata and accessors. Descriptor metadata is generated from concrete model fields, foreign keys, reverse one-to-one relations, many-to-many relations, and reverse one-to-many relations. Each descriptor contains metadata keys type, default, is_required, is_editable, and is_derived. Big-integer-like fields may add graphql_scalar. Direct and collection relations also add relation_kind="direct" or "collection" and filter_lookup when the relation can be used as a lookup root. Collection relations are exposed as <name>_list attributes and resolve to the related manager/queryset or to a filtered GeneralManager class when the related model has one. Collection descriptor names prefer the declared relation or related model name, then the Django accessor fallback, then relation-field-derived fallback names; if every candidate collides, DuplicateFieldNameError is raised. Descriptor construction expects the interface class to expose _model as a Django model class. A custom collection resolver is called with positional arguments (interface_instance, field_call, field_name), and resolver exceptions are not wrapped. GeneralManager-backed collection accessors raise MissingRelatedFieldsError only when no explicit relation lookup was supplied and no related field can be found at access time; multiple discovered related fields are all used as filter constraints. resolve_many_to_many() returns a related queryset for a many-to-many accessor; when the relation points through simple-history rows and the interface has a historical search_date, it returns the target history queryset as of that date, otherwise it returns live target rows filtered by related ids. Missing target relation metadata returns an empty queryset rather than raising. Invalid many-to-many accessor names raise AttributeError, and invalid interface model field names raise Django's FieldDoesNotExist. A dated relation read fails with HistoricalReadNotSupportedError (chained from HistoryNotSupportedError) when either membership history or target-row history is unavailable; it never falls back to current relation data. This remains true inside the scalar historical lookup buffer: a source row may be hydrated from the live table, but its many-to-many membership is resolved from the source history row at the effective date. Equal history_date values are broken by greatest history_id for both source and related rows.
Historical through-table columns are resolved from the concrete ManyToManyField source and reverse field metadata, including explicit through_fields; this preserves direction for asymmetric self-relations and custom through models with multiple foreign keys to the same model. Configured database aliases are applied independently to source membership and target history queries. When both querysets use the same alias, membership remains a lazy SQL subquery. A cross-alias relation instead materializes the membership ID list before querying target history because Django cannot execute a correct cross-database subquery.
Generated DatabaseInterface models register declared many-to-many fields with django-simple-history. Deployments must provision the resulting Historical<Model>_<field> through tables using the project's normal Django schema and migration workflow. Membership history is reliable only for changes recorded after that schema is rolled out: pre-rollout membership cannot be reconstructed or backfilled from scalar history alone. A generated relation whose custom through model is still an unresolved string during owner-model creation is not auto-registered for history; define and track that through model explicitly if its membership must support historical reads.
OrmReadCapability.get_data(interface_instance) returns the live model row for pk or, when search_date is older than the interface historical_lookup_buffer_seconds, the matching historical row. It caches reads inside the active calculation run using interface class, primary key, database alias, active/all manager choice, and search date. Missing rows propagate the generated model's DoesNotExist.
OrmHistoryCapability is the history helper used by ORM read/query support. get_historical_record(interface_cls, instance, search_date=None) resolves the primary key from instance.pk, then instance.id, then instance.identification["id"]; it prefers instance.history when present, otherwise falls back to interface_cls._model.history. When search_date is provided it filters with history_date__lte=search_date, orders by history_date and history_id, applies any configured database alias, and returns the latest historical model row or None. get_history_queryset_for_manager() returns the model history queryset scoped to a manager-like object's primary key and raises HistoryNotSupportedError when the model has no history manager or the manager cannot be identified; it applies any configured database alias before returning the filtered queryset. get_historical_queryset(interface_cls, search_date) applies any configured database alias and selects the latest non-deletion history row per object at or before search_date, using history_id to break same-timestamp ties. It raises HistoryNotSupportedError when history is unavailable. get_historical_record_by_pk() filters id=pk, history_date__lte=search_date and returns None when search_date is None, history is unavailable, or no row matches.
OrmQueryCapability.filter() and exclude() normalize payloads through the ORM payload normalizer, translate snake_case reverse-relation aliases, honor include_inactive, and accept search_date as either date or datetime. Dates are converted to midnight datetimes and then normalized through OrmInterfaceBase.normalize_search_date(). Invalid search_date inputs raise SearchDateInputError before normalization, and custom normalizers that return non-datetimes raise SearchDateNormalizationError. The visible InvalidSearchDateTypeError is a compatibility exception for custom validators that want to raise a message-bearing type; the built-in query path uses the two more specific errors above. Historical querysets require the history capability; otherwise HistoryNotSupportedError is raised. Ambiguous reverse aliases raise AmbiguousReverseFilterAliasError.
OrmReadCapability.get_field_type(name) returns a type object: the Django field class for stored fields, the related manager class for GeneralManager-backed relations, or the synthetic descriptor metadata "type" value. Unknown names raise Django's FieldDoesNotExist.
DjangoManagerSelector(model, database_alias, use_soft_delete, cached_active=None) is the public ORM utility that chooses Django managers for ORM-backed capability reads. active_manager() returns the model default manager when soft delete is disabled or when the model exposes an all_objects attribute by presence check; otherwise it reuses cached_active as-is or creates and caches a lightweight manager whose queryset filters is_active=True. all_manager() returns the all_objects attribute value only when soft delete is enabled and the attribute exists; otherwise it returns the default manager. The selector does not validate that all_objects or cached_active is a manager or belongs to model. A truthy database_alias rebinds the selected source manager through manager.db_manager(alias) on each call, while None and "" leave the original manager unchanged. The selector caches only the unaliased generated or caller-supplied active-manager source, not the aliased result. The generated active manager starts from the model default manager queryset and preserves aliases applied through db_manager(). The selector does not query the database by itself and has no global cache. Missing or malformed manager attributes and db_manager() failures propagate unchanged at the point the selector reads or uses them.
discard_orm_instance_cache(interface_cls, pk) clears cached ORM reads for one interface class and primary key inside the active calculation run. It is a no-op when no calculation run context is active and returns None.
OrmMutationCapability owns shared write helpers. assign_simple_attributes() sets normalized non-many-to-many values on a Django model instance, skips models.NOT_PROVIDED, wraps assignment ValueError as InvalidFieldValueError, and wraps assignment TypeError as InvalidFieldTypeError. save_with_history() sets _history_user for simple-history when the model does not expose changed_by, sets changed_by_id when the model has that field, runs full_clean(), saves inside an atomic transaction using the interface database alias when configured, returns the saved primary key, and applies history_comment with simple-history after the save. apply_many_to_many() expects normalized <relation>_id_list entries, strips the suffix to find the relation manager, calls .set(values), and applies the history comment again after relation updates.
OrmCreateCapability.create(interface_cls, **payload) is the capability-level implementation behind manager creation. Positional arguments are accepted only for signature compatibility and are ignored. The payload may contain reserved metadata keys creator_id and history_comment; other keys are validated as model fields/attributes or many-to-many aliases such as <relation>_id_list. The capability removes the metadata keys, validates and normalizes the remaining payload through the validation/support normalizer, creates the model instance, saves it, and applies many-to-many updates in one alias-aware transaction before returning {"id": pk}. Validation, save, history-reason, relation, and transaction errors propagate and roll back that unit. The GeneralManager layer consumes that result and returns the public manager instance from Manager.create(...).
OrmUpdateCapability.update() loads the target row by pk with inactive rows included, ignores positional arguments, applies the same normalization/save/many-to-many transaction, discards the run-scoped ORM read cache only after that transaction succeeds, and returns the capability result {"id": pk}. Inside a caller-owned transaction on the same alias, ORM reads bypass the run-scoped identity cache so uncommitted rows are not published into it. After rollback, callers should reconstruct any in-place-updated manager from its ID. The GeneralManager layer consumes that result, refreshes the public manager state, and returns the same manager instance from manager.update(...).
OrmDeleteCapability.delete() loads the row with inactive rows included and ignores positional arguments. It accepts only the reserved metadata keys creator_id and history_comment; other keyword arguments are currently ignored by this capability. With soft delete enabled it requires activation support, sets is_active=False, saves with a deactivation history comment, clears the read cache, and returns {"id": pk}. Without soft delete it sets history actor metadata, applies a deletion change reason, hard-deletes in an atomic transaction using the configured database alias, clears the read cache, and returns {"id": pk}. The GeneralManager layer consumes that result and invalidates the public manager instance for later field reads. Missing activation support raises MissingActivationSupportError; queryset .get(), validation, transaction, delete, many-to-many, history, cache invalidation, and observability errors propagate unchanged.
OrmValidationCapability.normalize_payload() validates payload keys, splits many-to-many values, normalizes manager-valued foreign keys to identifiers, and returns (simple_payload, many_to_many_payload). The many-to-many payload keeps <relation>_id_list keys after normalization; apply_many_to_many() strips that suffix before resolving the relation manager. MutationPayload is dict[str, object], ManyToManyPayload is dict[str, list[object]], and MutationResult is dict[str, object] because primary keys and payload values may be non-integer and heterogeneous. Unknown fields raise UnknownFieldError from the payload normalizer.
PayloadNormalizer is the model-bound helper used by ORM query and mutation capabilities. normalize_filter_kwargs(kwargs) returns a new mapping and unwraps manager-valued filter values to their underlying ORM instance when one is cached on the manager interface, otherwise to identification["id"]. Here "manager-valued" means an actual GeneralManager instance. If the manager has malformed identification state, such as a missing "id", the underlying exception propagates. validate_keys(kwargs) accepts model attributes from vars(model) (including descriptors, properties, methods, and other class attributes), names from model._meta.get_fields() (including forward and reverse Django relations), and many-to-many aliases. The canonical many-to-many write alias is <relation>_id_list; the GraphQL-facing <relation>_list spelling is also accepted only when the base relation is an actual local many-to-many field. Unknown keys raise UnknownFieldError.
split_many_to_many(kwargs) mutates and returns the provided mapping: matching many-to-many aliases are removed from the first returned mapping and placed in the second mapping under the canonical <relation>_id_list key. The first returned mapping is the same object passed in. Plain fields whose names merely end in _list are left untouched unless their base name is a real many-to-many relation. If both <relation>_list and <relation>_id_list are present, iteration order decides the last canonical value stored in the many-to-many mapping.
split_many_to_many_non_mutating(kwargs) returns new simple and many-to-many mappings without changing kwargs. It uses the same many-to-many alias recognition, canonical <relation>_id_list output keys, plain _list field preservation, and insertion-order collision behavior as the mutating split_many_to_many() helper.
normalize_simple_values(kwargs) returns a new mapping. It converts manager-valued foreign-key/one-to-one values to identifiers and renames unsuffixed relation keys to <relation>_id; raw non-model values for those forward ForeignKey and OneToOneField names are also sent to the <relation>_id key so Django receives an identifier assignment. Reverse relations, generic relations, and many-to-many fields are not renamed by this method. If both a relation key and its <relation>_id key appear, the later normalized key overwrites the earlier value according to input iteration order. normalize_many_values(kwargs) also returns a new mapping and preserves input keys exactly. It skips None and models.NOT_PROVIDED, treats strings and bytes as scalar one-item assignments, expands other iterables, consumes generators once, treats dictionaries as iterables over their keys, and resolves manager-like items to identification["id"] while preserving unrecognized values. Call split_many_to_many() or split_many_to_many_non_mutating() first when canonical many-to-many keys are required.
SoftDeleteCapability stores the effective soft-delete state for an interface. During setup it prefers _soft_delete_default, then _model._meta.use_soft_delete, and otherwise keeps the capability's configured default. is_soft_delete_enabled() checks the capability first, then model metadata, then _soft_delete_default.
The public custom-field helper exposed through OrmInterfaceBase returns two lists: discovered Django field names and ignore markers for the generated backing attributes, currently <field>_value and <field>_unit. Rules attached through Meta.rules are installed on the generated model metadata and used by the generated full_clean() hook. Lifecycle errors are intentionally not wrapped and GeneralManager does not promise stable lifecycle wrapper exception types here: invalid Django fields, invalid model bases, invalid nested Meta attributes, factory class construction errors, rule setup errors, custom-field-discovery errors, and support-capability lookup errors propagate from Django, factory_boy, rule construction, custom field code, or the support capability that raised them.
OrmInterfaceBase._from_trusted_orm_instance() is internal even though it is visible in generated API reference pages. It is only for framework-owned rows loaded by the interface's Django ORM query paths, not for API, GraphQL, import, factory, or other user payloads. When a subclass overrides __init__, trusted hydration calls that constructor as cls(pk) or cls(pk, search_date=...). For subclasses using the base initializer, the hook bypasses construction and installs the trusted row, {"id": pk} identification, primary key, and normalized search date directly.
general_manager.interface.capabilities.read_only ¶
Public read-only capability exports.
The package-level surface is intentionally limited to capability classes and patchable observability hooks used by application setup and tests. Database transaction helpers stay private to the management implementation.
Exports
ReadOnlyLifecycleCapability: Lifecycle capability that configures read-only interfaces during manager class creation. ReadOnlyManagementCapability: Management capability that validates schema state and synchronizes bound read-only data. ReadOnlyLogger: Minimal logger protocol used by read-only management. ReadOnlyObservabilityHook: Callable protocol for replacing the package-level observability wrapper. ReadOnlyEnsureSchemaOperation: Literal operation for schema checks. ReadOnlySyncDataOperation: Literal operation for data sync. ReadOnlyObservabilityOperation: Stable read-only observability operation names. ReadOnlyEnsureSchemaObservabilityEvent: Paired schema operation and payload. ReadOnlySyncObservabilityEvent: Paired sync operation and payload. ReadOnlyObservabilityPayload: Union of read-only observability payload schemas. ReadOnlySchemaObservabilityPayload: Payload schema emitted by schema checks. ReadOnlySyncObservabilityPayload: Payload schema emitted by data sync. logger: Package-level ReadOnlyLogger patch point. Management resolves this name at log time, so replacing read_only.logger affects subsequent schema and synchronization logs. with_observability: Observability wrapper patch point used by read-only management. Management resolves this callable at runtime through the package, so replacing read_only.with_observability affects subsequent schema-check and sync calls.
ReadOnlyObservabilityTarget module-attribute ¶
ReadOnlyObservabilityTarget = type[object]
Read-only interface class passed to observability hooks.
The alias stays broad so dynamic interface classes and test doubles can be used without importing ORM base classes into the package surface.
ReadOnlyLogger ¶
Bases: Protocol
Minimal logger shape consumed by read-only management patches.
debug ¶
debug(msg, *args, context=None, **kwargs)
Log diagnostic details with optional structured context.
info ¶
info(msg, *args, context=None, **kwargs)
Log sync summaries with optional structured context.
warning ¶
warning(msg, *args, context=None, **kwargs)
Log schema or sync warnings with optional structured context.
ReadOnlySchemaObservabilityPayload ¶
Bases: TypedDict
Payload emitted for read_only.ensure_schema observability events.
ReadOnlySyncObservabilityPayload ¶
Bases: TypedDict
Payload emitted for read_only.sync_data observability events.
ReadOnlyLifecycleCapability dataclass ¶
Bases: OrmLifecycleCapability
Configure generated read-only managers for soft-delete synchronization.
pre_create ¶
pre_create(*, name, attrs, interface, base_model_class)
Force read-only model generation onto the soft-delete base model.
Read-only synchronization uses inactive rows to represent payload rows that disappeared from _data. This hook creates a nested Meta class when the interface does not define one, overwrites Meta.use_soft_delete to True even when it was explicitly False, ignores the caller-supplied base_model_class, and delegates to the ORM lifecycle with GeneralManagerBasisModel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | str | Name used for the generated model, factory, and manager lifecycle artifacts. | required |
attrs | dict[str, object] | Class namespace for the new manager. This mapping is passed to the parent ORM lifecycle, which mutates and returns it with generated interface, factory, and interface-type entries. | required |
interface | type['OrmInterfaceBase[models.Model]'] | ORM interface class to configure; for normal use this is a | required |
base_model_class | type[GeneralManagerBasisModel] | Ignored by this capability; read-only managers always delegate with | required |
Returns:
| Type | Description |
|---|---|
dict[str, object] | The updated manager namespace, concrete interface subclass, and |
type['OrmInterfaceBase[models.Model]'] | generated read-only model class returned by the ORM lifecycle. |
Raises:
| Type | Description |
|---|---|
Exception | Specific exceptions are defined by the downstream component that raises them. Invalid interface attributes, Django model fields, Meta options, factory definitions, rule setup, support-capability lookup, or custom-field discovery errors propagate unchanged from the ORM lifecycle or the code that raised them. |
post_create ¶
post_create(*, new_class, interface_class, model)
Register the newly created manager class as a read-only class in GeneralManagerMeta.
Runs the ORM post-create lifecycle first so the manager, interface, and generated model are linked. It then appends new_class to GeneralManagerMeta.read_only_classes when the exact class object is not already present, which lets startup hooks discover read-only managers for schema checks and data synchronization. When model is None, the ORM post-create lifecycle returns without linking model state, but this capability still registers the class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_class | type['GeneralManager'] | Newly created | required |
interface_class | type['OrmInterfaceBase[models.Model]'] | Concrete ORM interface class, normally a read-only interface bound to the generated model. | required |
model | type['GeneralManagerBasisModel'] | None | Generated ORM model class, or | required |
Raises:
| Type | Description |
|---|---|
Exception | Specific exceptions are defined by the downstream component that raises them. Errors from ORM post-create linking, manager lookup, or soft-delete manager setup propagate unchanged before registry mutation. |
ReadOnlyObservabilityHook ¶
Bases: Protocol
Callable shape expected for read_only.with_observability patches.
The default hook creates one shallow copy of payload for the event and passes that same copy to every callback. It calls before_operation before func; if that callback raises, func is not called. It calls on_error only when func raises; if on_error raises, that exception replaces the original func exception. It calls after_operation only after func succeeds; if after_operation raises, that exception replaces the successful return. Otherwise it returns func's result. Production replacement hooks should call func exactly once and return its result. Test hooks may intentionally skip, repeat, or fail the operation to simulate edge cases. Mutating a patched hook's received payload does not affect read-only management after the hook call because the payload is used only for that observability event. Async functions are not awaited; an awaitable returned by func is returned as-is.
Raises:
| Type | Description |
|---|---|
Exception | Re-raises exceptions from |
The general_manager.interface.capabilities.read_only package is the supported package-level import surface for read-only capability classes: ReadOnlyLifecycleCapability and ReadOnlyManagementCapability. It also exposes ReadOnlyLogger, ReadOnlyObservabilityHook, ReadOnlyEnsureSchemaOperation, ReadOnlySyncDataOperation, ReadOnlyObservabilityOperation, ReadOnlyEnsureSchemaObservabilityEvent, ReadOnlySyncObservabilityEvent, ReadOnlyObservabilityPayload, ReadOnlyObservabilityTarget, ReadOnlySchemaObservabilityPayload, ReadOnlySyncObservabilityPayload, logger, and with_observability through __all__ as patch points and type helpers for tests or advanced instrumentation. The private _compat.call_with_observability() helper exists only to make read-only management resolve the package-level hook at call time; import with_observability from the package instead.
ReadOnlyLifecycleCapability is the lifecycle hook behind ReadOnlyInterface. During class creation it adds a nested Meta class when needed, overwrites Meta.use_soft_delete = True even when a subclass set it to False, ignores any caller-supplied model base, and delegates model generation to the ORM lifecycle with GeneralManagerBasisModel. The class-creation namespace is passed through the ORM lifecycle, which mutates and returns it with the generated interface, factory, and interface-type entries. After class creation it runs the ORM post-create linking first, then registers the new manager in GeneralManagerMeta.read_only_classes when that exact class object is not already present, so startup hooks can find it for schema checks and synchronization. If the upstream lifecycle supplies model=None, ORM linking returns without attaching model state, but the read-only class is still registered. Lifecycle exceptions are not wrapped: invalid Django fields or Meta options, factory or rule construction errors, custom-field discovery failures, support-capability lookup failures, and ORM manager setup errors propagate from the component that raised them.
logger is a GeneralManagerLoggerAdapter. Test doubles can follow ReadOnlyLogger: a minimal protocol with debug(), info(), and warning() methods that accept a message, positional logging arguments, and an optional context mapping keyword. Read-only management resolves general_manager.interface.capabilities.read_only.logger at log time, so patching that package-level name affects subsequent schema and sync logs.
ReadOnlyObservabilityHook is the replacement protocol for with_observability: a synchronous callable accepting a target, keyword-only operation, payload, and func, and returning the result of func. ReadOnlyObservabilityTarget is type[object]; read-only management passes the read-only interface class, and the alias stays broad so dynamically generated interfaces and test doubles are accepted without importing ORM base classes into the package surface. Production replacement hooks should call func exactly once and return its result. Test hooks may intentionally skip, repeat, or fail the operation to simulate edge cases. The default hook creates one shallow copy of payload for the event and passes that same copy to every callback. It calls before_operation before func; if before_operation raises, func is not called. It calls on_error only when func raises; if on_error raises, that exception replaces the original func exception. It calls after_operation only after func succeeds; if after_operation raises, that exception replaces the successful return. Otherwise the hook returns func's result. A patched hook receives the management payload dictionary directly. It may mutate that per-event dictionary during the call, but should not retain it for later mutation; read-only management treats the payload as disposable after the hook returns and does not read it again. Async functions are not awaited by this wrapper; an awaitable returned by func is returned as-is. Read-only management resolves the hook from the package at call time, so patching general_manager.interface.capabilities.read_only.with_observability affects subsequent schema-check and sync calls.
Default observability callbacks have the same keyword shape used by the shared observability capability: before_operation(operation=..., target=..., payload=...), after_operation(operation=..., target=..., payload=..., result=...), and on_error(operation=..., target=..., payload=..., error=...).
general_manager.interface.capabilities.core.with_observability(target, operation=..., payload=..., func=...) is the shared wrapper used by capability packages. It accepts any mapping-shaped payload, copies it once to a dict for hook calls, and executes func directly when the target has no get_capability_handler() method or no observability capability. When a capability is present, it calls non-None optional hooks only: it calls before_operation before func, calls on_error only if func raises, re-raises the original exception unless the error hook raises, and calls after_operation only after successful completion. If before_operation raises, func is not called. Hook exceptions are not wrapped.
LoggingObservabilityCapability is registered as the "observability" capability and writes structured debug/error log events for interface operations through the "interface.observability" logger. The start, end, and error event messages are "interface operation start", "interface operation end", and "interface operation error". Each call passes the structured metadata as the logger keyword argument context=.... Context contains operation, the target name (target.__name__ when that attribute is a string, otherwise the target class name; AttributeError from __name__ lookup is treated as missing), sorted payload_keys, and selected payload metadata keys: service, method, path, status_code, retry_count, and request_id. Selected payload keys are included whenever the key is present, including when the value is None. End events add result_type as the simple runtime type name and copy status_code, retry_count, and request_id from result.metadata when that metadata is a collections.abc.Mapping; missing metadata attributes and non-mapping metadata values are ignored, and AttributeError from metadata lookup is treated as missing metadata. Result metadata keys are included whenever present, including None, and replace same-named payload values in the end-event context. Error events add error=repr(error), error_class=type(error).__name__, and status_code from error.status_code when that attribute exists, including when the value is None; missing status_code and AttributeError from status_code lookup are ignored. Logger construction, non-AttributeError target-name lookup failures, payload-key sorting, payload/result metadata access, non-AttributeError error status lookup failures, and logger call errors propagate unchanged.
Calculation capabilities use the same package-level replacement pattern for general_manager.interface.capabilities.calculation.with_observability. Query operations resolve that hook at call time with the calculation interface class as target, a payload dictionary, and one of these operation labels: "calculation.query.filter" with {"kwargs": dict(kwargs)}, "calculation.query.exclude" with {"kwargs": dict(kwargs)}, or "calculation.query.all" with {}. Lifecycle hooks emit "calculation.pre_create" with the user-declared interface class as target and {"interface": interface.__name__, "name": name}. They emit "calculation.post_create" with the generated interface class as target and {"interface": interface_class.__name__}. The default hook copies the payload before calling callbacks, executes func once, returns its result, and propagates callback or operation exceptions using the callback ordering described above.
ReadOnlyObservabilityOperation is the literal union "read_only.ensure_schema" | "read_only.sync_data", and ReadOnlyObservabilityPayload is the union of the two payload schemas below. ReadOnlyObservabilityHook overloads pair each operation literal with the matching payload schema for type checkers. Schema checks emit operation="read_only.ensure_schema" with ReadOnlySchemaObservabilityPayload: manager is the manager class name string and model is the Django model class name string. The paired event alias is ReadOnlyEnsureSchemaObservabilityEvent. Data sync emits operation="read_only.sync_data" with ReadOnlySyncObservabilityPayload: manager and model are the bound class name strings when present, otherwise None, and schema_validated is the boolean flag passed to sync_data(). The paired event alias is ReadOnlySyncObservabilityEvent.
from collections.abc import Callable
from typing import TypeVar
from general_manager.interface.capabilities.read_only import (
ReadOnlyObservabilityOperation,
ReadOnlySchemaObservabilityPayload,
ReadOnlySyncObservabilityPayload,
)
ResultT = TypeVar("ResultT")
def traced_read_only_hook(
target: type[object],
*,
operation: ReadOnlyObservabilityOperation,
payload: ReadOnlySchemaObservabilityPayload | ReadOnlySyncObservabilityPayload,
func: Callable[[], ResultT],
) -> ResultT:
return func()
The read_only.management module below is documented as capability reference material. Its imported Django transaction module is not exported from read_only and is not package-level API. Patching general_manager.interface.capabilities.read_only.management.django_transaction is a private test escape hatch for replacing database transaction behavior, not a supported application extension point.
ReadOnlyManagementCapability.get_unique_fields(model) inspects Django model metadata to find the fields used to reconcile incoming _data rows with database rows. It includes fields marked unique=True, unique_together entries, and UniqueConstraint.fields, excluding the primary key named id. When a unique field is the concrete value column behind a MeasurementField, the method returns the public measurement descriptor name instead. If two measurement descriptors point at the same concrete value column, it raises ValueError; if the model has no _meta, it returns an empty set. The return value is intentionally a flat set. When several unique declarations exist, sync_data() uses the union of their fields as one composite identity and requires every field in that union on each payload row.
ensure_schema_is_up_to_date(interface_cls, manager_cls, model, *, connection=None) checks the bound model against the database table before read-only sync. It returns Django system-check Warning objects for missing model metadata, missing db_table, a missing database table, or mismatched local concrete column names. It compares column presence only: field types, nullability, defaults, indexes, generated columns, many-to-many through tables, and inherited fields outside the model's local concrete field list are not validated. A clean schema returns an empty list. Database introspection errors and read-only observability hook errors propagate unchanged.
sync_data(interface_cls, *, connection=None, transaction=None, integrity_error=None, json_module=None, logger_instance=None, unique_fields=None, schema_validated=False) synchronizes the parent manager's _data payload into the read-only model. _data may be a JSON string that decodes to a list or an in-memory list of row dictionaries. Unique fields are either supplied explicitly or discovered through get_unique_fields(). The sync creates missing rows, updates editable local fields, applies many-to-many assignments after save, reactivates matched soft-deleted rows, and sets previously active rows inactive when their unique identifier is absent from the payload. Omitted editable scalar fields are left unchanged on existing rows and excluded from create payloads. Omitted many-to-many fields are left unchanged; a present value of None clears the relation and a present list replaces it. Relation values may be lookup dictionaries; nested dictionaries are flattened into Django __ lookups and must match exactly one related row or ReadOnlyRelationLookupError is raised. Many-to-many relation payloads must be lists of lookup dictionaries or identifiers.
When schema_validated is false, sync_data() first calls ensure_schema_is_up_to_date() and logs then aborts without writes if warnings are returned. It also has a conservative fast path that fingerprints the active database rows and payload rows and skips the transaction when comparable local non-relation, non-measurement fields already match the payload fields present on each row. Related read-only interfaces sync before the local transaction, each through its own sync_data() call; recursive cycles are skipped by an in-progress stack. Public failures include MissingReadOnlyBindingError, MissingReadOnlyDataError, InvalidReadOnlyDataTypeError, InvalidReadOnlyDataFormatError, MissingUniqueFieldError, ReadOnlyRelationLookupError, the configured integrity error class, database errors, logger errors, and observability hook errors.
get_startup_hooks(interface_cls) returns a single startup callable when the interface is already bound to a parent manager and model. That callable runs sync_data() and suppresses only MissingReadOnlyBindingError, because binding metadata can become unavailable between hook registration and startup execution. When the interface is not bound at registration time, it returns an empty tuple instead of a no-op callable. get_system_checks(interface_cls) returns a callable that delegates to ensure_schema_is_up_to_date() when binding metadata is available and returns an empty list otherwise; observability and introspection errors propagate from the returned callable once binding is present. get_startup_hook_dependency_resolver(interface_cls) returns a resolver that orders read-only startup sync after direct read-only dependencies referenced by non-auto-created relation fields, including foreign-key, one-to-one, and many-to-many fields. The resolver inspects the class passed to the resolver; transitive dependencies and cycle handling are handled by the startup runner.
general_manager.interface.capabilities.read_only.management ¶
Capabilities that power ReadOnlyInterface behavior.
ReadOnlyManagementCapability dataclass ¶
Bases: BaseCapability
Provide schema verification and data-sync behavior for read-only interfaces.
get_startup_hook_dependency_resolver ¶
get_startup_hook_dependency_resolver(interface_cls)
Return a resolver function that identifies read-only interfaces which must run before a given interface's startup hook.
The returned resolver inspects the interface class passed to the resolver, not the interface_cls argument captured here. It reports direct read-only dependencies referenced by non-auto-created relation fields, including foreign-key, one-to-one, and many-to-many fields. Transitive dependencies and cycle handling are left to the startup hook runner.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | _ReadOnlyInterface | The interface class for which to obtain a startup-hook dependency resolver. | required |
Returns:
| Type | Description |
|---|---|
Callable[[type[object]], set[type[object]]] | A callable that, when invoked with an interface class, returns a set of read-only interface classes that should be executed prior to that interface's startup hook. |
get_unique_fields ¶
get_unique_fields(model)
Gather candidate unique field names declared on the Django model, remapping measurement-backed fields to their public attribute names.
Includes fields marked unique=True, fields listed in unique_together (or equivalent tuple/list/set entries), and fields referenced by UniqueConstraint definitions. Excludes the primary key named "id". If multiple unique declarations exist, the returned flat set is their union; sync_data() treats every returned field as part of one composite row identity. If the model has no _meta, returns an empty set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model | type[Model] | Django model class whose unique declarations should be inspected. | required |
Returns:
| Type | Description |
|---|---|
set[str] | A set of unique field names with |
Raises:
| Type | Description |
|---|---|
ValueError | If two |
ensure_schema_is_up_to_date ¶
ensure_schema_is_up_to_date(
interface_cls, manager_cls, model, *, connection=None
)
Verify that the Django model's declared column names match the actual database table and return schema-related warnings.
Performs the following checks and returns corresponding Django Warning objects when applicable: - Model metadata (_meta) is missing. - db_table is not defined on the model meta. - The named database table does not exist. - The table's column names differ from the model's local concrete field column names (missing or extra columns).
Field types, nullability, defaults, indexes, generated columns, many-to-many through tables, and inherited fields outside the local concrete field list are not compared.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | _ReadOnlyInterface | Read-only interface class passed to observability hooks. | required |
manager_cls | type['GeneralManager'] | Manager class used in warning hints and observability payloads. | required |
model | type[Model] | Django model class whose database table should be checked. | required |
connection | _SchemaConnection | None | Database connection to use for introspection. If omitted, the default Django connection is used. | None |
Returns:
| Type | Description |
|---|---|
list[Warning] | A list of Django system-check |
Raises:
| Type | Description |
|---|---|
Exception | Propagates database introspection errors and read-only observability hook exceptions without wrapping. |
sync_data ¶
sync_data(
interface_cls,
*,
connection=None,
transaction=None,
integrity_error=None,
json_module=None,
logger_instance=None,
unique_fields=None,
schema_validated=False
)
Synchronize the interface's bound read-only JSON data into the underlying Django model, creating, updating, and deactivating records to match the input.
Parses the read-only payload defined on the interface's parent class, enforces a set of unique identifying fields to match incoming items to existing rows, writes only model-editable fields that are present in each payload row, marks matched records active, creates missing records, and deactivates previously active records not present in the incoming data. If schema validation is enabled (or performed), aborts when schema warnings are detected.
When unique_fields is omitted, get_unique_fields() supplies a flat union of all unique declarations and every field in that union is required in each payload row. Omitted editable scalar fields are left unchanged on existing rows and are not included in create payloads. Omitted many-to-many fields are left unchanged; a present value of None clears the relation and a present list replaces it. Related read-only interfaces sync before the local transaction, each through its own sync_data() call, and recursive cycles are skipped by the in-progress guard.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | _ReadOnlyInterface | Read-only interface class whose parent class must expose | required |
connection | _SchemaConnection | None | Django DB connection to use instead of the default. | None |
transaction | _TransactionModule | None | Django transaction management object with an | None |
integrity_error | type[BaseException] | None | Exception class to treat as a DB integrity error (defaults to Django's IntegrityError). | None |
json_module | _JsonLoader | None | JSON-like parser with | None |
logger_instance | ReadOnlyLogger | None | Logger to record sync results; falls back to the capability's resolved logger. | None |
unique_fields | set[str] | None | Explicit set of field names to use as the unique identifier for items; when omitted, the model's unique metadata is used. | None |
schema_validated | bool | When True, skip runtime schema validation; when False, ensure_schema_is_up_to_date is called before syncing and the sync is aborted if warnings are returned. | False |
Raises:
| Type | Description |
|---|---|
MissingReadOnlyBindingError | If the interface is not bound to both a parent manager and a model. |
MissingReadOnlyDataError | If the parent manager has no |
InvalidReadOnlyDataTypeError | If |
InvalidReadOnlyDataFormatError | If JSON does not decode to a list, many-to-many data is not a list, or an item misses a required unique field. |
MissingUniqueFieldError | If no unique fields can be determined or supplied. |
ReadOnlyRelationLookupError | If a relation lookup dictionary matches zero or multiple related records. |
BaseException | Propagates the configured |
get_startup_hooks ¶
get_startup_hooks(interface_cls)
Provide a startup hook that triggers read-only data synchronization for the given interface.
If the interface is not bound to both a parent manager and model when hooks are requested, no hook is registered and an empty tuple is returned. The registered hook catches MissingReadOnlyBindingError only to tolerate binding metadata becoming unavailable between registration and startup execution; other sync errors propagate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | _ReadOnlyInterface | Interface class used to derive the bound manager and model. | required |
Returns:
| Type | Description |
|---|---|
Callable[[], None] | A one-element tuple containing a callable that runs synchronization when invoked, |
... | or an empty tuple if the interface lacks the necessary manager/model metadata. The callable invokes the capability's |
tuple[Callable[[], None], ...] | sync logic and silently skips if the read-only binding is not yet available. |
get_system_checks ¶
get_system_checks(interface_cls)
Provide a system check function that validates the read-only model schema against the database.
Missing parent-manager or model binding is intentionally silent and returns an empty warning list from the check callable. Once binding is present, schema warnings and propagated introspection or observability errors follow ensure_schema_is_up_to_date().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | _ReadOnlyInterface | The read-only interface class whose binding (parent manager and model) will be inspected. | required |
Returns:
| Type | Description |
|---|---|
tuple[Callable[[], list[Warning]], ...] | A tuple containing a single callable. When invoked, the callable returns a list of |
general_manager.interface.capabilities.calculation.lifecycle ¶
Capabilities tailored for calculation interfaces.
CalculationReadCapability dataclass ¶
Bases: BaseCapability
Calculations expose inputs only and never persist data.
get_data ¶
get_data(interface_instance)
Reject persisted-data access for calculation interface instances.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_instance | 'CalculationInterface' | Calculation interface instance whose stored data was requested. The value is accepted for capability compatibility and is not inspected. | required |
Raises:
| Type | Description |
|---|---|
NotImplementedError | Always raised because calculation managers are derived from their inputs and do not have backing storage. |
get_attribute_types ¶
get_attribute_types(interface_cls)
Build metadata for each declared calculation input.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['CalculationInterface'] | Calculation interface class whose collected | required |
Returns:
| Type | Description |
|---|---|
dict[str, dict[str, object]] | Mapping from input name to metadata rows with the exact keys |
dict[str, dict[str, object]] |
|
dict[str, dict[str, object]] | and |
dict[str, dict[str, object]] |
|
dict[str, dict[str, object]] |
|
get_attributes ¶
get_attributes(interface_cls)
Create lazy input accessors for a calculation interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['CalculationInterface'] | Calculation interface class whose | required |
Returns:
| Type | Description |
|---|---|
dict[str, Callable[['CalculationInterface'], object]] | Mapping from input name to a callable. Each callable resolves |
dict[str, Callable[['CalculationInterface'], object]] | declared dependencies first, casts the raw value from the instance's |
dict[str, Callable[['CalculationInterface'], object]] |
|
dict[str, Callable[['CalculationInterface'], object]] | instance, and returns the typed value as |
dict[str, Callable[['CalculationInterface'], object]] | identification keys are passed to |
dict[str, Callable[['CalculationInterface'], object]] | required-input enforcement is handled by separate validation, not |
dict[str, Callable[['CalculationInterface'], object]] | by this accessor. |
Raises:
| Type | Description |
|---|---|
KeyError | Propagated from missing dependency names or field names. |
TypeError | Propagated from input casting callbacks with incompatible signatures or values. |
ValueError | Propagated from input normalization/parsing failures. |
get_field_type ¶
get_field_type(interface_cls, field_name)
Return the declared Python type for one calculation input.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['CalculationInterface'] | Calculation interface class containing | required |
field_name | str | Name of the input field to look up. | required |
Returns:
| Type | Description |
|---|---|
type[object] | The Python type declared on the input field. |
Raises:
| Type | Description |
|---|---|
KeyError | If |
CalculationQueryCapability dataclass ¶
Bases: BaseCapability
Expose CalculationBucket helpers via the generic query capability.
filter ¶
filter(interface_cls, **kwargs)
Create a filtered calculation bucket for an interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['CalculationInterface'] | Calculation interface whose parent manager class is enumerated. | required |
**kwargs | object | Query filter parameters forwarded to | {} |
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManager] | Bucket representing calculation input combinations that match the |
CalculationBucket[GeneralManager] | provided filters. |
Raises:
| Type | Description |
|---|---|
InvalidCalculationInterfaceError | Propagated if the parent manager does not use a calculation interface. |
KeyError | Propagated from missing dependency values. |
TypeError | Propagated from invalid filter values, input domains, or callback signatures. |
ValueError | Propagated from input parsing, normalization, or filter value failures. |
exclude ¶
exclude(interface_cls, **kwargs)
Create a calculation bucket with matching combinations excluded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['CalculationInterface'] | Calculation interface whose parent manager class is enumerated. | required |
**kwargs | object | Exclusion criteria forwarded to | {} |
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManager] | Bucket representing calculation input combinations after matching |
CalculationBucket[GeneralManager] | combinations are removed. |
Raises:
| Type | Description |
|---|---|
InvalidCalculationInterfaceError | Propagated if the parent manager does not use a calculation interface. |
KeyError | Propagated from missing dependency values. |
TypeError | Propagated from invalid exclusion values, input domains, or callback signatures. |
ValueError | Propagated from input parsing, normalization, or filter value failures. |
all ¶
all(interface_cls)
Create a bucket for all calculation input combinations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type['CalculationInterface'] | Calculation interface whose parent manager class is enumerated. | required |
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManager] | Bucket representing every possible calculation input combination. |
Raises:
| Type | Description |
|---|---|
InvalidCalculationInterfaceError | Propagated if the parent manager does not use a calculation interface. |
KeyError | Propagated from missing dependency values. |
TypeError | Propagated from invalid input domain definitions or callback signatures. |
ValueError | Propagated from input parsing or normalization failures. |
CalculationLifecycleCapability dataclass ¶
Bases: BaseCapability
Manage calculation interface pre/post creation hooks.
pre_create ¶
pre_create(*, name, attrs, interface)
Collect calculation inputs and attach the generated interface class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | str | Declared manager class name, used only for observability payloads. | required |
attrs | dict[str, object] | Mutable manager-class attribute mapping. This method sets | required |
interface | type['CalculationInterface'] | User-declared calculation interface class. Only its own | required |
Returns:
| Type | Description |
|---|---|
dict[str, object] | Tuple of updated attrs, generated calculation interface subclass, |
type['CalculationInterface'] | and |
post_create ¶
post_create(*, new_class, interface_class, model=None)
Attach the concrete manager class to the generated interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_class | type[GeneralManager] | Concrete manager class just created. | required |
interface_class | type['CalculationInterface'] | Generated calculation interface class whose | required |
model | None | Reserved for lifecycle compatibility and ignored. | None |
ExistingModelResolutionCapability is the lifecycle capability behind ExistingModelInterface. resolve_model(interface_cls) reads interface_cls.model, accepts either a Django model class or an app-label string accepted by django.apps.apps.get_model() such as "app_label.ModelName" or settings.AUTH_USER_MODEL, stores the resolved class on interface_cls._model and interface_cls.model, and enables the soft-delete capability by default when the model exposes is_active. None, empty strings, unresolved lazy references, malformed strings, and non-model objects are invalid. Missing model configuration raises MissingModelConfigurationError; invalid strings or non-model references raise InvalidModelReferenceError.
ensure_history(model, interface_cls=None) registers database-aware django-simple-history for an untracked model and includes local many-to-many field names. A pre-existing tracker is accepted for the default alias. For a non-default interface alias, its generated history model must have GeneralManager's database-aware marker; otherwise UnsafeHistoryConfigurationError(model_name, interface_name, alias) is raised. The exception message is <model> must use DatabaseAwareHistoricalRecords before <interface> configures non-default database alias '<alias>'.. The records class and exception currently live in implementation modules and are not stable exports from general_manager.interface; this is a compatibility limitation of 0.63.1, not a promise of those direct import paths. Other registration errors from django-simple-history propagate. apply_rules(interface_cls, model) appends interface_cls.Meta.rules after any existing model._meta.rules and replaces model.full_clean with the GeneralManager rules-aware implementation. If no interface rules are declared, the method is a no-op. ensure_history() is idempotent once simple-history metadata exists; apply_rules() is not a deduplication boundary, so repeated calls append the interface rules again and repatch full_clean().
pre_create(name=..., attrs=..., interface=...) resolves the model, ensures history, applies rules, creates the concrete interface subclass, resets cached field descriptors, writes attrs["_interface_type"], attrs["Interface"], and attrs["Factory"], and returns (attrs, concrete_interface, model). A Factory class supplied on the manager attrs takes precedence over the interface Factory; public attributes from that definition and its nested Meta are copied into the generated AutoFactory, while Meta.model is always set to the resolved model. "Public attributes" means directly declared non-dunder attributes except Meta; inherited attributes are not copied, and descriptors, callables, and annotations present in the prototype __dict__ are copied as ordinary values. pre_create() repeats resolution, history, rule, and factory work each time it is called according to those helper contracts. post_create(new_class=..., interface_class=..., model=...) wires the generated manager class onto the interface and Django model, assigns new_class.objects, and when soft delete is enabled also exposes new_class.all_objects from ORM support with only_active=False. If the legacy model does not already expose an unfiltered all_objects, GeneralManager falls back to Django's _default_manager; that fallback mirrors the legacy model's default manager and is not guaranteed to include inactive rows when the legacy default manager filters them. A None model is a no-op for lifecycle compatibility. Errors from history registration, rule application, factory construction, class creation, manager wiring, ORM support lookup, and observability hooks propagate unchanged.
general_manager.interface.capabilities.existing_model.resolution ¶
Capabilities specialized for ExistingModelInterface.
ExistingModelResolutionCapability dataclass ¶
Bases: BaseCapability
Resolve and configure the Django model used by ExistingModelInterface.
resolve_model ¶
resolve_model(interface_cls)
Resolve and bind the Django model referenced by an ExistingModelInterface subclass.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | ExistingInterfaceClass | The interface class whose | required |
Returns:
| Type | Description |
|---|---|
type[Model] | type[models.Model]: The resolved Django model class. |
Raises:
| Type | Description |
|---|---|
MissingModelConfigurationError | If the interface has no |
InvalidModelReferenceError | If the |
Exception | Exceptions raised by the observability hook are not wrapped. |
ensure_history ¶
ensure_history(model, interface_cls=None)
Register simple history tracking for the given Django model if it is not already registered.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model | type[Model] | The Django model class to enable history tracking on. | required |
interface_cls | type['ExistingModelInterface'] | None | Optional interface class associated with the model; when provided, the registration is attributed to that interface. | None |
Raises:
| Type | Description |
|---|---|
Exception | Registration and observability hook exceptions are not wrapped. |
apply_rules ¶
apply_rules(interface_cls, model)
Apply the interface's Meta.rules to the Django model and wire a compatible full_clean method.
If the interface defines a Meta.rules sequence, this function appends those rules to any existing rules on model._meta and assigns the combined list back to model._meta.rules. It then replaces model.full_clean with a full-clean helper appropriate for the model. If no rules are defined on the interface, the model is left unchanged. Repeated calls append the interface rules again and replace full_clean again; the method is not a deduplication boundary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | type[ExistingModelInterface] | The interface class whose Meta.rules will be applied. | required |
model | type[Model] | The Django model to receive combined rules and a patched full_clean. | required |
Raises:
| Type | Description |
|---|---|
Exception | Invalid rule containers, full_clean patching errors, and observability hook exceptions are not wrapped. |
pre_create ¶
pre_create(*, name, attrs, interface)
Prepare and return attributes and types needed to create a concrete interface class tied to an existing Django model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | str | The name to use for the generated concrete interface and its factory. | required |
attrs | AttributeMap | Attribute mapping for the class being created; this mapping will be updated with keys such as "_interface_type", "Interface", and "Factory". | required |
interface | type[ExistingModelInterface] | The ExistingModelInterface subclass that defines the model reference and optional Factory to base the concrete interface on. | required |
Returns:
| Type | Description |
|---|---|
tuple[AttributeMap, ExistingInterfaceClass, type[Model]] | tuple[AttributeMap, ExistingInterfaceClass, type[models.Model]]: A tuple containing the (possibly mutated) attrs dict to use when creating the class, the generated concrete interface type (with its model wired), and the resolved Django model class. |
Raises:
| Type | Description |
|---|---|
MissingModelConfigurationError | If model resolution finds no model configuration. |
InvalidModelReferenceError | If model resolution receives an invalid reference. |
Exception | History registration, rule application, factory construction, class creation, and observability hook exceptions are not wrapped. Repeated calls repeat history/rule/factory work according to the helper methods' contracts. |
post_create ¶
post_create(*, new_class, interface_class, model)
Finalize wiring between the newly created concrete class, its interface, and the Django model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_class | type | The newly created concrete manager/class that will be attached to the interface and model. | required |
interface_class | type[ExistingModelInterface] | The interface class from which the concrete class was created. | required |
model | type[Model] | None | The resolved Django model associated with the interface, or | required |
Description
If a model is provided, attaches new_class as the interface's _parent_class and the model's _general_manager_class, assigns new_class.objects using the ORM persistence capability for the interface, and if soft-delete support is enabled, ensures the model exposes all_objects (falling back to _default_manager if missing) and assigns new_class.all_objects from the ORM support capability with only_active=False. If the legacy model does not already expose an unfiltered all_objects, the fallback mirrors Django's _default_manager; GeneralManager cannot guarantee that fallback is unfiltered when the legacy model's default manager filters rows.
Raises:
| Type | Description |
|---|---|
Exception | ORM support lookup, manager construction, generated class wiring, and observability hook exceptions are not wrapped. |
build_factory ¶
build_factory(
*, name, interface_cls, model, factory_definition=None
)
Create a concrete AutoFactory subclass configured for the given interface and Django model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name | str | Base name used to derive the generated factory class name (result will be "{name}Factory"). | required |
interface_cls | type[ExistingModelInterface] | The interface type the factory will produce instances for. | required |
model | type[Model] | The Django model that the factory's Meta.model should reference. | required |
factory_definition | type[object] | None | Optional prototype class whose directly declared non-dunder attributes are copied into the generated factory, except | None |
Returns:
| Type | Description |
|---|---|
type[AutoFactory[Model]] | type[AutoFactory]: A newly created AutoFactory subclass named "{name}Factory" with its |
Raises:
| Type | Description |
|---|---|
Exception | Invalid factory definitions, invalid nested Meta values, class creation errors, and AutoFactory metaclass errors are not wrapped. |
general_manager.interface.utils.errors.InvalidFieldValueError ¶
Bases: ValueError
Raised when model-field assignment rejects a value.
Used by writable ORM capabilities after Django/model assignment raises ValueError for a payload field.
__init__ ¶
__init__(field_name, value)
Build an error message for an invalid field value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field_name | str | Payload/model field name that rejected the value. | required |
value | object | Rejected value included in the message with | required |
general_manager.interface.utils.errors.InvalidFieldTypeError ¶
Bases: TypeError
Raised when model-field assignment rejects a value type.
Used by writable ORM capabilities after Django/model assignment raises TypeError for a payload field.
__init__ ¶
__init__(field_name, error)
Build an error message for a field type failure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field_name | str | Payload/model field name that rejected the value. | required |
error | TypeError | Original | required |
general_manager.interface.utils.errors.UnknownFieldError ¶
Bases: ValueError
Raised when write payloads reference fields absent from the model.
__init__ ¶
__init__(field_name, model_name)
Build an error message for an unknown model field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field_name | str | Payload field name that was not recognized. | required |
model_name | str | Name of the Django model checked for that field. | required |
general_manager.interface.utils.errors.DuplicateFieldNameError ¶
Bases: ValueError
Raised when generated interface descriptors collide on one name.
general_manager.interface.utils.errors.MissingActivationSupportError ¶
Bases: TypeError
Raised when soft delete needs model is_active support.
__init__ ¶
__init__(model_name)
Build an error message for missing soft-delete support.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name | str | Name of the model class missing | required |
general_manager.interface.utils.errors.MissingReadOnlyDataError ¶
Bases: ValueError
Raised when a read-only manager lacks its _data source.
__init__ ¶
__init__(interface_name)
Build an error message for missing read-only data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_name | str | Name of the read-only manager/interface owner. | required |
general_manager.interface.utils.errors.MissingUniqueFieldError ¶
Bases: ValueError
Raised when read-only sync cannot determine a row identity.
__init__ ¶
__init__(interface_name)
Build an error message for missing unique field metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_name | str | Name of the read-only manager/interface owner. | required |
general_manager.interface.utils.errors.ReadOnlyRelationLookupError ¶
Bases: ValueError
Raised when read-only sync resolves zero or multiple related rows.
__init__ ¶
__init__(interface_name, field_name, matches, lookup)
Build an error message for an ambiguous relation lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_name | str | Name of the read-only manager/interface owner. | required |
field_name | str | Relation field being resolved. | required |
matches | int | Number of matching rows; exactly one is required. | required |
lookup | object | Lookup payload included in the message with | required |
general_manager.interface.utils.errors.InvalidReadOnlyDataFormatError ¶
Bases: TypeError
Raised when read-only _data has an invalid row/list shape.
general_manager.interface.utils.errors.InvalidReadOnlyDataTypeError ¶
Bases: TypeError
Raised when read-only _data is neither a JSON string nor a list.
__init__ ¶
__init__()
Build the fixed _data must be a JSON string or a list of dictionaries. message.
general_manager.interface.utils.errors.MissingReadOnlyBindingError ¶
Bases: RuntimeError
Raised when read-only sync runs before lifecycle binding completes.
__init__ ¶
__init__(interface_name)
Build an error message for missing manager/model binding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_name | str | Name of the unbound read-only interface class. | required |
general_manager.interface.utils.errors.MissingModelConfigurationError ¶
Bases: ValueError
Raised when an ExistingModelInterface does not declare model.
__init__ ¶
__init__(interface_name)
Build an error message for missing existing-model configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_name | str | Name of the interface class missing | required |
general_manager.interface.utils.errors.UnsafeHistoryConfigurationError ¶
Bases: ValueError
Raised when pre-registered history cannot follow an interface alias.
__init__ ¶
__init__(model_name, interface_name, alias)
Build guidance for replacing an unsafe simple-history tracker.
general_manager.interface.utils.errors.InvalidModelReferenceError ¶
Bases: TypeError
Raised when an existing-model reference cannot be resolved.
__init__ ¶
__init__(reference)
Build an error message for an invalid model reference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reference | object | Invalid value from | required |
general_manager.interface.utils.errors contains public exception classes shared by the interface implementations. Writable ORM create/update paths raise UnknownFieldError for unknown payload fields, InvalidFieldValueError when field assignment raises ValueError, and InvalidFieldTypeError when assignment raises TypeError. Descriptor generation raises DuplicateFieldNameError when generated attribute names collide, and soft delete raises MissingActivationSupportError when an active/inactive model does not expose is_active.
Read-only synchronization raises MissingReadOnlyBindingError before lifecycle binding, MissingReadOnlyDataError when the parent manager does not provide _data, InvalidReadOnlyDataTypeError when _data is neither a JSON string nor a list, InvalidReadOnlyDataFormatError for malformed decoded payloads, many-to-many values, or missing required unique fields, MissingUniqueFieldError when row identity cannot be determined, and ReadOnlyRelationLookupError when a relation lookup dictionary resolves zero or multiple rows. Existing-model resolution raises MissingModelConfigurationError for a missing model declaration and InvalidModelReferenceError for unresolved or non-model declarations. These exceptions preserve their constructor inputs only in the formatted message; they do not expose additional public attributes.
The message formats are stable:
InvalidFieldValueError(field_name, value):Invalid value for {field_name}: {value}.InvalidFieldTypeError(field_name, error):Type error for {field_name}: {error}.UnknownFieldError(field_name, model_name):{field_name} does not exist in {model_name}.DuplicateFieldNameError():Field name already exists.MissingActivationSupportError(model_name):{model_name} must define an 'is_active' attribute.MissingReadOnlyDataError(interface_name):ReadOnlyInterface '{interface_name}' must define a '_data' attribute.MissingUniqueFieldError(interface_name):ReadOnlyInterface '{interface_name}' must declare at least one unique field.ReadOnlyRelationLookupError(interface_name, field_name, matches, lookup):ReadOnlyInterface '{interface_name}' could not resolve relation '{field_name}' (expected 1 match, found {matches}) for lookup {lookup!r}.InvalidReadOnlyDataFormatError():_data JSON must decode to a list of dictionaries.InvalidReadOnlyDataTypeError():_data must be a JSON string or a list of dictionaries.MissingReadOnlyBindingError(interface_name):ReadOnlyInterface '{interface_name}' must be bound to a manager and model before syncing.MissingModelConfigurationError(interface_name):{interface_name} must define a 'model' attribute.InvalidModelReferenceError(reference):Invalid model reference '{reference}'.
general_manager.interface.utils.database_interface_protocols.SupportsHistoryQuery ¶
Bases: Protocol
Protocol for the query object returned by django-simple-history managers.
as_of ¶
as_of(search_date)
Scope the history query to the state at a given date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
search_date | object | None | Date-like cutoff value accepted by the underlying history manager, or | required |
Returns:
| Type | Description |
|---|---|
'SupportsHistoryQuery' | History query limited to the specified |
'SupportsHistoryQuery' | history when |
using ¶
using(alias)
Return a history query scoped to the given database/router alias.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alias | str | Database/router alias to target for the returned query. | required |
Returns:
| Type | Description |
|---|---|
'SupportsHistoryQuery' | A history query object configured to operate against the specified alias. |
filter ¶
filter(**kwargs)
Filter the history query using the provided lookup expressions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Lookup expressions to filter history records. | {} |
Returns:
| Type | Description |
|---|---|
'SupportsHistoryQuery' | A |
last ¶
last()
Retrieve the last item from the history query results.
Returns:
| Type | Description |
|---|---|
object | Final object in the query result set, or |
object | empty. |
general_manager.interface.utils.database_interface_protocols.SupportsHistory ¶
Bases: Protocol
Protocol for models exposing a django-simple-history manager.
general_manager.interface.utils.database_interface_protocols.SupportsActivation ¶
Bases: Protocol
Protocol for models that can be activated/deactivated.
general_manager.interface.utils.database_interface_protocols.SupportsWrite ¶
Bases: Protocol
Protocol for models supporting full_clean/save operations.
full_clean ¶
full_clean(*args, **kwargs)
Validate the model's fields and run model- and field-level validation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args | object | Positional arguments forwarded to Django's | () |
**kwargs | object | Keyword arguments forwarded to Django's | {} |
Raises:
| Type | Description |
|---|---|
ValidationError | If validation fails. |
save ¶
save(*args, **kwargs)
Persist the model instance using its implementation-defined save behavior.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args | object | Positional arguments forwarded to the underlying save method. | () |
**kwargs | object | Keyword arguments forwarded to the underlying save method. | {} |
Returns:
| Type | Description |
|---|---|
object | Result of the underlying save operation. |
The database-interface protocols are structural helper types used by ORM capabilities. SupportsHistoryQuery models the small django-simple-history query surface GeneralManager calls: as_of(...), using(...), filter(...), and last(). Date cutoffs, lookup values, primary keys, and Django save return values are typed as object because they are forwarded to Django or django-simple-history without local interpretation. SupportsHistory, SupportsActivation, and SupportsWrite are runtime-checkable protocols for history managers, is_active soft-delete support, and writable model behavior.
Request Interfaces¶
Application authors normally use RequestField, RequestFilter, RequestQueryOperation, RequestMutationOperation, RequestTransportConfig, and the built-in auth/transport helpers. Transport authors usually implement SharedRequestTransport.send() or the hook protocols below.
RequestQueryOperation is an alias of RequestOperation. Prefer the alias in read/query declarations for readability; use RequestMutationOperation for create/update/delete declarations.
RequestQueryPlan is an alias of RequestPlan. It exists for readability and backward compatibility with earlier query-only request interfaces.
RequestAction is the literal action vocabulary used in plans and local predicates: all, create, delete, detail, exclude, filter, and update.
RequestLocation is the literal request-fragment location vocabulary: query, headers, path, and body.
RequestPayload is Mapping[str, object]; RequestHeaders is Mapping[str, str]; RequestResponse is one payload mapping or a list of payload mappings.
RequestInterface.input_fields is a dict[str, Input[type[object]]]. Request interfaces usually receive that mapping from the inherited lifecycle machinery; custom subclasses that override it should provide real Input descriptors, not plain metadata objects.
Request interface subclasses copy request configuration from Interface.Meta to same-named class attributes during subclass creation. Public Meta names are filters, query_operations, default_query_operation, transport, transport_config, auth_provider, retry_policy, create_operation, update_operation, delete_operation, create_serializer, update_serializer, response_serializer, and rules. Omitted values use the class defaults: empty filter and query-operation mappings, default_query_operation="list", no transport/auth/retry/serializer hooks, no mutation operations, and an empty rule list.
RequestSerializer receives one resolved value and returns the serialized value. RequestValidator receives one lookup value and should raise an exception when the value is invalid. RequestResponseNormalizer receives a raw transport response plus interface, operation, and plan, and must return a RequestQueryResult.
RequestOperation(name, path, ...) requires name and path. Optional constructor fields are method="GET", collection=False, filters={}, metadata={}, static_query_params={}, static_headers={}, static_body=None, and timeout=None. For request interfaces, pass filters=None when a declared operation should inherit the interface-level filter mapping; an explicit mapping, including {}, is operation-specific. Operations do not own serializer or response-normalizer hooks: mutation serializers such as create_serializer live on Interface.Meta, and response normalization lives on RequestTransportConfig.
Request capability internals use the same public types. Validation requires fields, a detail operation, callable serializers/auth hooks, valid retry policy settings, valid filter keys, and non-overlapping operation-local filters. Retry policies require max_attempts >= 1, non-negative base backoff, positive multiplier, bounded jitter, optional max backoff no lower than base backoff, and idempotency header/factory configured together. Query capabilities compile object-valued lookup maps into immutable RequestQueryPlan instances, track a request_query dependency, and defer execution to RequestBucket. Operation-local filters take precedence for their operation; inherited interface filters apply only when an operation declares filters=None. Unsupported local-only filters, excludes without remote support or fallback, invalid fragment locations, and conflicting duplicate fragment keys raise the documented request planning errors unchanged from the active query capability; RequestInterface.query_operation() does not wrap them. Attribute reads execute the detail plan only when no payload cache is present, require exactly one returned item, cache that mapping on the interface instance, and emit request.read.detail. Query execution emits request.query.execute; lifecycle cloning emits request.pre_create and _parent_class assignment emits request.post_create. Create/update/delete accept creator_id and history_comment for manager API compatibility but do not send those values to the remote service. RequestInterface.execute_request_plan() treats only create, update, and delete as mutation actions; every other action string resolves a query operation using plan.operation_name. Missing mutation operations raise NotImplementedError, undeclared non-default query operations raise UnknownRequestOperationError, and auth, retry, metrics, trace, transport, and normalization errors propagate according to the configured transport and normalizer implementations.
general_manager.interface.requests.RequestField dataclass ¶
Describe a manager attribute exposed by a request-backed interface.
source may be a dotted path or tuple path inside the remote payload. default is used by higher-level interface code when an optional value is absent, and normalizer can convert the resolved value before assignment.
general_manager.interface.requests.RequestFilter dataclass ¶
Declare how one manager lookup compiles into a remote request fragment.
location chooses whether the compiled value is written to query params, headers, path params, or body. compiler receives a RequestFilterBinding and may return a custom fragment. Filters without remote output must enable allow_local_fallback so matching happens against returned items.
general_manager.interface.requests.RequestFilterBinding dataclass ¶
Context passed into custom request filter compilers.
general_manager.interface.requests.RequestPlanFragment dataclass ¶
A partial request-plan contribution produced by one filter mapping.
general_manager.interface.requests.RequestOperation dataclass ¶
Describe a named remote request operation used by a request interface.
The path can contain {name} placeholders populated from RequestPlan.path_params. Static request parts are merged with the plan at execution time and conflicting duplicate keys raise RequestPlanConflictError. filters=None is a request-interface sentinel meaning "inherit the interface-level filter mapping"; an explicit mapping, including an empty mapping, is operation-specific.
general_manager.interface.requests.RequestMutationOperation dataclass ¶
Bases: RequestOperation
Describe a named create, update, or delete operation for a request interface.
general_manager.interface.requests.RequestPlan dataclass ¶
Normalized request plan produced from declarative request operations.
Transports consume this immutable value object. query_params, headers, path_params, and body are outbound request fragments; filters and excludes retain original manager lookup values for local fallback and introspection.
general_manager.interface.requests.RequestQueryResult dataclass ¶
Normalized output returned by request query execution hooks.
items contains zero or more mapping payloads after response normalization. Single-object responses are represented as a one-item tuple.
general_manager.interface.requests.SharedRequestTransport ¶
Bases: ABC
Base transport that builds and executes a request from a request plan.
execute() performs request construction, idempotency-key injection, auth, retry handling, metrics, tracing, and response normalization. Subclasses implement only send() for adapter-specific I/O.
general_manager.interface.requests.UrllibRequestTransport ¶
Bases: SharedRequestTransport
First-party JSON transport backed by Python's stdlib HTTP client.
The transport supports absolute HTTP(S) URLs, JSON request bodies, decoded JSON object/list responses, operation-level timeout overrides, and HTTP status mapping through RequestTransportStatusError.
send ¶
send(
request,
*,
interface_cls,
operation,
plan,
identification
)
Send a normalized HTTP request and return a decoded response.
general_manager.interface.requests.RequestTransportConfig dataclass ¶
Static configuration used by a shared request transport.
base_url must be an absolute HTTP(S) origin, optionally with a base path; operation paths are joined with one slash. timeout is expressed in seconds and may be overridden per operation.
general_manager.interface.requests.RequestRetryPolicy dataclass ¶
Framework retry/backoff policy for shared request transports.
By default only idempotent HTTP methods are retried. Set retry_non_idempotent_methods with an idempotency-key header/factory when retrying mutation methods such as POST or PATCH.
general_manager.interface.requests.RequestTransportRequest dataclass ¶
Normalized outbound request passed to auth providers and transports.
url is the absolute base URL joined with the formatted operation path, while path keeps the formatted path alone for tracing and adapters. The mappings are copied into immutable mapping proxies during initialization.
general_manager.interface.requests.RequestTransportResponse dataclass ¶
Decoded transport response before conversion into RequestQueryResult.
payload must already be decoded into either one mapping or a list of mappings. Use metadata for adapter-specific values that should survive response normalization.
general_manager.interface.requests.RequestAuthProvider ¶
Bases: Protocol
Protocol for applying authentication to an outbound transport request.
apply ¶
apply(request, *, interface_cls, operation, plan)
Return a request copy with authentication data applied.
general_manager.interface.requests.BearerTokenAuthProvider dataclass ¶
Apply a bearer token to the Authorization header.
apply ¶
apply(request, *, interface_cls, operation, plan)
Return a request copy with a Bearer <token> header.
general_manager.interface.requests.HeaderApiKeyAuthProvider dataclass ¶
Apply an API key to a configured request header.
apply ¶
apply(request, *, interface_cls, operation, plan)
Return a request copy with the configured header set to the API key.
general_manager.interface.requests.QueryApiKeyAuthProvider dataclass ¶
Apply an API key to a configured query-string parameter.
apply ¶
apply(request, *, interface_cls, operation, plan)
Return a request copy with the configured query parameter set.
general_manager.interface.requests.BasicAuthProvider dataclass ¶
Apply HTTP basic auth to the Authorization header.
apply ¶
apply(request, *, interface_cls, operation, plan)
Return a request copy with an RFC 7617-style Basic auth header.
general_manager.interface.requests.FieldMappingSerializer dataclass ¶
Map one dictionary shape into another using declared key names.
The mapping is {target_key: source_key}. Missing source keys raise KeyError; extra payload keys are ignored.
general_manager.interface.requests.RequestMetricsBackend ¶
Bases: Protocol
Protocol for recording request-interface metrics.
record_request ¶
record_request(
*,
service,
operation,
method,
status_code,
outcome,
duration,
retry_count
)
Record one completed transport execution in seconds.
record_error ¶
record_error(
*,
service,
operation,
method,
error_class,
status_code,
retry_count
)
Record one failed transport execution after retries stop.
general_manager.interface.requests.NoopRequestMetricsBackend ¶
Default metrics backend used when request metrics are not configured.
record_request ¶
record_request(
*,
service,
operation,
method,
status_code,
outcome,
duration,
retry_count
)
Accept a successful request metric without recording it.
record_error ¶
record_error(
*,
service,
operation,
method,
error_class,
status_code,
retry_count
)
Accept an error metric without recording it.
general_manager.interface.requests.RequestTraceBackend ¶
Bases: Protocol
Protocol for optional request tracing hooks.
on_request_start ¶
on_request_start(*, service, operation, method, path)
Start tracing for the overall request execution and return context.
on_request_end ¶
on_request_end(
*,
trace_context,
service,
operation,
method,
path,
status_code,
request_id,
retry_count
)
Finish tracing for a successful request execution.
on_request_error ¶
on_request_error(
*,
trace_context,
service,
operation,
method,
path,
error,
status_code,
retry_count
)
Finish tracing for a failed request execution.
general_manager.interface.requests.NoopRequestTraceBackend ¶
Default tracing backend used when request tracing is not configured.
on_request_start ¶
on_request_start(*, service, operation, method, path)
Return an inert trace context for a request start event.
on_request_end ¶
on_request_end(
*,
trace_context,
service,
operation,
method,
path,
status_code,
request_id,
retry_count
)
Ignore a successful request end event.
on_request_error ¶
on_request_error(
*,
trace_context,
service,
operation,
method,
path,
error,
status_code,
retry_count
)
Ignore a failed request end event.
Request Errors¶
general_manager.interface.requests.RequestRemoteError ¶
Bases: RequestInterfaceError
Base class for transport or upstream-service request failures.
general_manager.interface.requests.RequestTransportError ¶
Bases: RequestRemoteError
Raised when request execution fails before a usable upstream response exists.
general_manager.interface.requests.RequestTransportStatusError ¶
Bases: RequestTransportError
Raised by transports when an upstream HTTP-style status indicates failure.
__init__ ¶
__init__(
*, status_code, request, payload=None, headers=None
)
Store the failed request, decoded payload, response headers, and status.
general_manager.interface.requests.RequestAuthenticationError ¶
general_manager.interface.requests.RequestAuthorizationError ¶
general_manager.interface.requests.RequestNotFoundError ¶
general_manager.interface.requests.RequestConflictError ¶
general_manager.interface.requests.RequestRateLimitedError ¶
general_manager.interface.requests.RequestSchemaError ¶
Bases: RequestInterfaceError
Raised when a request payload or serializer returns an invalid schema.
serializer_must_return_mappings classmethod ¶
serializer_must_return_mappings(interface_name)
Return an error for serializers that produce non-mapping payloads.
non_mapping_payload classmethod ¶
non_mapping_payload(interface_name, operation_name)
Return an error for operation payloads that are not mappings.
non_mapping_json_list classmethod ¶
non_mapping_json_list()
Return an error for JSON arrays containing non-object items.
non_object_json_payload classmethod ¶
non_object_json_payload()
Return an error for decoded JSON that is not an object or object list.
unsupported_url_scheme classmethod ¶
unsupported_url_scheme(url)
Return an error for transports asked to call non-HTTP(S) URLs.
general_manager.interface.requests.RequestPlanConflictError ¶
Bases: ValueError
Raised when multiple filters try to write incompatible request fragments.
general_manager.interface.requests.MissingRequestPayloadFieldError ¶
Bases: KeyError
Raised when a required field is missing from a remote payload.
general_manager.interface.requests.RequestServerError ¶
Interface Infrastructure¶
general_manager.interface.infrastructure.startup_hooks.register_startup_hook ¶
register_startup_hook(
interface_cls, hook, *, dependency_resolver=None
)
Register a startup hook associated with an interface type.
Registrations are kept in insertion order per interface. If the same hook object is already registered for the same interface with the same dependency resolver object, the second registration is ignored. The function only records the hook; exceptions from the hook or resolver can occur later when callers run the registered hooks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | InterfaceType | The interface type the hook applies to. | required |
hook | StartupHook | Callable invoked at startup for implementations of the interface. | required |
dependency_resolver | DependencyResolver | None | Optional callable that returns the interface types | None |
general_manager.interface.infrastructure.startup_hooks.iter_interface_startup_hooks ¶
iter_interface_startup_hooks()
Yield registered interface/hook pairs without dependency ordering.
This iterator preserves the registry's insertion order: interfaces appear in the order they were first registered and hooks appear in per-interface registration order. It intentionally omits dependency-resolver metadata; use registered_startup_hook_entries() when runner-like dependency grouping is required.
Returns:
| Type | Description |
|---|---|
Iterator[tuple[InterfaceType, StartupHook]] | Iterator of |
general_manager.interface.infrastructure.startup_hooks.registered_startup_hooks ¶
registered_startup_hooks()
Return a detached registry snapshot keyed by interface type.
Returns:
| Type | Description |
|---|---|
dict[InterfaceType, tuple[StartupHook, ...]] | Mapping from each interface class to its startup hook callables. The |
dict[InterfaceType, tuple[StartupHook, ...]] | returned dictionary is detached from the registry and each hook sequence |
dict[InterfaceType, tuple[StartupHook, ...]] | is a tuple preserving per-interface registration order. |
general_manager.interface.infrastructure.startup_hooks.registered_startup_hook_entries ¶
registered_startup_hook_entries()
Return a detached snapshot including dependency resolvers.
Returns:
| Type | Description |
|---|---|
dict[InterfaceType, tuple[StartupHookEntry, ...]] | Mapping from each interface class to immutable |
dict[InterfaceType, tuple[StartupHookEntry, ...]] | records. The returned dictionary is detached from the registry and the |
dict[InterfaceType, tuple[StartupHookEntry, ...]] | tuple preserves per-interface registration order. |
general_manager.interface.infrastructure.startup_hooks.clear_startup_hooks ¶
clear_startup_hooks()
Clear every registered startup hook.
This is intended for tests and bootstrap reset flows. It mutates only the process-local registry and does not affect previously returned snapshot dictionaries.
general_manager.interface.infrastructure.startup_hooks.order_interfaces_by_dependency ¶
order_interfaces_by_dependency(
interfaces, dependency_resolver
)
Order interface classes so dependencies appear before dependents.
When dependency_resolver is None, the input order is returned unchanged. Otherwise, the resolver is called once for each input interface class and may return any set-like collection of interface classes. Dependencies not present in interfaces are ignored. Cycles and self-dependencies do not raise; affected interfaces are appended after the acyclic ordered portion in their original relative order. Resolver exceptions propagate to the caller.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interfaces | Sequence[InterfaceType] | Interface classes to order. The original order is used as a stable tie-breaker and as the fallback order for unresolved cycles. | required |
dependency_resolver | DependencyResolver | None | Optional callable that returns the interface classes each input interface depends on. | required |
Returns:
| Type | Description |
|---|---|
list[InterfaceType] | Ordered list of interface classes. With a resolver, repeated interface |
list[InterfaceType] | classes collapse to the first ordered occurrence because dependency |
list[InterfaceType] | tracking is keyed by interface class. |
general_manager.interface.infrastructure.system_checks.register_system_check ¶
register_system_check(interface_cls, hook)
Register a system-check hook for an interface type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interface_cls | InterfaceType | The interface class to associate the hook with. | required |
hook | SystemCheckHook | No-argument callable that returns a list of Django system-check result objects. | required |
Notes
If the same hook is already registered for the interface, this function leaves registrations unchanged.
general_manager.interface.infrastructure.system_checks.iter_interface_system_checks ¶
iter_interface_system_checks()
Iterate over all registered system-check hooks, yielding an (interface, hook) pair for each.
Returns:
| Name | Type | Description |
|---|---|---|
iterator | Iterator[tuple[InterfaceType, SystemCheckHook]] | An iterator that yields |
general_manager.interface.infrastructure.system_checks.registered_system_checks ¶
registered_system_checks()
Map interface types to tuples of their registered system-check hooks.
Returns:
| Type | Description |
|---|---|
dict[InterfaceType, tuple[SystemCheckHook, ...]] | A detached snapshot mapping each interface class to a tuple of its |
dict[InterfaceType, tuple[SystemCheckHook, ...]] | registered system-check hooks. Mutating the returned dict is harmless |
dict[InterfaceType, tuple[SystemCheckHook, ...]] | and does not mutate the registry; subsequent registry changes do not |
dict[InterfaceType, tuple[SystemCheckHook, ...]] | affect the returned tuples. |
general_manager.interface.infrastructure.system_checks.clear_system_checks ¶
clear_system_checks()
Remove all registered system checks, primarily for test isolation.