objectstate 1.1.9__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {objectstate-1.1.9 → objectstate-1.2.0}/.github/badges/coverage.svg +1 -1
- {objectstate-1.1.9 → objectstate-1.2.0}/PKG-INFO +18 -1
- {objectstate-1.1.9 → objectstate-1.2.0}/README.md +17 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/__init__.py +1 -1
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/context_manager.py +17 -6
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/object_state.py +157 -176
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/parameter_structure.py +11 -1
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_callable_baseline.py +81 -1
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_context_manager.py +52 -0
- objectstate-1.2.0/tests/test_object_state_restore.py +180 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_object_state_update_instance.py +39 -0
- objectstate-1.1.9/tests/test_object_state_restore.py +0 -45
- {objectstate-1.1.9 → objectstate-1.2.0}/.github/workflows/ci.yml +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/.github/workflows/coverage-pages.yml +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/.github/workflows/publish.yml +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/.gitignore +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/.readthedocs.yaml +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/BADGE_SETUP.md +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/LICENSE +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/.gitignore +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/Makefile +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/api/modules.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/architectural_fixes.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/architecture.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/archive/DOCUMENTATION_AUDIT.md +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/archive/DOCUMENTATION_FIXES.md +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/archive/README.md +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/conf.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/examples/atomic_operations.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/examples/basic.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/examples/dual_axis.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/examples/index.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/examples/ui.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/index.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/make.bat +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/provenance.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/quickstart.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/state_management.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/state_propagation.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/docs/undo_redo.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/paper.bib +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/paper.md +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/plans/n_dimensional_inheritance.md +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/pyproject.toml +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/scripts/check_ruff_added_lines.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/scripts/release.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/scripts/update_and_release.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/scripts/update_version.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/scripts/verify_release_ready.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/collection_containers.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/config.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/construction_binding.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/docs/configuration_framework.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/docs/context_system.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/docs/object_state_lifecycle.rst +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/dual_axis_resolver.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/edit_session.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/field_access.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/global_config.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/history_migration.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/lazy_factory.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/live_context_resolver.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/object_state_metadata.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/object_state_registry.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/parameter_owner.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/parametric_axes.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/placeholder.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/reified_generics.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/snapshot_model.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/subfield_semantics.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/time_travel_profile.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/token_cache.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/transaction_checkpoint.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/ui_visibility.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/src/objectstate/value_semantics.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/__init__.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/conftest.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_config.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_construction_history.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_field_access.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_global_config.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_history_persistence.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_integration.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_lazy_factory.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_object_state_metadata_contracts.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_parameter_owner.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_parametric_axes.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_placeholder.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_registry_subscription.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_reified_generics.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_resolved_change_notifications.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_subfield_semantics.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_timeline_projection.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_transaction_checkpoint.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_ui_visible_field_projection.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_undo_redo_cascade.py +0 -0
- {objectstate-1.1.9 → objectstate-1.2.0}/tests/test_value_semantics.py +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="114" height="20" role="img" aria-label="coverage:
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="114" height="20" role="img" aria-label="coverage: 74.21%"><title>coverage: 74.21%</title><filter id="blur"><feGaussianBlur stdDeviation="16"/></filter><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="114" height="20" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="53" height="20" fill="#ea7233"/><rect width="114" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="315" y="150" fill-opacity=".8" filter="url(#blur)" textLength="510">coverage</text><text x="315" y="150" fill-opacity=".3" textLength="510">coverage</text></g><text x="315" y="140" textLength="510">coverage</text></g><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="865" y="150" fill-opacity=".8" filter="url(#blur)" textLength="430">74.21%</text><text x="865" y="150" fill-opacity=".3" textLength="430">74.21%</text></g><text x="865" y="140" textLength="430">74.21%</text></g></g></svg>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: objectstate
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Generic lazy dataclass configuration framework with dual-axis inheritance and contextvars-based resolution
|
|
5
5
|
Project-URL: Homepage, https://github.com/OpenHCSDev/objectstate
|
|
6
6
|
Project-URL: Documentation, https://objectstate.readthedocs.io
|
|
@@ -168,6 +168,23 @@ state.restore_saved()
|
|
|
168
168
|
ObjectStateRegistry.unregister(state)
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
+
Headless compilation can resolve a submitted saved declaration without creating
|
|
172
|
+
or registering an editing state:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
resolved_step, provenance = ObjectState.resolve_saved_object(
|
|
176
|
+
submitted_step,
|
|
177
|
+
scope_id="pipeline::step_0",
|
|
178
|
+
ancestor_objects_with_scopes=(("pipeline", saved_pipeline_config),),
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This uses the saved global context and the same scoped inheritance and nominal
|
|
183
|
+
construction as editing states. The caller supplies saved ancestors in order
|
|
184
|
+
from least to most specific. Provenance describes the same saved values; mutable
|
|
185
|
+
results are detached together while callable identities and shared aliases stay
|
|
186
|
+
intact. The existing live editor and saved-baseline APIs retain their lifecycle.
|
|
187
|
+
|
|
171
188
|
## Undo/Redo and Time Travel
|
|
172
189
|
|
|
173
190
|
Git-like DAG history with branching timelines:
|
|
@@ -132,6 +132,23 @@ state.restore_saved()
|
|
|
132
132
|
ObjectStateRegistry.unregister(state)
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
+
Headless compilation can resolve a submitted saved declaration without creating
|
|
136
|
+
or registering an editing state:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
resolved_step, provenance = ObjectState.resolve_saved_object(
|
|
140
|
+
submitted_step,
|
|
141
|
+
scope_id="pipeline::step_0",
|
|
142
|
+
ancestor_objects_with_scopes=(("pipeline", saved_pipeline_config),),
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This uses the saved global context and the same scoped inheritance and nominal
|
|
147
|
+
construction as editing states. The caller supplies saved ancestors in order
|
|
148
|
+
from least to most specific. Provenance describes the same saved values; mutable
|
|
149
|
+
results are detached together while callable identities and shared aliases stay
|
|
150
|
+
intact. The existing live editor and saved-baseline APIs retain their lifecycle.
|
|
151
|
+
|
|
135
152
|
## Undo/Redo and Time Travel
|
|
136
153
|
|
|
137
154
|
Git-like DAG history with branching timelines:
|
|
@@ -66,10 +66,21 @@ def _merge_nested_dataclass(base, override, mask_with_none: bool = False):
|
|
|
66
66
|
if not is_dataclass(base) or not is_dataclass(override):
|
|
67
67
|
return override
|
|
68
68
|
|
|
69
|
+
from objectstate.lazy_factory import get_base_type_for_lazy, replace_raw
|
|
70
|
+
|
|
71
|
+
base_type = get_base_type_for_lazy(type(base)) or type(base)
|
|
72
|
+
override_type = get_base_type_for_lazy(type(override)) or type(override)
|
|
73
|
+
# Lazy overlays of the same owner inherit on the base instance. An authored
|
|
74
|
+
# nominal change instead owns the result, including subtype-only fields.
|
|
75
|
+
result_owner = base if base_type is override_type else override
|
|
76
|
+
base_fields = {field_info.name for field_info in fields(base)}
|
|
69
77
|
merge_values = {}
|
|
70
78
|
for field_info in fields(override):
|
|
71
79
|
field_name = field_info.name
|
|
72
80
|
override_value = object.__getattribute__(override, field_name)
|
|
81
|
+
if field_name not in base_fields:
|
|
82
|
+
# This field belongs only to the authored nominal owner.
|
|
83
|
+
continue
|
|
73
84
|
base_value = object.__getattribute__(base, field_name)
|
|
74
85
|
|
|
75
86
|
if override_value is None:
|
|
@@ -77,8 +88,9 @@ def _merge_nested_dataclass(base, override, mask_with_none: bool = False):
|
|
|
77
88
|
# None overrides base value (masking mode)
|
|
78
89
|
merge_values[field_name] = None
|
|
79
90
|
else:
|
|
80
|
-
# None means
|
|
81
|
-
|
|
91
|
+
# None means inherit, including when the result owner changes.
|
|
92
|
+
if result_owner is override:
|
|
93
|
+
merge_values[field_name] = base_value
|
|
82
94
|
elif is_dataclass(override_value):
|
|
83
95
|
# Recursively merge nested dataclass
|
|
84
96
|
if base_value is not None and is_dataclass(base_value):
|
|
@@ -89,13 +101,12 @@ def _merge_nested_dataclass(base, override, mask_with_none: bool = False):
|
|
|
89
101
|
# Concrete value - use override
|
|
90
102
|
merge_values[field_name] = override_value
|
|
91
103
|
|
|
92
|
-
# Merge
|
|
104
|
+
# Merge on the nominal owner using replace_raw to preserve None values
|
|
93
105
|
# (dataclasses.replace triggers lazy resolution, baking in resolved values)
|
|
94
106
|
if merge_values:
|
|
95
|
-
|
|
96
|
-
return replace_raw(base, **merge_values)
|
|
107
|
+
return replace_raw(result_owner, **merge_values)
|
|
97
108
|
else:
|
|
98
|
-
return
|
|
109
|
+
return result_owner
|
|
99
110
|
|
|
100
111
|
|
|
101
112
|
@contextmanager
|