Core API¶
general_manager.manager.general_manager.GeneralManager ¶
identification property ¶
identification
Return the identification dictionary used to fetch the managed object.
__init__ ¶
__init__(*args, **kwargs)
Create a manager by constructing its Interface and record the resulting identification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args | object | Positional arguments forwarded to the Interface constructor. | () |
**kwargs | object | Keyword arguments forwarded to the Interface constructor. | {} |
__getattr__ ¶
__getattr__(attribute_name)
Lazily install descriptors for declared fields on late-imported managers.
Manager classes imported after Django app startup are registered but have not yet had descriptor properties attached. Falling back here lets interactive and test-only managers behave like startup-loaded managers while preserving normal AttributeError behavior for unknown names. The fallback calls GeneralManagerMeta.ensure_attributes_initialized(self.__class__, attribute_name); a truthy result means descriptors were installed and the attribute is returned through object.__getattribute__. A falsey result raises AttributeError(attribute_name).
__or__ ¶
__or__(other)
Combine this manager with another manager or a Bucket into a Bucket representing their union.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | Self | Bucket[Self] | A manager of the same class or a Bucket to union with. | required |
Returns:
| Type | Description |
|---|---|
Bucket[Self] | Bucket[Self]: A Bucket containing the union of the managed objects represented by this manager and |
Raises:
| Type | Description |
|---|---|
UnsupportedUnionOperandError | If |
__eq__ ¶
__eq__(other)
Determine whether another object represents the same managed entity.
Returns:
| Type | Description |
|---|---|
bool |
|
__iter__ ¶
__iter__()
Iterate over attribute names and resolved values for the managed object.
Callable entries in _attributes are invoked with self._interface. The synthetic history property and generated relation descriptors are skipped. GraphQLProperty and normal property class attributes are yielded by reading them through getattr(self, name).
create classmethod ¶
create(
creator_id=None,
history_comment=None,
ignore_permission=False,
**kwargs
)
Create a new managed object through the interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
creator_id | int | None | Optional identifier of the creating user. | None |
history_comment | str | None | Audit comment stored with the change. | None |
ignore_permission | bool | When True, skip permission validation. | False |
**kwargs | object | Additional fields forwarded to the interface | {} |
Returns:
| Name | Type | Description |
|---|---|---|
Self | Self | Manager instance representing the created object. |
Raises:
| Type | Description |
|---|---|
PermissionError | Propagated if the permission check fails. |
update ¶
update(
creator_id=None,
history_comment=None,
ignore_permission=False,
**kwargs
)
Update the managed object, refresh this manager in place, and return it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
creator_id | int | None | Optional identifier of the user performing the update. | None |
history_comment | str | None | Optional audit comment recorded with the update. | None |
ignore_permission | bool | If True, skip permission validation. | False |
**kwargs | object | Field updates forwarded to the interface. | {} |
Returns:
| Name | Type | Description |
|---|---|---|
Self | Self | This manager instance after reloading its backing interface state. |
Raises:
| Type | Description |
|---|---|
PermissionError | If the permission check fails when |
delete ¶
delete(
creator_id=None,
history_comment=None,
ignore_permission=False,
)
Delete the managed object; performs a soft delete when the underlying interface is configured accordingly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
creator_id | int | None | Optional identifier of the user performing the action. | None |
history_comment | str | None | Audit comment recorded with the deletion. | None |
ignore_permission | bool | When True, skip permission validation. | False |
Raises:
| Type | Description |
|---|---|
PermissionError | If permission validation fails. |
filter classmethod ¶
filter(**kwargs)
Get a Bucket of managers matching the provided lookup expressions.
Lookup expressions may include GeneralManager instances, or lists/tuples containing them. Single-field manager identifications are replaced with their id value only when the identification mapping has exactly the one key "id". Empty mappings, single-key non-"id" mappings, and multi-key mappings are replaced with a copied identification mapping before the lookups are forwarded to the interface. Normalization is shallow: only top-level lookup values and direct list/tuple items are inspected. Non-manager values, including nested containers, are forwarded unchanged. When no manager values are present, the original kwargs mapping is delegated. The method returns the interface result typed as Bucket[Self] and does not wrap identification, mapping-copy, interface, or bucket errors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Lookup expressions used to filter managers. | {} |
Returns:
| Type | Description |
|---|---|
Bucket[Self] | Bucket[Self]: Bucket containing manager instances that match the lookups. |
get classmethod ¶
get(**kwargs)
Return the single manager matching the provided lookup expressions.
This is a convenience wrapper around filter(...).get() and preserves the underlying bucket's single-item exception behavior.
exclude classmethod ¶
exclude(**kwargs)
Return a bucket excluding managers that match the provided lookups.
Lookup normalization, return typing, and error propagation match filter(...).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Lookup expressions forwarded to the interface as exclusions. | {} |
Returns:
| Type | Description |
|---|---|
Bucket[Self] | Bucket[Self]: Bucket of manager instances that do not satisfy the lookups. |
__parse_identification staticmethod ¶
__parse_identification(kwargs)
Replace manager instances within a filter mapping by lookup identifiers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kwargs | dict[str, object] | Mapping containing potential manager instances. | required |
Returns:
| Type | Description |
|---|---|
dict[str, object] | None | Mapping with managers substituted by lookup identifiers, or |
dict[str, object] | None |
|
__lookup_identifier staticmethod ¶
__lookup_identifier(manager)
Return the scalar id for normal managers, or a copy for composite ids.
GeneralManager(*args, **kwargs) constructs the configured Interface, stores its identification mapping, and tracks an identification dependency. Public constructor inputs are the interface inputs for that manager; constructor validation and input-specific errors come from the interface. identification returns the stored mapping, and str(manager)/repr(manager) render ClassName(**identification). Iterating a manager yields declared attributes and GraphQL/property values after checking that the manager state is still valid. Callable entries in _attributes are invoked with self._interface; the synthetic history property and generated relation descriptors are skipped. Managers start valid after construction or trusted hydration. _reload_interface_state() reconstructs Interface(**identification), marks the manager valid, and clears the invalidation reason. _invalidate_manager_state(reason) marks the manager invalid and stores the reason. Reading or mutating a manager after delete() raises InvalidManagerStateError.
GeneralManager.create(creator_id=None, history_comment=None, ignore_permission=False, **fields) checks create permission unless ignore_permission is true, delegates to Interface.create(...), logs the created identification, and returns a new manager constructed from that identification. manager.update(...) checks that the manager is still valid, checks update permission unless skipped, delegates to the interface, reloads the backing interface in place, preserves request payload cache when available, and returns the same manager instance. manager.delete(...) checks delete permission unless skipped, delegates to the interface, invalidates the manager for later field reads, and returns None.
For writable ORM interfaces as of GeneralManager 0.63.1, ordinary create()/update() calls commit the row save, history actor/reason, and many-to-many <relation>_id_list changes in one transaction on the configured database alias. Validation, save, history, relation, and transaction exceptions propagate and roll back that complete unit. Upload-aware writes retain their separate atomic upload/finalization contract. After a caller-owned transaction rolls back, discard an in-place-updated manager and reconstruct it from its ID; materialized values on that Python object may reflect the failed transaction. The ORM transaction guide shows the pattern.
GeneralManager.filter(**lookups) and exclude(**lookups) forward lookup expressions to the interface and return Bucket[Self]. Lookup values may be manager instances or lists/tuples containing manager instances; those values are replaced with their scalar identification["id"] value for normal single-id managers, or with a copied identification mapping for composite identifiers, before the interface call. Scalar normalization applies only when the identification mapping has exactly the one key "id". Empty mappings, single-key non-"id" mappings, and multi-key mappings are forwarded as copied identification mappings. Normalization is shallow: only top-level lookup values and direct list/tuple items are inspected. Nested containers and non-manager values are forwarded unchanged. Calls without manager values delegate the original lookup mapping. These methods return the interface result typed as Bucket[Self] and do not wrap identification access, mapping-copy, interface, or bucket errors. GeneralManager.get(**lookups) is filter(**lookups).get() and preserves the bucket's single-item behavior. GeneralManager.all() returns Interface.filter() as a bucket of the concrete manager class.
manager.history delegates to the configured history capability's get_history_queryset_for_manager(Interface, manager) and returns that queryset object. Missing history capability support raises HistoryNotSupportedError. Late descriptor fallback calls GeneralManagerMeta.ensure_attributes_initialized(cls, name); when it returns true, the attribute is read normally, and otherwise AttributeError(name) is raised.
GeneralManager.__or__(other) combines a manager instance with either a compatible Bucket or another manager instance of the exact same class. Bucket operands handle the union themselves; same-class manager operands call filter(id__in=[left.identification, right.identification]). Other operands raise UnsupportedUnionOperandError.
GeneralManager._from_trusted_orm_instance(row, *, search_date=None) is an internal trusted hydration hook for framework-owned ORM rows. It bypasses public input validation and should only be used with Django rows already loaded by the owning ORM interface. Managers that use the base constructor hydrate by calling the interface's trusted ORM hook directly, store the hydrated interface and its identification, mark state valid, and track the identification dependency. Managers with a custom __init__ are reconstructed with cls(row.pk) or cls(row.pk, search_date=search_date) so their custom construction contract still runs. ORM interfaces normalize search_date while building the trusted interface or constructor path. Interfaces without a trusted hydration hook raise TrustedOrmHydrationNotSupportedError.
UnsupportedUnionOperandError(type_) renders Unsupported type for union: {type_}.. TrustedOrmHydrationNotSupportedError(interface_name) renders {interface_name} does not support trusted ORM hydration..
general_manager.manager.general_manager.UnsupportedUnionOperandError ¶
Bases: TypeError
Raised when attempting to union a manager with an incompatible operand.
The public message is "Unsupported type for union: {operand_type}.".
__init__ ¶
__init__(operand_type)
Exception raised when attempting to perform a union with an unsupported operand type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
operand_type | type | The operand type that is not supported for the union; its representation is included in the exception message. | required |
general_manager.manager.general_manager.TrustedOrmHydrationNotSupportedError ¶
Bases: TypeError
Raised when trusted ORM hydration is requested for a non-ORM interface.
The public message is "{interface_name} does not support trusted ORM hydration.".
general_manager.utils.public_api.MissingExportError ¶
Bases: AttributeError
Raised when a requested export is not defined in the public API.
__init__ ¶
__init__(module_name, attribute)
Initialize the MissingExportError with the originating module name and the missing attribute.
Constructs the exception message "module 'module_name' has no attribute 'attribute'".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_name | str | Name of the module where the attribute was expected. | required |
attribute | str | Name of the missing attribute. | required |
Package-level imports such as from general_manager import GeneralManager and from general_manager.interface import DatabaseInterface are resolved lazily from the public API registry. A package __getattr__(name) returns the resolved export object, caches it in that package module, and raises MissingExportError for names not listed in that package's __all__. dir(package) includes both currently loaded module globals and registered lazy exports. Successful lazy resolutions are debug-logged with module, export, target module, and target attribute context. Missing public exports are warning-logged with module and export context.
general_manager.models is the root Django models module for this app. It re-exports SearchIndexState, WorkflowEventRecord, WorkflowOutbox, WorkflowExecutionRecord, and WorkflowDeliveryAttempt from their canonical search/workflow modules for Django discovery and stable root-module imports. The module defines no helper callables, accepts no application input, returns no application output, and does not wrap import or Django app-registry errors. Detailed field and model behavior is documented in the Search and Workflow API pages.
general_manager.apps.GeneralmanagerConfig ¶
Bases: AppConfig
Django application configuration for GeneralManager startup hooks.
ready ¶
ready()
Coordinate all startup phases for the general_manager app.
The startup sequence installs hook runners and system checks, imports optional app managers modules, initializes pending manager classes, configures remote APIs, observability, search, workflow, and warm-up schedulers, and finally builds GraphQL when AUTOCREATE_GRAPHQL is enabled.
Raises:
| Type | Description |
|---|---|
Exception | Startup errors from imported managers modules, initialization, settings-backed configurators, remote API wiring, or GraphQL bootstrap propagate unchanged. |
install_startup_hook_runner staticmethod ¶
install_startup_hook_runner()
Install the startup hook runner through the bootstrap module.
register_system_checks staticmethod ¶
register_system_checks()
Register GeneralManager system checks through the bootstrap module.
initialize_general_manager_classes staticmethod ¶
initialize_general_manager_classes(
pending_attribute_initialization, all_classes
)
Initialize pending manager classes through the bootstrap module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pending_attribute_initialization | list[type[GeneralManager]] | Manager classes whose generated attributes still need initialization. | required |
all_classes | list[type[GeneralManager]] | Registry of all known manager classes used for initialization and permission validation. | required |
Raises:
| Type | Description |
|---|---|
Exception | Propagates errors from bootstrap initialization, including invalid permission-class configuration. |
check_permission_class staticmethod ¶
check_permission_class(general_manager_class)
Validate a manager permission class through the bootstrap module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
general_manager_class | type[GeneralManager] | Manager class whose nested permission class should be checked. | required |
Raises:
| Type | Description |
|---|---|
InvalidPermissionClassError | If the configured permission class is not a |
handle_graph_ql staticmethod ¶
handle_graph_ql(pending_graphql_interfaces)
Build GraphQL integration for pending manager interfaces.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pending_graphql_interfaces | list[type[GeneralManager]] | Manager classes queued for GraphQL interface and mutation generation. | required |
Raises:
| Type | Description |
|---|---|
Exception | Propagates GraphQL schema, URLConf, and ASGI wiring errors from bootstrap. |
handle_remote_api staticmethod ¶
handle_remote_api(manager_classes)
Register remote API integration for manager classes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manager_classes | list[type[GeneralManager]] | Manager classes inspected for remote API exposure. | required |
Raises:
| Type | Description |
|---|---|
Exception | Propagates errors from remote API registration. |
add_graphql_url staticmethod ¶
add_graphql_url(schema)
Add the generated GraphQL URL to the configured URLConf.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema | Schema | Graphene schema served by the generated GraphQL view. | required |
Raises:
| Type | Description |
|---|---|
MissingRootUrlconfError | If Django has no |
Exception | Propagates import, URLConf mutation, middleware, view, or ASGI route wiring errors from bootstrap. |
GeneralmanagerConfig.ready() is the Django startup entry point for the package. It installs the management-command startup-hook runner and registers system checks before importing optional <app>.managers modules and initializing pending manager classes. Installing the runner does not execute registered startup hooks immediately; the patched management-command runner executes them before supported commands run. After manager initialization, ready() registers remote APIs, configures audit logging, search, workflow, search reconciliation, and GraphQL warm-up schedules, and builds the GraphQL schema only when AUTOCREATE_GRAPHQL is enabled. Startup failures from manager imports, initialization, settings-backed configurators, remote API wiring, or GraphQL bootstrap propagate through Django's app-loading path.
The static methods on GeneralmanagerConfig are compatibility wrappers around general_manager.bootstrap helpers. They keep older imports and tests working: install_startup_hook_runner(), register_system_checks(), initialize_general_manager_classes(...), check_permission_class(...), handle_graph_ql(...), handle_remote_api(...), add_graphql_url(schema), and _ensure_asgi_subscription_route(graphql_url). add_graphql_url(schema) requires a Graphene schema and raises MissingRootUrlconfError when Django has no ROOT_URLCONF. Other wrapper errors propagate from the bootstrap helper they call. register_system_checks() is process-idempotent by module-qualified interface class identity, so repeated app setup skips already-registered hooks without suppressing different interface classes that share the same bare class name.
general_manager.manager.meta.GeneralManagerMeta ¶
Bases: type
Metaclass responsible for wiring GeneralManager interfaces and registries.
The metaclass validates declared Interface classes, lets interface lifecycle hooks alter class creation, tracks manager classes for startup initialization and GraphQL generation, and lazily installs descriptor-backed fields for managers imported after startup. The process-global registries are append-only for class creation; this class does not deduplicate entries or lock registry mutation outside descriptor initialization.
__getattribute__ ¶
__getattribute__(attribute_name)
Initialize late-imported field descriptors before class attribute lookup.
__getattr__ is only reached for missing names, so inherited GeneralManager attributes must pass through here to let declared fields override inherited names the same way bootstrap initialization does. Once a manager class has completed descriptor initialization, attributes already present on that class use normal type lookup without rechecking initialization. Missing names and inherited public names still pass through initialization so late-discovered fields keep the existing override behavior. "Non-private" means the requested name does not start with "_" and is not exactly "Interface". Probing an unknown public name may call Interface.get_attributes(), but it installs descriptors only when the probed name is declared by the interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
attribute_name | str | Class attribute being read. | required |
Returns:
| Type | Description |
|---|---|
object | The attribute returned by |
object | descriptor initialization. |
Raises:
| Type | Description |
|---|---|
AttributeError | Propagated from normal class attribute lookup. |
Exception | Exceptions from |
__getattr__ ¶
__getattr__(attribute_name)
Lazily install field descriptors for manager classes imported after startup.
Django app initialization wires descriptors for managers known at startup. Managers defined later, for example in an interactive shell or a test scratch module, still register with this metaclass but have not had descriptors attached yet. If the missing class attribute is a declared manager field, initialize the class and retry the lookup. Unknown names may call the interface attribute provider, but they do not cache _attributes or install descriptors unless the name is declared.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
attribute_name | str | Missing class attribute being resolved. | required |
Returns:
| Type | Description |
|---|---|
object | The descriptor-backed attribute value after initialization. |
Raises:
| Type | Description |
|---|---|
AttributeError | If the name is not an interface-backed field. |
Exception | Exceptions from |
ensure_attributes_initialized staticmethod ¶
ensure_attributes_initialized(
manager_class, attribute_name=None
)
Ensure descriptor-backed fields are installed for manager_class.
Returns True when the class exposes attribute_name after initialization, or when no specific attribute was requested and descriptors were installed. Returns False for unknown attributes or classes that do not expose interface-backed fields. The class-level manager_class._attributes cache stores the dict[str, object] interface attribute mapping used to build descriptors; manager instances also store resolved per-instance values on instance._attributes. This shared attribute name is intentional compatibility behavior. Attribute mapping key order is preserved when descriptors are installed, empty mappings still count as successful initialization when no specific attribute_name was requested, and non-string keys are not validated here but are incompatible with normal descriptor installation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manager_class | type['GeneralManager'] | Manager class whose descriptors should be installed. | required |
attribute_name | str | None | Optional single field name to validate before installing descriptors. | None |
Returns:
| Type | Description |
|---|---|
bool |
|
bool | installed for the requested field; otherwise |
bool |
|
bool | method returns |
Raises:
| Type | Description |
|---|---|
Exception | Exceptions from |
ensure_manager_is_valid staticmethod ¶
ensure_manager_is_valid(instance, attribute_name=None)
Raise when descriptor-backed field access targets an invalidated manager.
Missing _manager_state_valid is treated as valid. Missing _manager_state_reason falls back to "manager state is invalid" when the manager is marked invalid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
instance | 'GeneralManager' | Manager instance being accessed. | required |
attribute_name | str | None | Field name being read, or | None |
Raises:
| Type | Description |
|---|---|
InvalidManagerStateError | If the manager carries an invalidated state flag. |
__new__ ¶
__new__(mcs, name, bases, attrs)
Create a GeneralManager subclass, integrate any declared Interface hooks, and register the class for pending initialization and GraphQL processing.
If the class body directly defines an Interface key in attrs, validates it is a subclass of InterfaceBase, calls interface.handle_interface() on that class object, invokes the returned pre-creation hook to allow modification of the class namespace, creates the class, then invokes the returned post-creation hook and registers the class for attribute initialization and global tracking. Inherited Interface attributes are not treated as declared by this creation path; subclasses that should be managers must declare their own Interface class body entry. InterfaceBase itself satisfies the subclass check, but its default lifecycle path raises NotImplementedError unless a lifecycle capability or override is available. handle_interface() is a classmethod on InterfaceBase; concrete interfaces may inherit the capability-driven implementation or override it. It must return (pre_creation, post_creation) callables. pre_creation is called with (name, attrs, interface) and must return (attrs, interface_cls, model) where attrs is a dict[str, object] namespace passed to type.__new__, interface_cls is a type[InterfaceBase] used for post-creation and capability selection, and model is a Django Model subclass or None passed to post_creation. The metaclass does not separately assign new_class.Interface = interface_cls; the returned attrs mapping must contain the final "Interface" entry when the created class should expose that interface. post_creation is called with (new_class, interface_cls, model) and returns None. model is lifecycle pass-through owned by the interface capability; the metaclass does not store or validate it except by passing it to post_creation. Return values are not type-validated beyond tuple unpacking and the later calls that consume them. If Interface is not defined directly in attrs, creates the class directly. If settings.AUTOCREATE_GRAPHQL is true, registers the created class for GraphQL interface processing, including plain classes without an interface; later GraphQL bootstrap owns any filtering or failure behavior. If class creation or any interface-backed setup step raises before the settings check, pending_graphql_interfaces is not appended.
Capability selection is the interface capability manifest chosen by ManifestCapabilityBuilder for the returned interface_cls. It is built by ManifestCapabilityBuilder.build(interface_cls) and stored by interface_cls.set_capability_selection(selection) for later capability-handler lookup. This metaclass does not append to read_only_classes; the read-only lifecycle capability owns that registry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mcs | type | The metaclass creating the class. | required |
name | str | Name of the class being created. | required |
bases | tuple[type, ...] | Base classes for the new class. | required |
attrs | dict[str, object] | Class namespace supplied during creation. | required |
Returns:
| Name | Type | Description |
|---|---|---|
type | type | The newly created subclass, possibly modified by Interface hooks. |
Raises:
| Type | Description |
|---|---|
InvalidInterfaceTypeError | If a declared |
NotImplementedError | Propagated from interfaces that cannot provide lifecycle hooks through |
TypeError | Propagated from malformed hook call signatures, invalid class namespace values passed to |
ValueError | Propagated from malformed lifecycle hook return unpacking. |
NotImplementedError | Propagated from interfaces that cannot provide lifecycle hooks through |
Exception | Other exceptions from interface pre/post creation hooks, capability selection, or setting the capability selection propagate unchanged. |
create_at_properties_for_attributes staticmethod ¶
create_at_properties_for_attributes(attributes, new_class)
Attach descriptor properties to new_class for each name in attributes.
Each generated descriptor returns the interface field type when accessed on the class and resolves the corresponding value from instance._attributes when accessed on an instance. Existing attributes with the same names are overwritten unconditionally, matching bootstrap descriptor installation. Generated descriptors implement only __get__; assignment to the same name on the class replaces the descriptor, and instance assignment follows normal non-data-descriptor shadowing rules. Descriptor reads cache resolved values on the manager instance and replay dependency tracking when returning a cached manager value. Duplicate names are processed in order, so later duplicates overwrite earlier descriptors. Non-string names or iterables that raise during iteration propagate their original exception and may leave descriptors from earlier names installed. If called through ensure_attributes_initialized(), those failures can occur after manager_class._attributes is cached and before pending-initialization removal. If the stored value is callable it is always treated as a deferred evaluator and invoked with instance._interface; expose literal callables by wrapping them in a non-callable container or by using a custom descriptor path. A missing stored key raises MissingAttributeError, but a missing instance._attributes mapping or missing instance._interface attribute raises the normal AttributeError. A present but malformed _interface is passed to the callable unchanged; callable failures are wrapped in AttributeEvaluationError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
attributes | Iterable[str] | Names of attributes for which descriptors will be created. | required |
new_class | type[GeneralManager] | Class that will receive the generated descriptor attributes. | required |
Raises:
| Type | Description |
|---|---|
MissingAttributeError | Later raised by generated descriptors when an instance does not contain the requested attribute. |
AttributeEvaluationError | Later raised by generated descriptors when a callable attribute value fails. |
InvalidManagerStateError | Later raised by generated descriptors when reading an invalidated manager. |
GeneralManagerMeta is the metaclass behind every GeneralManager subclass. When a class body directly declares an Interface key in attrs, the metaclass validates that it is an InterfaceBase subclass, calls interface.handle_interface() on that class object, then calls the returned lifecycle pre-creation hook with (name, attrs, interface) and expects (attrs, interface_cls, model) back. Inherited Interface attributes are not treated as declarations by this class-creation path; subclasses that should be registered managers must declare their own Interface class body entry. InterfaceBase itself passes the subclass check, but its default lifecycle path raises NotImplementedError unless a lifecycle capability or override supplies hooks. InterfaceBase.handle_interface() is a classmethod; concrete interfaces may inherit its capability-driven implementation or override it. It must return (pre_creation, post_creation) callables. pre_creation(name, attrs, interface) returns (attrs, interface_cls, model): attrs is a dict[str, object] namespace passed to type.__new__, interface_cls is a type[InterfaceBase] used for post-creation and capability selection, and model is a Django Model subclass or None. The metaclass does not separately assign new_class.Interface = interface_cls; the returned attrs mapping must contain the final "Interface" entry when the created class should expose that interface. post_creation(new_class, interface_cls, model) returns None. model is lifecycle pass-through owned by the interface capability; the metaclass does not store or validate it except by passing it to post_creation. Return values are not type-validated beyond tuple unpacking and the later calls that consume them. After class creation the metaclass calls the post hook, builds capability selection from ManifestCapabilityBuilder.build(interface_cls), stores it with interface_cls.set_capability_selection(selection) for later capability-handler lookup, and appends the new class to all_classes and pending_attribute_initialization. Capability selection is the interface capability manifest chosen for the returned interface class. Invalid interface declarations raise InvalidInterfaceTypeError. Malformed hook call signatures, invalid class namespace values passed to type.__new__, invalid returned interface classes consumed by capability setup, and descriptor/class creation operations may raise TypeError; malformed lifecycle hook return unpacking may raise ValueError; unsupported lifecycle hooks raise NotImplementedError; other lifecycle hook errors, capability-selection errors, and selection-storage errors propagate from their source. Classes without an Interface are still created normally but are not added to the manager registries. When AUTOCREATE_GRAPHQL is enabled, pending_graphql_interfaces append happens after class creation and, for interface-backed managers, after pre-hook, post-hook, capability selection, pending_attribute_initialization, and all_classes registration. Every class created by the metaclass is appended, including plain classes without an Interface; downstream GraphQL bootstrap owns later filtering or failure behavior. If class creation or any interface-backed setup step raises before the settings check, pending_graphql_interfaces is not appended. read_only_classes is a sibling registry populated by the read-only lifecycle capability, not by GeneralManagerMeta.__new__; read-only lifecycle creation appends generated read-only manager classes there and normal tests or bootstrap cleanup may replace the list when restoring process state.
ensure_attributes_initialized(manager_class, attribute_name=None) installs descriptor-backed fields from manager_class.Interface.get_attributes(). Supplying attribute_name limits the success condition to that declared field: unknown names, managers without an Interface, interfaces without get_attributes, and interfaces whose read attributes raise NotImplementedError return False. Other errors from get_attributes() propagate. Probing an unknown public name may call get_attributes(), but it does not cache attributes or install descriptors unless the name is declared. Successful initialization stores the dict[str, object] interface attribute mapping on the class-level manager_class._attributes, creates descriptors for all declared fields, and removes the class from pending_attribute_initialization when present. Mapping key order is preserved when descriptors are installed. Empty mappings count as successful initialization when no specific attribute_name was requested. Non-string keys are not validated before descriptor installation; if setattr() rejects a key, the original exception propagates, _attributes may already be cached, descriptors from earlier keys may already be installed, and pending-initializer removal is skipped because execution stops before that step. A later ensure_attributes_initialized(manager_class) call sees the cached _attributes mapping and retries descriptor creation for all keys; a targeted call for a declared key also retries descriptor creation for all keys before returning True. Manager instances also use instance._attributes for resolved values; the shared attribute name is intentional compatibility behavior.
Generated descriptors return Interface.get_field_type(name) when read on the class. When read on an instance, they first call ensure_manager_is_valid(instance, name), then read instance._attributes[name]. Callable attribute values are invoked with instance._interface and are always treated as deferred evaluators; literal callables must be wrapped in a non-callable container or exposed by a custom descriptor path. Callable failures are wrapped in AttributeEvaluationError whose message starts with Error calling attribute {name}:, with the original exception chained as __cause__. Missing stored keys raise MissingAttributeError, but missing instance._attributes or instance._interface raises normal AttributeError. Invalidated managers raise InvalidManagerStateError, and class-level field type lookup errors propagate from the interface. Missing _manager_state_valid is treated as valid; a missing invalidation reason falls back to manager state is invalid. Invalid attribute reads render Cannot access attribute {attribute_name!r} on invalidated {ManagerName}: {reason}.; whole-manager checks render Cannot access invalidated {ManagerName}: {reason}..
GeneralManagerMeta.__getattribute__ performs lazy descriptor installation before class attribute reads whose names do not start with _, excluding Interface, so a declared field can override inherited manager methods such as create. __getattr__ performs the same lazy installation for genuinely missing class attributes and raises AttributeError(name) when the name is not an interface-backed field. Descriptor installation overwrites existing attributes with the same names, including explicit class attributes and inherited methods. Generated descriptors implement only __get__: assigning the same name on the class replaces the descriptor, assigning on an instance follows normal non-data-descriptor shadowing rules, and descriptor reads do not cache resolved values. Duplicate names are processed in order, so later duplicates overwrite earlier descriptors. Non-string names or attribute iterables that fail partway through propagate their original exception and may leave descriptors for earlier names installed. A present but malformed _interface is passed to callable attribute values unchanged; errors raised by that callable are wrapped as AttributeEvaluationError. Normal GeneralManager construction creates instance._interface from self.Interface(*args, **kwargs), and trusted ORM hydration creates it through the interface's trusted hydration hook. The descriptor does not check that the current instance._interface is an instance of new_class.Interface; it passes the value currently stored on the instance.
The class registries are process-local mutable lists used by bootstrap, search, GraphQL, tests, and read-only lifecycle wiring. Application code should treat them as framework-owned; replacement or clearing is tolerated for tests and advanced bootstrap integrations that restore process state afterward. Class creation appends without deduplication. Descriptor initialization holds one metaclass-level lock around checking/caching _attributes, calling get_attributes(), installing descriptors, and removing the class from pending_attribute_initialization; under that lock, get_attributes() is called at most once for a class whose attributes are successfully cached. Other registry mutation is not locked. Concurrent external clearing or replacement of the registry lists while classes are being created or descriptors are being initialized has no stronger guarantee than normal Python list assignment and mutation semantics.
An empty attribute mapping means the interface has no descriptor-backed fields to install. That still counts as initialized for bulk startup work because the class no longer needs pending descriptor processing; targeted initialization for a named field still returns False when the name is absent.
general_manager.manager.group_manager.GroupManager ¶
Bases: Generic[GeneralManagerType]
Represent aggregated results for grouped GeneralManager records.
__init__ ¶
__init__(manager_class, group_by_value, data)
Initialise a grouped manager with the underlying bucket and grouping keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manager_class | type[GeneralManagerType] | Manager subclass whose records were grouped. | required |
group_by_value | dict[str, object] | Grouping key values describing this group. | required |
data | Bucket[GeneralManagerType] | Bucket of records belonging to the group. | required |
Returns:
| Type | Description |
|---|---|
None | None |
__hash__ ¶
__hash__()
Return a hash based on the manager class, group keys, and grouped data.
Manager instances, mappings, lists, tuples, and sets are recursively frozen before hashing. Mapping entries are sorted by their frozen key/value tuples; sets become frozenset values. The resulting hash follows normal Python hash stability rules: it is suitable for the lifetime of unchanged group state, but it is not a cross-process persistent identifier and can change if mutable grouped data changes after construction.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Hash value combining class, keys, and data. |
__eq__ ¶
__eq__(other)
Compare grouped managers by manager class, keys, and grouped data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | object | Object to compare against. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True when both grouped managers describe the same data. |
__repr__ ¶
__repr__()
Return a debug representation showing grouped keys and data.
Returns:
| Type | Description |
|---|---|
str | Debug string in the form |
str |
|
__iter__ ¶
__iter__()
Iterate over attribute names and their aggregated values.
Yields:
| Type | Description |
|---|---|
str | Attribute name and aggregated value pairs. Interface attributes are |
object | the keys returned by |
tuple[str, object] | are yielded in that mapping's iteration order. |
tuple[str, object] | values declared directly on the manager class are yielded after |
tuple[str, object] | interface attributes in class |
tuple[str, object] | not filtered. |
__getattr__ ¶
__getattr__(item)
Lazily compute aggregated attribute values when accessed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | str | Attribute name requested by the caller. | required |
Returns:
| Type | Description |
|---|---|
object | Group-by key value or cached aggregate for the requested attribute. |
object | Cached aggregate values are stored in the private |
object | dictionary under the requested attribute name and are not |
object | invalidated if the underlying bucket or |
object | mutated after first access. |
Raises:
| Type | Description |
|---|---|
MissingGroupAttributeError | If the attribute cannot be resolved from group metadata or a |
Exception | Exceptions raised while iterating the underlying bucket or reading grouped record attributes propagate unchanged. |
combine_value ¶
combine_value(item)
Aggregate the values of a named attribute across all records in the group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | str | Attribute name to aggregate from each grouped record. | required |
Returns:
| Type | Description |
|---|---|
object | Aggregated value for |
object | all- |
object | with |
object | overwriting earlier keys; strings are deduplicated in encounter |
object | order and joined by |
object | handling; numeric and |
object | datetime/date/time values use |
object | selected from interface metadata or a concrete |
object | return annotation, not from each runtime value, so mixed runtime |
object | values follow the selected branch and may raise from that operation. |
Raises:
| Type | Description |
|---|---|
MissingGroupAttributeError | If the attribute does not exist or its type cannot be determined on the manager. |
Exception | Exceptions raised while reading grouped record attributes, unioning bucket/manager values, merging containers, summing values, or comparing date/time values propagate unchanged. |
GroupManager is the per-group object yielded by GroupBucket. Attribute access first returns group-by key values, then lazily aggregates values from the group's underlying bucket and caches the result. Cached aggregates are not invalidated if the underlying bucket or group-key mapping is mutated later; they are stored in the private _grouped_data dictionary under the requested attribute name. Iteration yields keys from manager_class.Interface.get_attributes() first in that mapping's order, then GraphQLProperty values declared directly on the manager class in class-__dict__ order; duplicate names are not filtered.
id, empty buckets, and all-None inputs aggregate to None. Bucket and manager values are combined with |, lists are concatenated, dicts are merged with later values overwriting earlier keys, strings are de-duplicated in encounter order and joined by ", ", booleans use any() before numeric handling, numeric and Measurement values are summed, and date/time values use max(). The aggregation branch is chosen from interface metadata or a concrete GraphQLProperty return annotation, not from every runtime value, so mixed runtime values follow the selected branch and may raise from that operation. GraphQL property annotations use the first typing.get_args() entry when present, otherwise the annotation object itself; unsupported non-class annotations raise MissingGroupAttributeError. hash(group) recursively freezes manager instances, mappings, lists, tuples, and sets before hashing. Mapping entries are sorted by their frozen key/value tuples, sets become frozenset values, and the final hash is suitable only for unchanged in-process group state, not as a persistent cross-process identifier. Missing metadata or unsupported return annotations raise MissingGroupAttributeError; errors from bucket iteration, attribute access, unioning, summing, merging, or comparison propagate unchanged.
general_manager.manager.input.Input ¶
Bases: Generic[INPUT_TYPE]
Describe an interface input's type, constraints, and dependency metadata.
Input instances are attached to Interface classes and consumed by GeneralManager interfaces when casting raw values, enumerating calculation combinations, or exposing GraphQL input metadata. The descriptor stores the expected Python class, optional allowed values, scalar bounds, dependency names, and optional validation/normalization callbacks. It does not validate that static possible_values match type during construction.
__init__ ¶
__init__(
type,
possible_values=None,
depends_on=None,
*,
required=True,
min_value=None,
max_value=None,
validator=None,
normalizer=None
)
Create an Input specification with type information, constraints, and dependency metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type | INPUT_TYPE | Expected Python class for the input value. | required |
possible_values | PossibleValues | None | Allowed values as a domain, iterable, bucket, or callable returning one. | None |
depends_on | list[str] | None | Names of other inputs required for dynamic constraints. | None |
required | bool | Whether callers must provide a value for this input. | True |
min_value | ScalarConstraint | None | Inclusive lower bound for scalar values. | None |
max_value | ScalarConstraint | None | Inclusive upper bound for scalar values. | None |
validator | Validator | None | Extra validation callback returning | None |
normalizer | Normalizer | None | Optional callback used to canonicalize values after casting. | None |
Raises:
| Type | Description |
|---|---|
TypeError | If |
date_range classmethod ¶
date_range(
*,
start,
end,
frequency="day",
step=1,
depends_on=None,
required=True
)
Create a date input backed by a structured date range domain.
start and end may be dates or callbacks that accept declared dependency values. Dependency names are inferred from callback parameter names unless depends_on is supplied. The generated input normalizes non-daily frequencies to their canonical date before returning values from :meth:cast.
Raises:
| Type | Description |
|---|---|
InvalidDateRangeError | If bounds, frequency, or step are invalid after dependency callbacks have been resolved. |
TypeError | If a dependency callback cannot be invoked with the available dependency values. |
KeyError | If a dependent domain is resolved without a required dependency value. |
monthly_date classmethod ¶
monthly_date(
*,
start,
end,
anchor="month_end",
step=1,
depends_on=None,
required=True
)
Create a date input constrained to canonical monthly dates.
anchor accepts "start"/"month_start" and "end"/"month_end". Other values are forwarded as date-range frequencies and invalid values raise InvalidDateRangeError when the domain is built.
yearly_date classmethod ¶
yearly_date(
*,
start,
end,
anchor="year_end",
step=1,
depends_on=None,
required=True
)
Create a date input constrained to canonical yearly dates.
anchor accepts "start"/"year_start" and "end"/"year_end". Other values are forwarded as date-range frequencies and invalid values raise InvalidDateRangeError when the domain is built.
from_manager_query classmethod ¶
from_manager_query(
manager_type,
*,
query=None,
depends_on=None,
required=True
)
Create a manager input whose possible values come from a manager query.
With no query, possible values come from manager_type.all(). Mapping queries are passed to manager_type.filter(**query); callable queries receive dependency values and may return either a mapping or an already resolved iterable/bucket/domain.
Raises:
| Type | Description |
|---|---|
AttributeError | If |
TypeError | If a query callback cannot be invoked with the available dependency values. |
KeyError | If dependency values are missing when possible values are resolved. |
resolve_possible_values ¶
resolve_possible_values(
identification=None, *, cache_context=None
)
Resolve possible values for the current dependency context.
Static values are returned unchanged. Callable providers receive only declared dependency values, raising KeyError when a dependency is missing. When called inside a calculation run with cache_context, provider results are cached by owner class, field name, and declared dependency values; one-shot iterators are materialized before caching. Unhashable dependency values skip the cache and call the provider.
normalize ¶
normalize(
value, identification=None, *, cache_context=None
)
Canonicalize a cast value using domain or explicit normalization rules.
If possible_values is a static InputDomain, domain normalization runs even when no custom normalizer is configured. Dynamic possible values are resolved only when a custom normalizer exists; if that resolved value is an InputDomain, dynamic-domain normalization runs before the custom normalizer. Custom normalizers receive the converted value first, then positional dependency values, a domain keyword containing the resolved possible-values object or None, and named dependency values. Unsupported callback signatures raise the normal Python TypeError from invocation.
validate_bounds ¶
validate_bounds(value)
Return whether a value satisfies configured scalar bounds.
None is valid only for non-required inputs. For non-None values, Python comparison errors from incompatible value/bound types propagate.
validate_with_callable ¶
validate_with_callable(value, identification=None)
Return whether a value satisfies the configured validator callback.
None values bypass custom validators. Validator callbacks receive the candidate value first, followed by declared dependency values selected from identification. A None return is treated as a successful validation and callback exceptions propagate unchanged.
cast ¶
cast(value, identification=None, *, cache_context=None)
Convert a raw value to the configured input type and normalize it.
cast does not apply scalar bounds, possible-value membership checks, or the validator callback. Interface validation calls :meth:validate_bounds, possible-value membership, and :meth:validate_with_callable as separate steps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value | object | Raw value supplied by the caller. | required |
identification | dict[str, object] | None | Mapping of dependency input names to their current values, used by dynamic possible values, normalizers, and validators. | None |
Returns:
| Type | Description |
|---|---|
object | Value converted to the target type, or |
object |
|
Raises:
| Type | Description |
|---|---|
ValueError | If date, datetime, measurement, or fallback constructor conversion rejects the value. |
TypeError | If the configured type constructor or a callback cannot accept the supplied value/dependencies. |
KeyError | If normalization needs a declared dependency that is missing from |
Input(type, possible_values=None, depends_on=None, *, required=True, min_value=None, max_value=None, validator=None, normalizer=None) is the public descriptor used on calculation and custom interfaces. It stores the expected Python class, optional static or callable allowed values, scalar bounds, dependency names, and optional validation/normalization callbacks. Construction does not check that static possible_values match type; value casting and interface validation perform the runtime checks. Unless this section says a detail belongs to an owning interface, the behavior described here is the public contract for the exported Input and domain classes. Supported type values are Python class objects that issubclass(type, GeneralManager) and isinstance(value, type) can inspect. Manager-typed inputs declare a GeneralManager subclass; manager instances are instances of that declared manager class.
Input.cast(value, identification=None, *, cache_context=None) converts raw values to the configured type and then normalizes them. None is returned unchanged. date and datetime inputs accept native values and ISO strings; date inputs convert native datetime values to .date(), while datetime inputs convert native date values with datetime.combine(value, datetime.min.time()). ISO strings are parsed by Python's date.fromisoformat() or datetime.fromisoformat() exactly, including their normal timezone-aware datetime behavior. Manager-typed inputs accept either a mapping used as constructor keywords or a single value passed as id; existing manager instances skip construction but still pass through normalization. The id path constructs manager_type(id=value) and does not perform a query by itself. Mappings, including mappings with an id key, are passed as manager_type(**mapping); invalid keywords and manager constructors that do not accept id fail through the constructor's normal exception. For every other type, already-matching values pass through normalization and non-matching values are converted with type(value). Constructor errors propagate unchanged. Measurement inputs accept the strings documented for Measurement.from_string(). cast() does not apply scalar bounds, possible-value membership checks, or the validator callback; interface validation calls validate_bounds(), membership validation, and validate_with_callable() separately. Conversion ValueErrors, constructor/callback TypeErrors, and missing dependency KeyErrors propagate. identification is the current input-value mapping keyed by dependency input name; Input only reads the dependency names declared on that input.
Callable possible_values, validators, and normalizers receive only declared dependency values. Dependency names are supplied explicitly through depends_on or inferred from non-variadic callback parameters. resolve_possible_values() returns static values unchanged, invokes providers for the current dependency context, and uses run-scoped caching only when a cache context and active calculation run are present. Cache keys include the owner class, input field name, and frozen declared dependency values; there is no cross-run invalidation. Unhashable dependency values skip the run cache. Static possible values are returned as the original object, not copied or materialized. The cache lives only for the active CalculationRunContext; leaving that run ends the cache lifetime.
Callback invocation follows each callback's signature. Dependency names are inferred from callable possible_values in Input(...), from start/end callbacks in Input.date_range(...), and from callable query in Input.from_manager_query(...). Validator and normalizer callbacks do not infer dependencies by themselves; pass depends_on when they need other input values. Names such as value or domain are not reserved during inference. Dependency values are available as both positional values in declared dependency order and named keyword values. Positional-only parameters consume positional values; positional-or-keyword parameters consume positional values first and then named values; keyword-only parameters consume named values; *args receives remaining positional values; **kwargs receives remaining named values. Defaults are left for Python to apply when no dependency value is supplied for that parameter. Normalizers also receive the converted value before dependency values and may accept a domain keyword containing the resolved possible values or None. For example, with depends_on=["project"], a validator lambda value, project: ... gets the candidate first and the project second; a normalizer lambda value, project, domain=None: ... gets the converted value, project, and resolved possible-values object. Avoid naming dependencies value or domain for normalizers unless you intentionally want Python-style positional binding to win over the same keyword name.
normalize(value, ...) first applies static InputDomain normalization. Dynamic possible values are resolved only when a custom normalizer exists; if the resolved object is an InputDomain, dynamic-domain normalization then runs before the custom normalizer. The domain keyword receives the resolved possible-values object itself, including non-domain iterables or buckets, or None when there are no possible values. A callable possible-values provider that returns an InputDomain does not normalize values during cast() unless a custom normalizer is present; this is intentional compatibility behavior.
validate_bounds(value) returns True for None only when required=False. For non-None values it compares the value directly with configured scalar bounds, so incompatible mixed types raise ordinary Python comparison errors. validate_with_callable(value, identification=None) skips None, treats a validator result of None as success, and propagates validator exceptions. Validators receive the candidate value first, followed by declared dependency values from identification. On Input itself, validate_bounds(None) is the requiredness check; owning interfaces may combine it with their own input-shape validation before calling the rest of the pipeline.
Input.date_range(...), Input.monthly_date(...), and Input.yearly_date(...) build date inputs backed by DateRangeDomain; Input.from_manager_query(...) builds manager inputs whose possible values come from .all() or .filter(**query). These helpers are stable public API. Input does not define a public membership-validation helper for plain iterables, buckets, or callable results; that validation belongs to the owning interface. Static possible values that do not match the declared type therefore fail only when an owning interface validates membership or a configured normalizer/domain operation rejects them.
general_manager.manager.input.InputDomain dataclass ¶
Bases: Generic[VALUE_TYPE]
Structured description of an input domain.
The base domain stores a kind string, returns identity values from :meth:normalize, reports {"kind": kind} from :meth:metadata, and implements contains(value) as a safe membership check. Direct in checks call :meth:__contains__, which iterates over :meth:__iter__. On the base class that raises DomainIterationError because subclasses are responsible for finite iteration; call :meth:contains when callers need a false result instead of that eager-iteration error.
InputDomain is the base class for structured possible-value domains. It provides contains(value), normalize(value), metadata(), and iteration. The base class is intentionally not eagerly iterable and raises DomainIterationError; use concrete domains or custom subclasses for finite choices. The base normalize() is identity, base metadata() returns only {"kind": kind}, contains(value) catches TypeError from membership and returns False, and direct value in domain calls __contains__ and can propagate DomainIterationError from the base iterator or iteration errors from subclasses.
general_manager.manager.input.NumericRangeDomain dataclass ¶
Bases: InputDomain[int | float | Decimal]
Inclusive finite numeric range with optional stepping.
Values are valid only when they fall on the generated step sequence. If any bound, step, or candidate is a Decimal, membership and iteration use Decimal arithmetic and iteration yields Decimal values. Otherwise, if any bound, step, or candidate is a float, they use float arithmetic and iteration yields float values. Pure integer ranges yield int values. bool is not a documented numeric input type even though Python may treat it as an integer at runtime. Floating-point checks use max(1e-12, abs(step) * 1e-9) tolerance and decimal checks use the equivalent Decimal tolerance so endpoint and step comparisons remain stable for common decimal fractions.
NumericRangeDomain(min_value, max_value, step=1) represents an inclusive finite numeric range for int, float, or Decimal values. It raises InvalidNumericRangeError when step <= 0 or min_value > max_value. Float membership uses max(1e-12, abs(step) * 1e-9) tolerance, and decimal membership uses max(Decimal("1e-12"), abs(Decimal(str(step))) * Decimal("1e-9")), so stepped ranges such as 0.0 to 0.3 by 0.1 behave predictably. Values inside the bounds but not on the step sequence are rejected. If any bound, step, or candidate is a Decimal, checks use decimal arithmetic and iteration yields Decimal values. Otherwise, if any bound, step, or candidate is a float, checks use float arithmetic and iteration yields floats. Pure integer ranges yield integers. bool is not a documented numeric input type even though Python may treat it as an integer at runtime; callers should not rely on bool-specific behavior as part of this API.
general_manager.manager.input.DateRangeDomain dataclass ¶
Bases: InputDomain[date]
Inclusive finite date domain backed by a frequency and step.
Non-daily frequencies normalize candidate dates to the configured anchor before membership checks. week_end anchors to Sunday. Month and year steps advance by calendar months or years from the current anchored date; quarter steps advance by three-month intervals. Iteration starts at normalize(start) and stops once the next generated date would be greater than the raw end value, so unaligned starts may anchor before or after the supplied start date and unaligned ends are upper bounds rather than additional anchors. datetime values are accepted by membership checks and converted to their date component first; :meth:normalize itself is typed for date inputs.
DateRangeDomain(start, end, *, frequency="day", step=1) represents an inclusive finite date range. Supported frequencies are day, week_end, month_start, month_end, quarter_end, year_start, and year_end. Invalid bounds, non-positive steps, and unsupported frequencies raise InvalidDateRangeError. Membership checks convert datetime values to their date component, normalize non-daily candidates to the configured anchor, and then require that anchored date to appear in the generated range. week_end anchors to Sunday. Month and year steps advance by calendar months or years from the current anchored date; quarter steps advance by three-month intervals. Iteration starts at normalize(start) and stops when the next generated date would be greater than the raw end, so unaligned starts may anchor before or after the supplied start date and unaligned ends act as upper bounds. Examples: month_start normalizes 2024-02-15 to 2024-02-01; month_end normalizes it to 2024-02-29; quarter_end normalizes it to 2024-03-31; year_start normalizes it to 2024-01-01; year_end normalizes it to 2024-12-31.
general_manager.bucket.base_bucket.Bucket ¶
Bases: ABC, Generic[GeneralManagerType]
Abstract interface for lazily evaluated GeneralManager collections.
Concrete buckets provide their own storage type and reconstruction behavior. The base class stores only the manager class plus object-shaped lookup metadata so shared helpers such as grouping and run-scoped indexes can work across database, request, and calculation-backed collections.
__init__ ¶
__init__(manager_class)
Create a bucket bound to a specific manager class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manager_class | type[GeneralManagerType] | GeneralManager subclass whose instances this bucket represents. | required |
Returns:
| Type | Description |
|---|---|
None | None |
__eq__ ¶
__eq__(other)
Compare two buckets for equality.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | object | Object tested for equality with this bucket. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True when the buckets share the same class, manager class, and data payload. |
__reduce__ ¶
__reduce__()
Provide fallback pickling support by returning constructor arguments.
Subclasses with additional constructor requirements override this method. The fallback shape is kept for older bucket implementations that accepted (data, manager_class, filters, excludes).
Returns:
| Type | Description |
|---|---|
str | tuple[object, ...] | tuple[object, ...]: Reconstruction data for compatible subclasses. |
__or__ abstractmethod ¶
__or__(other)
Return a bucket containing the union of this bucket and another input.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | Bucket[GeneralManagerType] | GeneralManagerType | Bucket or single manager instance to merge. | required |
Returns:
| Type | Description |
|---|---|
Bucket[GeneralManagerType] | Bucket[GeneralManagerType]: New bucket with the combined contents. |
__iter__ abstractmethod ¶
__iter__()
Iterate over items in the bucket.
Yields:
| Name | Type | Description |
|---|---|---|
GeneralManagerType | GeneralManagerType | Items stored in the bucket. |
filter abstractmethod ¶
filter(**kwargs)
Return a bucket reduced to items matching the provided filters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field lookups applied to the underlying query. | {} |
Returns:
| Type | Description |
|---|---|
Bucket[GeneralManagerType] | Bucket[GeneralManagerType]: Filtered bucket instance. |
exclude abstractmethod ¶
exclude(**kwargs)
Return a bucket that excludes items matching the provided filters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field lookups specifying records to remove from the result. | {} |
Returns:
| Type | Description |
|---|---|
Bucket[GeneralManagerType] | Bucket[GeneralManagerType]: Bucket with the specified records excluded. |
first abstractmethod ¶
first()
Return the first item contained in the bucket.
Returns:
| Type | Description |
|---|---|
GeneralManagerType | None | GeneralManagerType | None: First entry if present, otherwise None. |
last abstractmethod ¶
last()
Return the last item contained in the bucket.
Returns:
| Type | Description |
|---|---|
GeneralManagerType | None | GeneralManagerType | None: Last entry if present, otherwise None. |
count abstractmethod ¶
count()
Return the number of items represented by the bucket.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Count of items. |
all abstractmethod ¶
all()
Return a bucket encompassing every item managed by this instance.
Returns:
| Type | Description |
|---|---|
Bucket[GeneralManagerType] | Bucket[GeneralManagerType]: Bucket without filters or exclusions. |
get abstractmethod ¶
get(**kwargs)
Retrieve a single item matching the provided criteria.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field lookups identifying the target record. | {} |
Returns:
| Name | Type | Description |
|---|---|---|
GeneralManagerType | GeneralManagerType | Matching item. |
__getitem__ abstractmethod ¶
__getitem__(item)
Retrieve an item or slice from the bucket.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | int | slice | Index or slice specifying the desired record(s). | required |
Returns:
| Type | Description |
|---|---|
GeneralManagerType | Bucket[GeneralManagerType] | GeneralManagerType | Bucket[GeneralManagerType]: Resulting item or bucket slice. |
__len__ abstractmethod ¶
__len__()
Return the number of items contained in the bucket.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Count of elements. |
__contains__ abstractmethod ¶
__contains__(item)
Checks whether the specified item is present in the bucket.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | GeneralManagerType | Manager instance evaluated for membership. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True if the bucket contains the provided instance. |
sort abstractmethod ¶
sort(key, reverse=False)
Return a sorted bucket.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key | str | tuple[str, ...] | Attribute name(s) used for sorting. | required |
reverse | bool | Whether to sort in descending order. | False |
Returns:
| Type | Description |
|---|---|
Bucket[GeneralManagerType] | Bucket[GeneralManagerType]: Sorted bucket instance. |
group_by ¶
group_by(*group_by_keys)
Materialise a grouped view of the bucket.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*group_by_keys | str | Attribute names used to form groups. | () |
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: Bucket grouping items by the provided keys. |
index_by ¶
index_by(key_spec, *, max_rows=1000)
Build or reuse a unique run-scoped index over this bucket.
Duplicate frozen keys raise an error because each key must identify one row. The result is cached only for the active calculation run and is separated by bucket object, key spec, unique-vs-many mode, and max_rows. If no run is active, the method creates a temporary run for this call, so there is no reuse across separate calls. Cached hits return the same mutable dictionary object stored for the run; treat it as read-only because mutations are visible to later same-run hits. Failed index construction does not store a cache entry, so later same-run calls retry the build. Validation order is max_rows, then key_spec, then bucket iteration. During iteration, the row guardrail is checked before key resolution for each row.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key_spec | BucketIndexKeySpec | One field name, or a non-empty tuple of field names for a composite key. Empty strings are accepted and passed to attribute lookup unchanged; mapping keys are not read unless the row also exposes them as attributes. | required |
max_rows | int | None | Maximum number of source rows to read before failing, or | 1000 |
Returns:
| Type | Description |
|---|---|
dict[Hashable, GeneralManagerType] | A dictionary mapping each frozen key to the single matching manager. |
dict[Hashable, GeneralManagerType] | Empty buckets return an empty dictionary. |
dict[Hashable, GeneralManagerType] | Frozen keys preserve already-hashable scalar values and normalize |
dict[Hashable, GeneralManagerType] | managers and containers into hashable identities suitable for lookup |
dict[Hashable, GeneralManagerType] | during the same process. |
Raises:
| Type | Description |
|---|---|
BucketIndexTooLargeError | If more than |
DuplicateBucketIndexKeyError | If two rows resolve to the same key. |
MissingBucketIndexKeyError | If a row lacks a requested key field. |
UnsupportedBucketIndexKeySpecError | If |
TypeError | If |
UnhashableBucketIndexKeyError | If a key value cannot be frozen. |
Exception | Exceptions raised while iterating the bucket propagates unchanged. |
index_many ¶
index_many(key_spec, *, max_rows=1000)
Build or reuse a run-scoped index that groups rows by key.
Values are tuples preserving source iteration order, and the cached result is scoped to the active calculation run. Cache entries are separated by bucket object, key spec, unique-vs-many mode, and max_rows. If no run is active, the method creates a temporary run for this call, so there is no reuse across separate calls. Cached hits return the same mutable dictionary object stored for the run; treat it as read-only because mutations are visible to later same-run hits. Failed index construction does not store a cache entry, so later same-run calls retry the build. Validation order is max_rows, then key_spec, then bucket iteration. During iteration, the row guardrail is checked before key resolution for each row.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key_spec | BucketIndexKeySpec | One field name, or a non-empty tuple of field names for a composite key. Empty strings are accepted and passed to attribute lookup unchanged; mapping keys are not read unless the row also exposes them as attributes. | required |
max_rows | int | None | Maximum number of source rows to read before failing, or | 1000 |
Returns:
| Type | Description |
|---|---|
dict[Hashable, tuple[GeneralManagerType, ...]] | A dictionary mapping each frozen key to matching managers in source |
dict[Hashable, tuple[GeneralManagerType, ...]] | order. Empty buckets return an empty dictionary. Frozen keys |
dict[Hashable, tuple[GeneralManagerType, ...]] | preserve already-hashable scalar values and normalize managers and |
dict[Hashable, tuple[GeneralManagerType, ...]] | containers into hashable identities suitable for lookup during the |
dict[Hashable, tuple[GeneralManagerType, ...]] | same process. |
Raises:
| Type | Description |
|---|---|
BucketIndexTooLargeError | If more than |
MissingBucketIndexKeyError | If a row lacks a requested key field. |
UnsupportedBucketIndexKeySpecError | If |
TypeError | If |
UnhashableBucketIndexKeyError | If a key value cannot be frozen. |
Exception | Exceptions raised while iterating the bucket propagates unchanged. |
general_manager.bucket.database_bucket.DatabaseBucket ¶
Bases: Bucket[GeneralManagerType]
Bucket implementation backed by Django ORM querysets.
__init__ ¶
__init__(
data,
manager_class,
filter_definitions=None,
exclude_definitions=None,
*,
search_date=None,
sort_keys=None,
sort_reverse=False,
run_scoped_cacheable=True
)
Instantiate a database-backed bucket with optional filter state.
Filter and exclude definitions are copied into bucket-owned dictionaries, so later mutations to caller-provided mappings do not change this bucket. Pickle reconstruction restores through primary-key snapshots rather than by serializing the queryset object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data | QuerySet[Model] | Queryset providing the underlying data. | required |
manager_class | type[GeneralManagerType] | GeneralManager subclass used to wrap rows. | required |
filter_definitions | FilterDefinitions | None | Pre-existing filter expressions captured from parent buckets. | None |
exclude_definitions | FilterDefinitions | None | Pre-existing exclusion expressions captured from parent buckets. | None |
search_date | datetime | date | None | Optional timestamp applied when instantiating manager instances. | None |
sort_keys | tuple[str, ...] | None | Property names used by a previous bucket sort operation. | None |
sort_reverse | bool | Whether sorted keys should be interpreted in descending order for dependency tracking. | False |
run_scoped_cacheable | bool | Whether terminal results from this bucket are safe to reuse inside the active calculation run. | True |
Returns:
| Type | Description |
|---|---|
None | None |
__reduce__ ¶
__reduce__()
Preserve a result snapshot without serializing the queryset object.
Reducing a bucket records the effective filter/exclude dependencies, materializes primary keys in queryset order, rejects duplicate primary keys with DuplicateDatabaseBucketSnapshotError, and restores through the original model default manager on the original database alias by filtering those primary keys and preserving the snapshot order.
__iter__ ¶
__iter__()
Iterate over manager instances corresponding to the queryset rows.
Safe run-scoped row snapshots are reused when present. Otherwise cached primary-key snapshots are reused when available, and the queryset is iterated as trusted ORM rows when possible. Rows are trusted only when they match the interface model, are not deferred, and historical buckets expose history state. Untrusted rows fall back to primary-key manager construction. search_date is passed through when managers are built from primary keys or trusted rows.
Yields:
| Name | Type | Description |
|---|---|---|
GeneralManagerType | GeneralManagerType | Manager instance for each primary key in the queryset. |
__or__ ¶
__or__(other)
Produce a new DatabaseBucket representing the union of this bucket with another DatabaseBucket or a GeneralManager instance of the same manager class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | Bucket[GeneralManagerType] | GeneralManagerType | The bucket or manager instance to merge with this bucket. | required |
Returns:
| Type | Description |
|---|---|
DatabaseBucket[GeneralManagerType] | DatabaseBucket[GeneralManagerType]: A new bucket containing the combined items from both operands. |
Raises:
| Type | Description |
|---|---|
DatabaseBucketTypeMismatchError | If |
DatabaseBucketManagerMismatchError | If |
DatabaseBucketSearchDateMismatchError | If both buckets target the same manager but have different search dates. |
__merge_filter_definitions ¶
__merge_filter_definitions(basis, **kwargs)
Merge stored filter definitions with additional lookup values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
basis | FilterDefinitions | Existing lookup definitions copied into the result. | required |
**kwargs | LookupValue | New lookups whose values are appended to the result mapping. | {} |
Returns:
| Name | Type | Description |
|---|---|---|
FilterDefinitions | FilterDefinitions | Combined mapping of lookups to value lists. |
__parse_filter_definitions ¶
__parse_filter_definitions(**kwargs)
Split provided filter kwargs into three parts: query annotations required by properties, ORM-compatible lookup mappings, and Python-evaluated filter specifications.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | LookupValue | Filter lookups supplied to | {} |
Returns:
| Name | Type | Description |
|---|---|---|
tuple | tuple[dict[str, QueryAnnotation], LookupMapping, list[PythonFilterDefinition]] |
|
Raises:
| Type | Description |
|---|---|
NonFilterablePropertyError | If a lookup targets a property that is not allowed to be filtered. |
__parse_python_filters ¶
__parse_python_filters(query_set, python_filters)
Evaluate Python-only filters and return the primary keys that satisfy them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query_set | QuerySet[Model] | Queryset to inspect. | required |
python_filters | list[tuple[str, object, str]] | Filters requiring Python evaluation, each containing the lookup, value, and property root. | required |
Returns:
| Type | Description |
|---|---|
list[object] | list[object]: Primary keys of rows that meet all Python-evaluated filters. |
filter ¶
filter(**kwargs)
Return a new DatabaseBucket refined by the given Django-style lookup expressions.
search_date is a reserved kwarg consumed by the bucket and preserved on the returned bucket. Remaining kwargs are split between ORM lookups, query-annotated properties, and Python-only property filters. Python-only property filters evaluate the candidate rows in Python and narrow the queryset by the matching primary keys. Stored filter definitions are copied before the new lookups are appended, so parent and child buckets do not share nested lookup lists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Django-style lookup expressions to apply to the underlying queryset, plus optional reserved | {} |
Returns:
| Type | Description |
|---|---|
DatabaseBucket[GeneralManagerType] | DatabaseBucket[GeneralManagerType]: New bucket containing items matching the existing state combined with the provided lookups. |
Raises:
| Type | Description |
|---|---|
NonFilterablePropertyError | If a provided property is not filterable for this manager. |
InvalidQueryAnnotationTypeError | If a query-annotation callback returns a non-QuerySet. |
QuerysetFilteringError | If Django raises |
exclude ¶
exclude(**kwargs)
Produce a bucket that excludes rows matching the provided Django-style lookup expressions.
Accepts ORM lookups, query annotation entries, and Python-only filters; annotation callables will be applied to the underlying queryset as needed. search_date is a reserved kwarg consumed by the bucket and preserved on the returned bucket. Python-only property filters evaluate candidate rows in Python and then exclude the matching primary keys. Stored exclude definitions are copied before new lookups are appended, so parent and child buckets do not share nested lookup lists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Django-style lookup expressions, annotation entries, or property-based filters used to identify records to exclude. | {} |
Returns:
| Type | Description |
|---|---|
DatabaseBucket[GeneralManagerType] | DatabaseBucket[GeneralManagerType]: A new bucket whose queryset omits rows matching the provided lookups. |
Raises:
| Type | Description |
|---|---|
NonFilterablePropertyError | If a provided property is not filterable for this manager. |
InvalidQueryAnnotationTypeError | If an annotation callable is applied and does not return a Django QuerySet. |
QuerysetFilteringError | If Django raises |
first ¶
first()
Return the first row in the queryset as a manager instance.
Reuses safe cached row snapshots or primary-key snapshots when present; otherwise delegates to queryset first().
Returns:
| Type | Description |
|---|---|
GeneralManagerType | None | GeneralManagerType | None: First manager instance if available. |
last ¶
last()
Return the last row in the queryset as a manager instance.
Reuses safe cached row snapshots or primary-key snapshots when present; otherwise delegates to queryset last().
Returns:
| Type | Description |
|---|---|
GeneralManagerType | None | GeneralManagerType | None: Last manager instance if available. |
count ¶
count()
Count the number of rows represented by the bucket.
A safe run-scoped primary-key snapshot is reused when present; otherwise this delegates to the queryset count.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Number of represented rows. |
all ¶
all()
Return a new lazy bucket wrapping self._data.all().
Filter definitions, exclusion definitions, search date, sort metadata, and run-scoped cacheability are preserved on the returned bucket.
Returns:
| Type | Description |
|---|---|
DatabaseBucket[GeneralManagerType] | DatabaseBucket[GeneralManagerType]: Bucket encapsulating |
get ¶
get(**kwargs)
Retrieve a single manager instance matching the provided lookups.
When a run-scoped row or primary-key snapshot is already available and the lookup is exactly one pk or id value, the snapshot is used before falling back to queryset get(). Snapshot lookups preserve the queryset's DoesNotExist and MultipleObjectsReturned behavior.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field lookups resolved via | {} |
Returns:
| Name | Type | Description |
|---|---|---|
GeneralManagerType | GeneralManagerType | Manager instance wrapping the matched model. |
Raises:
| Type | Description |
|---|---|
ObjectDoesNotExist | Propagated from the underlying queryset when no row matches. |
MultipleObjectsReturned | Propagated when multiple rows satisfy the lookup. |
__getitem__ ¶
__getitem__(item)
Access manager instances by index or obtain a sliced bucket.
Slices return a lazy DatabaseBucket. Scalar indexes return a manager instance; when a run-scoped snapshot path is used, negative scalar indexes raise ValueError. Otherwise normal Django queryset indexing exceptions propagate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | int | slice | Index of the desired row or slice object describing a range. | required |
Returns:
| Type | Description |
|---|---|
GeneralManagerType | DatabaseBucket[GeneralManagerType] | GeneralManagerType | DatabaseBucket[GeneralManagerType]: Manager instance for single indices or bucket wrapping the sliced queryset. |
__bool__ ¶
__bool__()
Return whether the bucket contains at least one row without counting all rows.
Truthiness is an existence check, not a cardinality request. Reuse any active run-context snapshot first, then cache a queryset exists() result for equivalent trusted querysets in the same calculation run.
__len__ ¶
__len__()
Return the number of rows represented by the bucket.
Delegates to count() so dependency tracking, run-scoped snapshots, and queryset fallback behavior stay aligned between both cardinality paths.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Number of represented rows. |
__str__ ¶
__str__()
Return a user-friendly representation of the bucket.
Returns:
| Name | Type | Description |
|---|---|---|
str | str | Human-readable description of the queryset and manager class. |
__repr__ ¶
__repr__()
Return a debug representation of the bucket.
Returns:
| Name | Type | Description |
|---|---|---|
str | str | Detailed description including queryset, manager class, filters, and excludes. |
group_by ¶
group_by(*group_by_keys)
Group only when this bucket matches the active historical instant.
__contains__ ¶
__contains__(item)
Determine whether the provided instance belongs to the bucket.
Manager instances are matched by identification["id"] and Django models by pk. Missing identifiers return False. A safe run-scoped primary-key snapshot is used when present; otherwise the bucket performs a targeted queryset exists() lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | GeneralManagerType | Model | Manager or model instance whose primary key is checked. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True when the primary key exists in the queryset. |
sort ¶
sort(key, reverse=False)
Return a new DatabaseBucket ordered by the given property name(s).
Accepts a single property name or a tuple of property names. Properties with ORM annotations are applied at the database level; properties without ORM annotations are evaluated in Python and the resulting records are re-ordered while preserving a queryset result. Python-only sorts materialize candidate rows, sort them in memory, then preserve that materialized order with a Django Case annotation. Stable ordering and preservation of manager wrapping are maintained.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key | str | tuple[str, ...] | Property name or sequence of property names to sort by, applied in order of appearance. | required |
reverse | bool | If True, sort each specified key in descending order. | False |
Returns:
| Type | Description |
|---|---|
DatabaseBucket[GeneralManagerType] | DatabaseBucket[GeneralManagerType]: A new bucket whose underlying queryset is ordered according to the requested keys. |
Raises:
| Type | Description |
|---|---|
NonSortablePropertyError | If any requested property is not marked as sortable on the manager's GraphQL properties. |
InvalidQueryAnnotationTypeError | If a property query annotation callable returns a non-QuerySet value. |
QuerysetOrderingError | If the ORM rejects the constructed ordering (e.g., invalid field or incompatible ordering expression). |
none ¶
none()
Return an empty bucket sharing the same manager class.
Preserves copied filter/exclude state, search date, sort metadata, and run-scoped cacheability from all() before replacing the queryset with QuerySet.none().
Returns:
| Type | Description |
|---|---|
DatabaseBucket[GeneralManagerType] | DatabaseBucket[GeneralManagerType]: Empty bucket retaining manager and query context. |
DatabaseBucket is the ORM-backed collection returned by database and existing-model managers. It keeps Django queryset laziness for builder methods such as filter(), exclude(), all(), sort(), and slicing, then wraps model rows as the configured manager class when terminal operations evaluate the query. The constructor accepts a Django QuerySet, the manager class, optional filter/exclude snapshots, optional search_date, sort metadata, and the run-scoped cache flag. Those lookup snapshots are copied into bucket-owned dictionaries, so mutating the original mappings after construction does not change the bucket.
Common cookbook patterns:
active = Project.filter(status="active")
first = active.sort("name").first()
total = active.count()
if first is not None and first in active:
visible_names = [project.name for project in active[0:10]]
count() and len(bucket) return the queryset count unless a safe run-scoped snapshot already exists. first(), last(), scalar indexing, iteration, and membership checks record the effective dependency before reading rows; membership uses the candidate manager's identification["id"] or a model instance's primary key and returns False for unsaved objects. Python-only @graph_ql_property filters and sorts are supported only when the property is marked filterable or sortable; non-filterable properties raise NonFilterablePropertyError, non-sortable properties raise NonSortablePropertyError, invalid query annotations raise InvalidQueryAnnotationTypeError, and rejected ORM filter/order expressions are wrapped as QuerysetFilteringError or QuerysetOrderingError.
Run-scoped reuse is conservative. Database buckets bypass snapshot reuse for select-for-update, combined, distinct, prefetch-related, deferred-field, invalid, or oversized queryset shapes. When a safe row snapshot exists, terminal helpers reuse trusted ORM rows; otherwise they can reuse cached primary keys or evaluate the queryset normally. Historical buckets pass search_date into constructed managers and only trust ORM rows that expose history state. Pickled bucket snapshots store primary keys in queryset order, reject duplicate primary keys, and restore by filtering those primary keys through the original model/database alias while preserving the snapshot order. filter() and exclude() copy their stored lookup snapshots before appending new lookups, and get() only answers cached snapshots for single-key pk or id lookups. Python-only property sorts materialize candidate rows, sort them in memory, then preserve the materialized order with a Django Case annotation. Combining database buckets with | requires the same bucket type, manager class, and search_date; union buckets disable run-scoped result reuse. none() keeps the same manager, filter/exclude snapshots, search date, sort metadata, and cache flag while replacing the queryset with an empty queryset.
general_manager.bucket.group_bucket.GroupBucket ¶
Bases: Generic[GeneralManagerType]
Bucket variant that groups managers by specified attributes.
__init__ ¶
__init__(manager_class, group_by_keys, data)
Build a grouping bucket from the provided base data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manager_class | type[GeneralManagerType] | GeneralManager subclass represented by the bucket. | required |
group_by_keys | tuple[str, ...] | Attribute names used to define each group. | required |
data | Bucket[GeneralManagerType] | Source bucket whose entries are grouped. | required |
Returns:
| Type | Description |
|---|---|
None | None |
Raises:
| Type | Description |
|---|---|
TypeError | If a group-by key is not a string. |
ValueError | If a group-by key is not a valid manager attribute. |
__eq__ ¶
__eq__(other)
Compare by unordered group set, manager class, and grouping keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | object | Object compared against the current bucket. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True when both buckets contain the same set of groups and use the same manager class and grouping-key tuple. Group order is not part of equality. |
__check_group_by_arguments ¶
__check_group_by_arguments(group_by_keys)
Validate that each provided group-by key is a string and is exposed by the manager interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
group_by_keys | tuple[str, ...] | Attribute names to use for grouping. | required |
Raises:
| Type | Description |
|---|---|
InvalidGroupByKeyTypeError | If any element of |
UnknownGroupByKeyError | If any key is not listed in the manager class's interface attributes. |
__build_grouped_manager ¶
__build_grouped_manager(data)
Builds a GroupManager for each distinct combination of configured group-by attribute values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data | Bucket[GeneralManagerType] | Source bucket whose entries are partitioned by the bucket's configured group-by keys. | required |
Returns:
| Type | Description |
|---|---|
list[GroupManager[GeneralManagerType]] | list[GroupManager[GeneralManagerType]]: A list of GroupManager objects, one per unique tuple of group-by key values; groups are produced in order sorted by the string representation of their key tuples. |
__or__ ¶
__or__(other)
Return a new GroupBucket representing the union of this bucket and another compatible GroupBucket.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | GroupBucket | The grouping bucket to merge with this one. | required |
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: A GroupBucket with the same manager class and grouping keys whose basis data is the union of both inputs. |
Raises:
| Type | Description |
|---|---|
GroupBucketTypeMismatchError | If |
GroupBucketManagerMismatchError | If |
GroupBucketKeysMismatchError | If |
__reduce__ ¶
__reduce__()
Provide pickling support with constructor and current basis data.
Returns:
| Type | Description |
|---|---|
str | tuple[object, ...] | tuple[object, ...]: |
__iter__ ¶
__iter__()
Iterate over the grouped managers produced by this bucket.
Yields:
| Type | Description |
|---|---|
GroupManager[GeneralManagerType] | GroupManager[GeneralManagerType]: Individual group manager instances. |
filter ¶
filter(**kwargs)
Return a grouped bucket filtered by the provided lookups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field lookups evaluated against the underlying bucket. | {} |
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: Grouped bucket containing only matching records. |
exclude ¶
exclude(**kwargs)
Return a grouped bucket that excludes records matching the provided lookups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field lookups whose matches should be removed from the underlying bucket. | {} |
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: Grouped bucket built from the filtered base data. |
first ¶
first()
Return the first grouped manager in the collection.
Returns:
| Type | Description |
|---|---|
GroupManager[GeneralManagerType] | None | GroupManager[GeneralManagerType] | None: First group when available. |
last ¶
last()
Return the last grouped manager in the collection.
Returns:
| Type | Description |
|---|---|
GroupManager[GeneralManagerType] | None | GroupManager[GeneralManagerType] | None: Last group when available. |
count ¶
count()
Count the number of grouped managers in the bucket.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Number of groups. |
all ¶
all()
Return the current grouping bucket.
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: This instance. |
get ¶
get(**kwargs)
Retrieve the first GroupManager matching the provided lookups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field lookups used to filter the grouped managers. | {} |
Returns:
| Type | Description |
|---|---|
GroupManager[GeneralManagerType] | The first matching GroupManager. |
Raises:
| Type | Description |
|---|---|
GroupItemNotFoundError | If no grouped manager matches the filters. |
__getitem__ ¶
__getitem__(item)
Retrieve a single grouped manager by index or construct a new GroupBucket from a slice of groups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | int | slice | Integer index to select a single GroupManager, or a slice to select a subsequence of groups. | required |
Returns:
| Type | Description |
|---|---|
GroupManager[GeneralManagerType] | GroupBucket[GeneralManagerType] | GroupManager[GeneralManagerType] if |
Raises:
| Type | Description |
|---|---|
EmptyGroupBucketSliceError | If the slice selects no groups. |
InvalidGroupBucketIndexError | If |
__len__ ¶
__len__()
Return the number of grouped managers.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Number of groups. |
__contains__ ¶
__contains__(item)
Determine whether the given manager instance exists in the underlying data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | GeneralManagerType | Manager instance checked for membership. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True if the instance is present in the basis data. |
sort ¶
sort(key, reverse=False)
Return a new GroupBucket sorted by the specified attributes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key | str | tuple[str, ...] | Attribute name(s) used for sorting. | required |
reverse | bool | Whether to apply descending order. | False |
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: Sorted grouping bucket. |
group_by ¶
group_by(*group_by_keys)
Extend the grouping with additional attribute keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*group_by_keys | str | Attribute names appended to the current grouping. | () |
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: New bucket grouped by the combined key set. |
none ¶
none()
Produce an empty grouping bucket that preserves the current configuration.
Returns:
| Type | Description |
|---|---|
GroupBucket[GeneralManagerType] | GroupBucket[GeneralManagerType]: Empty grouping bucket with identical manager class and grouping keys. |
GroupBucket is the grouped view returned by bucket.group_by(...). It materializes one GroupManager per distinct tuple of group-by values from the source bucket. Group keys must be strings listed by the manager interface's attributes; non-string keys raise InvalidGroupByKeyTypeError, and unknown keys raise UnknownGroupByKeyError. Group values are frozen into hashable identities so manager-valued keys compare by manager class plus sorted identification items, lists and tuples compare by element identities, sets compare as frozensets, mapping values compare by recursively frozen key/value pairs sorted by repr, and other values use their raw hashable value. Groups are emitted in str(group_by_value) sort order. Equality ignores that order and compares the set of groups plus manager class and grouping-key tuple. Pickle reconstruction uses (GroupBucket, (manager_class, group_by_keys, basis_data)), rebuilding groups from the stored basis bucket.
For manager-valued group keys, the source bucket slice is rebuilt with relation lookups derived from the grouped manager identification. Attribute metadata filter_lookup is used when present; otherwise the group key name is used. filter(**lookups) and exclude(**lookups) delegate to the underlying basis bucket and then rebuild the grouped view. get(**lookups) returns the first matching group after that filtering step and raises GroupItemNotFoundError when no group remains; it does not enforce uniqueness. first() and last() return a group or None, while count() and len(bucket) count groups.
Scalar indexing returns a GroupManager. Slicing unions the selected groups' underlying basis buckets and returns a new GroupBucket; an empty slice raises EmptyGroupBucketSliceError, and non-int/non-slice indexes raise InvalidGroupBucketIndexError. all() returns self. none() returns a new empty grouped bucket with the same manager class and grouping keys. Membership checks test whether the supplied manager instance is present in the underlying basis bucket, not whether a matching group key exists.
sort(key, reverse=False) sorts the current groups in memory by one attribute name or a tuple of attribute names, returning a new grouped bucket with the same basis bucket and sorted group list. Missing sort attributes propagate AttributeError, and incomparable values propagate Python TypeError. The | operator combines compatible grouped buckets by unioning their basis buckets and regrouping; operands must be GroupBucket instances of the same concrete class, manager class, and grouping-key tuple. Mismatches raise GroupBucketTypeMismatchError, GroupBucketManagerMismatchError, or GroupBucketKeysMismatchError.
general_manager.bucket.calculation_bucket.CalculationBucket ¶
Bases: Bucket[GeneralManagerType]
Bucket that builds cartesian products of calculation input fields.
__init__ ¶
__init__(
manager_class,
filter_definitions=None,
exclude_definitions=None,
sort_key=None,
reverse=False,
)
Initialize a CalculationBucket configured to enumerate all valid input combinations for a manager.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manager_class | type[GeneralManagerType] | Manager subclass whose Interface must inherit from CalculationInterface. | required |
filter_definitions | dict[str, dict] | None | Mapping of input/property filter constraints to apply to generated combinations. | None |
exclude_definitions | dict[str, dict] | None | Mapping of input/property exclude constraints to remove generated combinations. | None |
sort_key | str | tuple[str] | None | Key name or tuple of key names used to order generated manager combinations. | None |
reverse | bool | If True, reverse the ordering defined by | False |
Raises:
| Type | Description |
|---|---|
InvalidCalculationInterfaceError | If the manager_class.Interface does not inherit from CalculationInterface. |
__eq__ ¶
__eq__(other)
Compare two calculation buckets for structural equality.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | object | Candidate bucket. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True when both buckets share the same manager class and identical filter/exclude state. |
__reduce__ ¶
__reduce__()
Provide pickling support for calculation buckets.
Returns:
| Type | Description |
|---|---|
generalManagerClassName | tuple[object, ...] | tuple[object, ...]: Reconstruction data representing the class, arguments, and state. |
__setstate__ ¶
__setstate__(state)
Restore the bucket after unpickling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state | dict[str, object] | Pickled state containing cached combination data. | required |
Returns:
| Type | Description |
|---|---|
None | None |
__or__ ¶
__or__(other)
Build a bucket from constraints common to this bucket and another operand.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other | Bucket[GeneralManagerType] | GeneralManagerType | A CalculationBucket or a GeneralManager instance to combine. If a same-class manager instance is given, it is first converted into an | required |
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManagerType] | A new CalculationBucket containing only filter and exclude |
CalculationBucket[GeneralManagerType] | definitions that are present with equal values on both bucket |
CalculationBucket[GeneralManagerType] | operands. This is a compatibility-preserving common-constraint |
CalculationBucket[GeneralManagerType] | merge, not a set union of materialized calculation results. |
Raises:
| Type | Description |
|---|---|
IncompatibleBucketTypeError | If |
IncompatibleBucketManagerError | If |
__str__ ¶
__str__()
Return a compact preview of generated combinations.
Cached buckets include the exact combination count. Uncached buckets avoid materializing all combinations for string formatting; when more than the preview limit exists, the count is reported as a lower-bound label.
Returns:
| Name | Type | Description |
|---|---|---|
str | str | Human-readable summary of up to five combinations. |
__repr__ ¶
__repr__()
Return a detailed representation of the bucket configuration.
Returns:
| Name | Type | Description |
|---|---|---|
str | str | Debug string listing filters, excludes, sort key, and ordering. |
transform_properties_to_input_fields staticmethod ¶
transform_properties_to_input_fields(
properties, input_fields
)
Derive input-field definitions for GraphQL properties without explicit inputs.
This helper is a framework hook used by calculation filtering and sorting. It treats list, tuple, set, union, and optional property type hints as their concrete element/member type when possible and falls back to object when the hint cannot be resolved to a class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
properties | dict[str, GraphQLProperty] | GraphQL properties declared on the manager. | required |
input_fields | dict[str, Input] | Existing input field definitions. | required |
Returns:
| Type | Description |
|---|---|
dict[str, Input[type[object]]] | dict[str, Input]: Combined mapping of input field names to |
filter ¶
filter(**kwargs)
Add additional filters and return a new calculation bucket.
Lookup keys use the shared calculation filter grammar: field or field__lookup for input and property values. Supported Python lookup operators are exact, lt, lte, gt, gte, contains, startswith, endswith, and in. For manager-typed inputs, field=value filters by the manager id, field_id is an id alias, and suffixes such as field__name__startswith are forwarded to the nested manager bucket. Unknown fields raise UnknownInputFieldError from the filter parser.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Filter expressions applied to generated combinations. | {} |
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManagerType] | CalculationBucket[GeneralManagerType]: Bucket reflecting the updated filter definitions. |
Raises:
| Type | Description |
|---|---|
UnknownInputFieldError | If a filter key references no input or derived GraphQL property. |
TypeError | Propagated from invalid input casts or downstream manager-bucket filtering. |
ValueError | Propagated from input parsing or normalization. |
exclude ¶
exclude(**kwargs)
Add additional exclusion rules and return a new calculation bucket.
Exclusion keys use the same lookup grammar and error behavior as :meth:filter; matching combinations are removed rather than kept.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Exclusion expressions removing combinations from the result. | {} |
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManagerType] | CalculationBucket[GeneralManagerType]: Bucket reflecting the updated exclusion definitions. |
Raises:
| Type | Description |
|---|---|
UnknownInputFieldError | If an exclude key references no input or derived GraphQL property. |
TypeError | Propagated from invalid input casts or downstream manager-bucket filtering. |
ValueError | Propagated from input parsing or normalization. |
all ¶
all()
Return a deep copy of this calculation bucket.
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManagerType] | CalculationBucket[GeneralManagerType]: Independent copy that can be mutated without affecting the original. |
__iter__ ¶
__iter__()
Iterate over every generated combination as a manager instance.
Yields:
| Name | Type | Description |
|---|---|---|
GeneralManagerType | GeneralManagerType | Manager constructed from each valid set of inputs. |
generate_combinations ¶
generate_combinations()
Compute (and cache) the list of valid input combinations.
This framework helper materializes the bucket. It orders inputs by dependency, applies input-level filters/excludes while enumerating candidate values, then applies property-level filters/excludes and sorting when manager access is required. The returned list is the bucket's cached mutable list; callers should treat it as read-only.
Returns:
| Type | Description |
|---|---|
List[Combination] | list[Combination]: Cached list of input dictionaries satisfying filters, excludes, and ordering. |
Raises:
| Type | Description |
|---|---|
CyclicDependencyError | If input dependencies contain a cycle. |
InvalidPossibleValuesError | If a required input cannot provide iterable or bucket-backed possible values. |
UnknownInputFieldError | If stored filter definitions reference an unknown input or property. |
AttributeError | Propagated from missing computed properties during property filtering or sorting. |
TypeError | Propagated from invalid casts, downstream bucket filtering, or incomparable sort values. |
ValueError | Propagated from input parsing or normalization. |
topological_sort_inputs ¶
topological_sort_inputs()
Produce a dependency-respecting order of input fields.
This framework helper includes every configured input name and orders dependencies before the inputs that depend on them.
Returns:
| Type | Description |
|---|---|
List[str] | list[str]: Input names ordered so each dependency appears before its dependents. |
Raises:
| Type | Description |
|---|---|
CyclicDependencyError | If the dependency graph contains a cycle; the exception's |
get_possible_values ¶
get_possible_values(key_name, input_field, current_combo)
Resolve potential values for an input field based on the current partial input combination.
This framework helper resolves static, callable, domain, iterable, or bucket-backed possible_values for one input. Optional inputs with no possible-values source return None; required inputs without a valid iterable, domain, or bucket source raise InvalidPossibleValuesError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key_name | str | Name of the input field used for error context. | required |
input_field | Input | Input definition that may include | required |
current_combo | dict | Partial mapping of already-selected input values required to evaluate dependencies. | required |
Returns:
| Type | Description |
|---|---|
Union[Iterable[object], Bucket['GeneralManager'], None] | Iterable[object] | Bucket[GeneralManager] | None: An iterable of allowed values for the input, a Bucket supplying candidate values, or |
Raises:
| Type | Description |
|---|---|
InvalidPossibleValuesError | If the input field's |
first ¶
first()
Return the first generated manager instance.
Returns:
| Type | Description |
|---|---|
GeneralManagerType | None | GeneralManagerType | None: First instance or None when no combinations exist. |
last ¶
last()
Return the last generated manager instance.
Returns:
| Type | Description |
|---|---|
GeneralManagerType | None | GeneralManagerType | None: Last instance or None when no combinations exist. |
count ¶
count()
Return the number of calculation combinations.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Number of generated combinations. |
__len__ ¶
__len__()
Return the number of generated combinations.
Returns:
| Name | Type | Description |
|---|---|---|
int | int | Cached number of combinations. |
__getitem__ ¶
__getitem__(item)
Retrieve a manager instance or subset of combinations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | int | slice | Index or slice specifying which combinations to return. | required |
Returns:
| Type | Description |
|---|---|
GeneralManagerType | CalculationBucket[GeneralManagerType] | GeneralManagerType | CalculationBucket[GeneralManagerType]: Manager instance for single indices or bucket wrapping the sliced combinations. |
__contains__ ¶
__contains__(item)
Determine whether the provided manager instance exists among generated combinations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item | GeneralManagerType | Manager instance to test for membership. | required |
Returns:
| Name | Type | Description |
|---|---|---|
bool | bool | True when the instance matches one of the generated combinations. |
get ¶
get(**kwargs)
Return the single manager instance that matches the provided field filters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs | object | Field filters to apply when selecting a calculation (e.g., property or input names mapped to expected values). | {} |
Returns:
| Type | Description |
|---|---|
GeneralManagerType | The single manager instance that satisfies the provided filters. |
Raises:
| Type | Description |
|---|---|
MissingCalculationMatchError | If no matching manager exists. |
MultipleCalculationMatchError | If more than one matching manager exists. |
sort ¶
sort(key, reverse=False)
Create a new CalculationBucket configured to order generated combinations by the given attribute key.
Sorting by raw input keys happens before managers are built. Sorting by computed properties builds manager instances and reads the named attributes. Missing attributes raise AttributeError when the bucket materializes; incomparable values raise TypeError from Python's sort. Exceptions raised by computed properties propagate unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key | str | tuple[str] | Attribute name or tuple of attribute names to use for ordering generated manager combinations. | required |
reverse | bool | If True, sort in descending order. | False |
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManagerType] | A new CalculationBucket configured to sort combinations by the provided key and direction. |
group_by ¶
group_by(*group_by_keys)
Group this bucket only when its snapshot matches the active context.
none ¶
none()
Return an empty calculation bucket for the same manager class.
The returned bucket starts from an all() copy, then clears cached data and raw/parsed filter and exclude definitions. It preserves the manager class, sort key, and reverse flag.
Returns:
| Type | Description |
|---|---|
CalculationBucket[GeneralManagerType] | CalculationBucket[GeneralManagerType]: Bucket with no combinations |
CalculationBucket[GeneralManagerType] | and cleared filter/exclude state. |
CalculationBucket is the lazy collection behind calculation-manager all(), filter(), and exclude(). It stores raw filter/exclude definitions, parses them against calculation inputs and derived GraphQL properties, and materializes combinations only when iterated, counted, indexed, or converted to text. all() returns an independent copy. filter(**kwargs) and exclude(**kwargs) return new buckets with additional lookup definitions. Keys use field or field__lookup; Python-level lookup operators are exact, lt, lte, gt, gte, contains, startswith, endswith, and in. Manager-typed inputs can be filtered by the manager object, by <input>_id, or by nested manager lookups such as project__name__startswith. Derived GraphQL properties can be filtered with the same Python lookup operators and do not use the database-bucket filterable marker. Unknown filter or exclude fields raise UnknownInputFieldError from general_manager.utils.filter_parser.
Terminal helpers mirror the other bucket types: first() and last() return a manager or None, get(**kwargs) requires exactly one match and raises MissingCalculationMatchError or MultipleCalculationMatchError otherwise, count() and len(bucket) count generated combinations, scalar indexing returns a manager instance, slicing returns a new bucket with cached combinations, and none() returns an empty bucket with the same manager class, sort key, and reverse flag while clearing raw and parsed filters/excludes. Sorting accepts one key or a tuple of keys and can sort either raw inputs or computed properties. Missing sort attributes raise AttributeError, incomparable sort values raise TypeError, and computed-property exceptions propagate unchanged when the bucket materializes. Invalid calculation interfaces raise InvalidCalculationInterfaceError, incompatible bucket unions raise IncompatibleBucketTypeError or IncompatibleBucketManagerError, cyclic input dependencies raise CyclicDependencyError, and required inputs without an iterable or bucket-backed domain raise InvalidPossibleValuesError.
The | operator is a compatibility merge for calculation buckets, not a materialized set union. Combining two compatible CalculationBucket instances keeps only filter and exclude definitions that exist with equal values on both operands, producing a bucket for their common constraints. Passing a same-class manager instance first converts that instance into an id__in=[identification] filter bucket before applying the same common-constraint merge.
generate_combinations(), topological_sort_inputs(), get_possible_values(), and transform_properties_to_input_fields() are framework helpers. They remain callable for advanced integrations, but application code should usually use all(), filter(), exclude(), sort(), and terminal helpers instead. SortedFilters is an internal typed partition of parsed filters used during combination generation and is not a user-facing extension point.
general_manager.bucket.request_bucket.RequestBucket ¶
Bases: Bucket[GeneralManagerType]
Lazy bucket backed by a compiled request query plan.
Pickling preserves the compiled request plan and any serialized items, but unpickling does not immediately re-run network requests. Restored buckets keep their operation name and request plan metadata for equality and follow-up query compilation, but are marked as already materialized for iteration. Callers should only pickle buckets with serialized items if they expect iteration after unpickling to preserve results.
operation_name property ¶
operation_name
Return the query operation name preserved on this bucket.
Concrete item buckets created from slices, unions, or none() keep the source operation name for observability and equality context even though they no longer have a request plan.
__init__ ¶
__init__(
manager_class,
interface_cls,
*,
operation_name="list",
request_plan=None,
filters=None,
excludes=None,
items=None,
raw_items=None,
count_override=None
)
Create a lazy request-plan bucket or a materialized item bucket.
request_plan creates a lazy bucket unless serialized items or raw_items are supplied. items are already-built managers. raw_items are request payloads used to reconstruct managers and reinstall payload caches, including during pickle restoration. Filter and exclude lookup maps are copied into bucket-owned dictionaries so later caller mutations do not affect this bucket. count_override is the count returned after materialization.
__setstate__ ¶
__setstate__(state)
Restore pickle state without executing a request.
Serialized raw payloads rebuild manager instances and reinstall their request payload caches. If no raw payloads were serialized, the restored bucket uses the serialized manager items.
__or__ ¶
__or__(other)
Return a concrete item bucket containing both operands' items.
Raises:
| Type | Description |
|---|---|
RequestBucketManagerMismatchError | If another request bucket is backed by a different manager class. |
RequestBucketTypeMismatchError | If |
filter ¶
filter(**kwargs)
Return a bucket restricted by the supplied request or local lookups.
Lazy request-plan buckets merge the lookups into the compiled request plan and validate them through the query capability, even after iteration caches fetched items. Concrete item buckets created by slicing, unioning, or none() have no request plan; they validate the same lookup vocabulary and then filter contained manager instances in memory. Materialized lookups are ANDed across keys. Missing attributes do not match.
Raises:
| Type | Description |
|---|---|
Request-interface lookup validation errors | Propagated from query capability when a lookup is unknown, unsupported, requires an unavailable local fallback, conflicts in the request plan, or targets an unsupported request location. |
exclude ¶
exclude(**kwargs)
Return a bucket excluding items that match the supplied lookups.
Lazy request-plan buckets compile exclude lookups into the request plan. Concrete item buckets created by slicing, unioning, or none() first validate exclude support and then remove matching manager instances in memory. Missing attributes do not match and therefore are not excluded. Unsupported exclude lookups raise the request-interface validation errors produced by the query capability.
Raises:
| Type | Description |
|---|---|
RequestExcludeNotSupportedError | If exclude is requested for a lookup without remote exclude support or local fallback. |
Request-interface lookup validation errors | Propagated from query capability when a lookup is unknown, unsupported, conflicts in the request plan, or targets an unsupported request location. |
count ¶
count()
Materialize, then return the current count override or item count.
Lazy materialization stores the upstream total_count as the count override when available, stores the local fallback result count when local predicates are applied, and otherwise falls back to the materialized item count. Concrete buckets keep the override installed by slicing, unioning, or none().
get ¶
get(**kwargs)
Return exactly one item, optionally after applying additional filters.
Raises:
| Type | Description |
|---|---|
RequestSingleItemRequiredError | If the resulting bucket does not contain exactly one item. |
sort ¶
sort(key, reverse=False)
Return a materialized bucket sorted by one or more manager attributes.
Raises:
| Type | Description |
|---|---|
RequestBucketSortAttributeError | If any item lacks a requested sort attribute. |
TypeError | Propagated when Python cannot compare the resolved sort values, such as mixed unrelated value types. |
RequestBucket is the lazy collection returned by request-backed managers. filter(), exclude(), and all() preserve the configured request operation for lazy request-plan buckets, even after iteration caches the fetched items. Buckets built from concrete items, such as slices, unions, and none(), have no request plan; their follow-up filter() and exclude() calls validate the same request lookup rules and then operate on the contained manager instances in memory. Missing attributes do not match materialized filters. These methods return RequestBucket instances. Materialized filter() combines lookup keys with AND semantics; materialized exclude() removes an item when any supplied lookup matches, so a missing attribute does not exclude that item. Lookup suffix semantics come from request filters: bare or unknown suffixes are exact matches, supported suffixes include comparisons, contains, icontains, in, and isnull, and incompatible comparisons return False. The constructor accepts the manager class, request interface class, operation name, optional request plan, optional filter/exclude lookup maps, optional serialized manager items, optional raw request payloads, and an optional count override. Lookup maps are copied into bucket-owned dictionaries. Supplying items creates a concrete manager-item bucket; supplying raw_items rebuilds manager instances from extract_identification() and installs each raw payload as the manager interface's request payload cache. Lazy filter(), exclude(), and all() compile a new request plan and can raise the same lookup validation and planning errors as the request query capability, including unknown or unsupported filters, unsupported exclude lookups, required local fallbacks, fragment conflicts, and unsupported request locations. Any method that materializes a lazy bucket, including iteration, len(), count(), first(), last(), get(), indexing, slicing, membership, sorting, equality against a concrete bucket, and concrete follow-up filters, can propagate request execution, response-shape, permission, and validation errors from the underlying request interface.
Concrete buckets keep the source operation_name as metadata even though they no longer have a request plan. Unioning request buckets or adding a single manager instance also produces a concrete item bucket; incompatible bucket types raise RequestBucketTypeMismatchError, and request buckets for different manager classes raise RequestBucketManagerMismatchError. Only bucket | other is implemented here; manager | bucket follows the manager's own union behavior. Union order is left items followed by right items, and duplicates are not removed. Equality compares manager class and operation name first; when both sides still have request plans it compares plan plus compiled filters/excludes, otherwise it materializes and compares the ordered sequence of each item’s identification mapping. sort(key, reverse=False) materializes the bucket, accepts one attribute name or a tuple of attribute names, and raises RequestBucketSortAttributeError when an item lacks a requested attribute. Tuple keys sort lexicographically by the resolved attribute values. Nested attribute paths are not parsed; each key part is passed directly to getattr. Python TypeError propagates for incomparable values such as mixed unrelated types.
Pickle-restored buckets keep their operation name and request plan metadata, but unpickling does not execute a request. Iteration after unpickling uses whatever items were serialized, and serialized raw payloads are reinstalled on rebuilt manager instances for field reads. Follow-up filter(), exclude(), or all() calls on a restored bucket with a request plan compile a new lazy request bucket. If neither serializable manager items nor raw payloads were stored, iteration after unpickling yields the empty serialized item set even when request-plan metadata is present. Normal pickle failures for unserializable manager instances propagate from Python's pickle machinery.
get() requires exactly one result and raises RequestSingleItemRequiredError otherwise. count() always materializes first. After materialization the current count override wins; lazy materialization installs the upstream total_count when the response provides one, installs the local fallback item count when local predicates are applied, and otherwise falls back to the number of materialized items. A constructor count_override on a still-lazy bucket can therefore be replaced by the count observed during request execution. Local fallback predicates reject partial remote pages with RequestLocalPaginationUnsupportedError when the upstream total_count does not match the returned item count. Slices, unions, and none() are concrete buckets whose count override is their concrete item count; all() always returns a new bucket rather than self. __contains__ delegates to tuple membership over materialized manager objects, so it uses normal manager equality/identity rather than request lookup semantics.
general_manager.rule.rule.Rule ¶
Bases: Generic[GeneralManagerType]
Encapsulate a boolean predicate and derive contextual error messages from its AST.
When the predicate evaluates to False, the rule inspects the parsed abstract syntax tree to determine which variables failed and crafts either autogenerated or custom error messages.
__init__ ¶
__init__(
func, custom_error_message=None, ignore_if_none=True
)
Initialize a Rule that wraps a predicate function, captures its source AST to discover referenced variables, and prepares handlers for generating error messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func | Callable[[GeneralManagerType], bool] | Predicate that evaluates a GeneralManager instance. | required |
custom_error_message | Optional[str] | Optional template used to format generated error messages; placeholders must match variables referenced by the predicate. | None |
ignore_if_none | bool | If True, evaluation will be skipped (result recorded as None) when any referenced variable resolves to None. | True |
evaluate ¶
evaluate(x)
Evaluate the rule's predicate against a GeneralManager instance and record evaluation context.
Binds the primary parameter to the provided input, extracts referenced variable values, and sets the last evaluation result to the predicate outcome. If ignore_if_none is true and any referenced variable value is None, the evaluation is skipped and the last result is set to None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x | GeneralManagerType | Manager instance supplied to the predicate. | required |
Returns:
| Type | Description |
|---|---|
Optional[bool] |
|
validate_custom_error_message ¶
validate_custom_error_message()
Validate that a provided custom error message template includes placeholders for every variable referenced by the rule.
Raises:
| Type | Description |
|---|---|
MissingErrorTemplateVariableError | If one or more extracted variables are not present as |
get_error_message ¶
get_error_message()
Construct error messages for the last failed evaluation.
Returns:
| Type | Description |
|---|---|
Optional[Dict[str, str]] | dict[str, str] | None: Mapping keyed by referenced variables or |
Optional[Dict[str, str]] | Django's |
Optional[Dict[str, str]] |
|
Raises:
| Type | Description |
|---|---|
MissingErrorTemplateVariableError | If a failed rule's custom message omits a placeholder for a referenced variable. |
ErrorMessageGenerationError | If internal evaluation state records a failed result without retaining its evaluated input. |
Exception | A matching rule handler's documented message-generation exceptions propagate unchanged. |
Rule(func, custom_error_message=None, ignore_if_none=True) returns the predicate result from evaluate(manager) as True, False, or None when a referenced value is skipped. After False, get_error_message() returns a non-empty dict[str, str]: handler-derived messages when available, a variable-keyed combination fallback otherwise, or Django's "__all__" key for a variable-free predicate. A custom message is retained by the fallback. Calling get_error_message() before evaluation or after a passing/skipped evaluation returns None. For a failed rule, missing custom-message placeholders raise MissingErrorTemplateVariableError, and documented custom or built-in handler exceptions propagate unchanged. The defensive ErrorMessageGenerationError applies only if internal state records failure without retaining the evaluated input. The non-empty failed-rule fallback is guaranteed from 0.62.2. See the task guide and cookbook recipe.
BaseRuleHandler.handle(node, left, right, op, var_values, rule) is called by Rule while explaining a failed predicate. It returns {variable: message} and does not re-run or decide validation. Custom handlers should set function_name to a non-empty string; duplicate names replace earlier registrations from RULE_HANDLERS in order. RULE_HANDLERS entries must be dotted import paths to BaseRuleHandler subclasses; import errors, non-subclasses, invalid function_name values, and constructor errors surface during Rule construction.
general_manager.rule.handler.BaseRuleHandler ¶
Bases: ABC
Define the protocol for generating rule-specific error messages.
Rule handlers are used after a predicate has already failed. They explain a comparison by returning messages keyed by variable name; they do not decide whether a rule passes. Subclasses must set function_name, which is the dispatch key used by Rule and RULE_HANDLERS registration.
handle abstractmethod ¶
handle(node, left, right, op, var_values, rule)
Produce error messages for a comparison or function call node.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
node | AST | AST node representing the expression being evaluated. | required |
left | expr | None | Left operand when applicable. | required |
right | expr | None | Right operand when applicable. | required |
op | cmpop | None | Comparison operator node. | required |
var_values | dict[str, object | None] | Resolved variable values used during evaluation. | required |
rule | RuleHandlerContext | Rule-like object invoking the handler. | required |
Returns:
| Type | Description |
|---|---|
RuleErrorMap | dict[str, str]: Mapping of variable names to error messages. Return an empty mapping when the handler cannot explain the node. |
general_manager.rule.handler.InvalidFunctionNodeError ¶
Bases: ValueError
Raised when a rule handler receives an invalid AST node for its function.
__init__ ¶
__init__(function_name)
Initialize the exception for an invalid left-hand AST node used with a function call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
function_name | str | Name of the function with the invalid left node; stored on the exception and used to form the message "Invalid left node for {function_name}() function." | required |
general_manager.rule.handler.InvalidLenThresholdError ¶
Bases: TypeError
Raised when len() comparisons use a non-numeric threshold.
__init__ ¶
__init__()
Exception raised when a len() threshold is not a numeric value.
Initializes the exception with a default message indicating invalid arguments for the len function.
general_manager.rule.handler.InvalidNumericThresholdError ¶
Bases: TypeError
Raised when aggregate handlers use a non-numeric threshold.
__init__ ¶
__init__(function_name)
Create an InvalidFunctionNodeError with a formatted message for the given function name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
function_name | str | Name of the aggregate function (e.g., "sum", "max", "min") included in the message. | required |
general_manager.rule.handler.NonEmptyIterableError ¶
Bases: ValueError
Raised when an aggregate function expects a non-empty iterable.
__init__ ¶
__init__(function_name)
Initialize the error indicating an aggregate function received an empty iterable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
function_name | str | Name of the aggregate function (e.g., 'sum', 'max', 'len') used to build the error message. | required |
general_manager.rule.handler.NumericIterableError ¶
Bases: TypeError
Raised when an aggregate function expects numeric elements.
__init__ ¶
__init__(function_name)
Initialize the exception indicating that a function expected an iterable of numeric values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
function_name | str | Name of the function included in the exception message (message: " | required |
general_manager.rule.rule.InvalidRuleHandlerConfigurationError ¶
Bases: TypeError
Raised when a RULE_HANDLERS entry does not resolve to a rule handler class.