objectstate.dual_axis_resolver
Generic dual-axis resolver for lazy configuration inheritance.
This module provides the core inheritance resolution logic as a pure function, supporting both context hierarchy (X-axis) and sibling inheritance (Y-axis).
The resolver is completely generic and has no application-specific dependencies.
Functions
Clear the MRO resolution cache. |
|
|
Find which scope AND type provided the concrete value for a field. |
|
Invalidate cache entries for a specific field that could be affected by a type change. |
|
MRO-based inheritance resolution. |
|
Resolve a field value AND find its provenance source in ONE walk. |
- objectstate.dual_axis_resolver.clear_mro_resolution_cache() None[source]
Clear the MRO resolution cache. Call when context fundamentally changes.
- objectstate.dual_axis_resolver.invalidate_mro_cache_for_field(changed_type: type, field_name: str) None[source]
Invalidate cache entries for a specific field that could be affected by a type change.
PERFORMANCE: Only clears cache entries where: 1. The field_name matches 2. The obj_type has changed_type in its MRO (could inherit from it)
This is much more targeted than clear_mro_resolution_cache().
- objectstate.dual_axis_resolver.resolve_field_inheritance(obj, field_name: str, available_configs: Dict[str, Any]) Any[source]
MRO-based inheritance resolution.
ALGORITHM: For LazyDataclass types:
Check if same-type config exists in context with concrete value
Walk MRO to find parent class configs with concrete value
Fall back to static class defaults if nothing found
- For concrete classes with lazy resolution:
SKIP same-type lookup (if you created ProcessingConfig(group_by=None), you want None)
Walk MRO to find PARENT class configs with concrete value (sibling inheritance)
Return None if nothing found (no static default fallback)
- Parameters:
obj – The object requesting field resolution
field_name – Name of the field to resolve
available_configs – Dict mapping config type names to config instances
- Returns:
Resolved field value or None if not found
- objectstate.dual_axis_resolver.resolve_with_provenance(container_type: type, field_name: str) Tuple[Any, str | None, type | None][source]
Resolve a field value AND find its provenance source in ONE walk.
TWO-PHASE DUAL-AXIS RESOLUTION:
- Phase 1 - Hierarchy (same-type only, outer to inner):
Walk scopes from global → pipeline → step, checking ONLY the same-type config. If a concrete value is found, return it immediately. This gives hierarchy precedence for directly-set values.
- Phase 2 - MRO fallback (only if Phase 1 found nothing):
Walk scopes from inner to outer (step → pipeline → global), doing MRO walk. This allows sibling inheritance when no concrete value exists in the hierarchy.
This ensures: - GlobalPipelineConfig.well_filter_config.well_filter overrides the same field
at PipelineConfig level (hierarchy precedence for same-type)
MRO inheritance only applies when NO concrete value exists in the hierarchy for the specific config type being resolved
PERFORMANCE: Single walk instead of separate resolve + provenance calls.
IMPORTANT: Must be called within a config_context() that has scope_ids set up. The layer stack is built by build_context_stack() with ancestor_objects_with_scopes.
- Parameters:
container_type – The type containing the field (e.g., LazyPathPlanningConfig)
field_name – Name of the field to find provenance for (e.g., “well_filter”)
- Returns:
The resolved value, scope that provided it, and the TYPE that has the concrete value (may differ from container_type due to MRO inheritance, e.g., PathPlanningConfig instead of WellFilterConfig). If no concrete value found, returns (None, None, None).
- Return type:
(resolved_value, source_scope_id, source_type)
- objectstate.dual_axis_resolver.get_field_provenance(container_type: type, field_name: str) Tuple[str | None, type | None][source]
Find which scope AND type provided the concrete value for a field.
CONVENIENCE WRAPPER: Calls resolve_with_provenance() and returns scope + type. Use resolve_with_provenance() directly when you also need the value.
- Parameters:
container_type – The type containing the field (e.g., LazyPathPlanningConfig)
field_name – Name of the field to find provenance for (e.g., “well_filter”)
- Returns:
The scope_id and type that provided the value. source_type may differ from container_type due to MRO inheritance. Returns (None, None) if no layer has a concrete value.
- Return type:
(source_scope_id, source_type)