Coverage for src/objectstate/edit_session.py: 40%
40 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-17 07:22 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-17 07:22 +0000
1"""Generic edit-session boundary for ObjectState-backed objects."""
3from __future__ import annotations
5from dataclasses import dataclass
6from typing import TYPE_CHECKING, Callable, Generic, TypeVar, cast
8if TYPE_CHECKING:
9 from objectstate.object_state import ObjectState
12EditedObjectT = TypeVar("EditedObjectT")
15@dataclass(slots=True)
16class ObjectStateEditSession(Generic[EditedObjectT]):
17 """Reconstruct and inspect an edited object through ObjectState.
19 ObjectState owns parameter storage, dirty state, lazy dataclass
20 reconstruction, and save/cancel baselines. This session is a small
21 fail-loud boundary for windows or other callers that need the current
22 edited object without reimplementing ObjectState semantics.
23 """
25 state_provider: Callable[[], ObjectState | None]
26 fallback_object: EditedObjectT | None = None
27 expected_type: type[EditedObjectT] | None = None
29 @property
30 def state(self) -> ObjectState | None:
31 return self.state_provider()
33 def require_state(self, parameter_name: str) -> ObjectState:
34 state = self.state
35 if state is None:
36 raise KeyError(
37 f"ObjectStateEditSession has no state for parameter {parameter_name!r}"
38 )
39 return state
41 def to_object(self, *, update_delegate: bool = False) -> EditedObjectT:
42 state = self.state
43 if state is None:
44 value = self.fallback_object
45 else:
46 value = state.to_object(update_delegate=update_delegate)
48 if value is None:
49 raise RuntimeError("ObjectStateEditSession has no object to reconstruct")
50 if self.expected_type is not None and not isinstance(value, self.expected_type):
51 raise TypeError(
52 "ObjectStateEditSession reconstructed "
53 f"{type(value).__name__}; expected {self.expected_type.__name__}"
54 )
55 return cast(EditedObjectT, value)
57 def has_parameter(self, parameter_name: str) -> bool:
58 state = self.state
59 return state is not None and parameter_name in state.parameters
61 def parameter_value(self, parameter_name: str):
62 state = self.require_state(parameter_name)
63 if parameter_name not in state.parameters:
64 raise KeyError(f"ObjectState parameter does not exist: {parameter_name!r}")
65 return state.parameters[parameter_name]
67 def update_parameter(self, parameter_name: str, value) -> None:
68 state = self.require_state(parameter_name)
69 if parameter_name not in state.parameters:
70 raise KeyError(f"ObjectState parameter does not exist: {parameter_name!r}")
71 state.update_parameter(parameter_name, value)