"""Resolution context — carries service and parent references during tree walk.""" class Context: """Evaluation frame for the resolver. Top-level context has ``service`` set and ``parent_object`` as None. Each selected/allocated object pushes a child context so children can reference ``parent`` and traverse its relations. """ def __init__(self, service, parent_object=None): self.service = service self.parent_object = parent_object def child(self, obj): return Context( service=self.service, parent_object=obj, ) @property def parent(self): return self.parent_object def resolve_path(self, path): """Resolve a dotted reference like ``parent.site.management_prefix``. Supported roots: - ``service`` → the Service instance - ``parent`` → the parent object (or None at service scope) Returns None if any segment is None or missing. """ parts = path.split(".") root = parts[0] if root == "service": obj = self.service elif root == "parent": obj = self.parent_object else: raise KeyError(f"Unknown context root: {root!r}") for part in parts[1:]: if obj is None: return None if isinstance(obj, dict): obj = obj.get(part) else: obj = getattr(obj, part, None) return obj