Refactor Python unit context handling into ContextItem and UnitContext#148
Draft
Copilot wants to merge 2 commits into
Draft
Refactor Python unit context handling into ContextItem and UnitContext#148Copilot wants to merge 2 commits into
ContextItem and UnitContext#148Copilot wants to merge 2 commits into
Conversation
Copilot
AI
changed the title
[WIP] Refactor context-item handling logic into its own class
Refactor Python unit context handling into Jun 3, 2026
ContextItem and UnitContext
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR #147 had context-item parsing/serialization and list mutation logic embedded in
ExecutionUnit, which made the unit class carry provider-shape normalization concerns. This refactor aligns the Python implementation with the TypeScript structure by separating single-item and collection responsibilities.Context item model extracted
src/py/mat3ra/wode/units/context_item.pywithContextItemas the canonical persisted shape:{"name", "isEdited", "data", "extraData"}name/isEdited/data/extraData)isXxxEdited/xxxExtraData)isUsingJinjaVariablesdata -> {"value": data}) and unwrapping ({"value": ...} -> ...) into the class.Unit context collection extracted
src/py/mat3ra/wode/units/unit_context.pywithUnitContext(RootModel[List[ContextItem]]).UnitContextnow owns list-level operations:get,get_data,add/upsert,remove,clear, iteration/length.ExecutionUnitslimmed downcontextfield switched toUnitContext.UnitContext.from_value(...)._context_item_name,_read_context_data,context_item,_replace_context_item,_normalized_context_item,_context_item_from_provider_yield.add_context,get_context_item,get_context,set_context,remove_context,clear_context.add_context_provider(provider)behavior remains unchanged.Exports and compatibility
ContextItemandUnitContextfromsrc/py/mat3ra/wode/units/__init__.py.unit.add_context(...)from persisted or provider-yield inputunit.get_context(...)data semantics (including scalar unwrap)to_dict()["context"]remains webapp-compatible list-of-dicts shape.Original prompt
Context
PR #147 currently keeps the entire context-item handling logic inside
ExecutionUnit(seesrc/py/mat3ra/wode/units/execution.py), with many static helpers (_context_item_name,_read_context_data,context_item,_replace_context_item,_normalized_context_item,_context_item_from_provider_yield, plusadd_context/get_context/set_context/remove_context/clear_context).Reviewer feedback on #147 (comment):
This mirrors how the TypeScript implementation is structured. We should align the Python side with the TS side.
TypeScript reference implementation
Relevant TS files at https://github.com/Exabyte-io/wode/tree/main/src/js :
src/js/context/providers/base/ContextProvider.ts:UnitContext = ContextItemSchema[],ContextName,ContextExtraData,ContextData.ContextProvider.getContextItemData(): Sreturns{ name, isEdited, data, extraData }— the canonical serialization of a single persisted context item. The provider owns serialization of itself into a persisted item.ContextProvider.findContextItem(unitContext, contextName)is a static helper that finds an item in aUnitContextarray by name.src/js/units/ExecutionUnit.ts:contextis justContextItemSchema[](a plain list).ExecutionUnithas NOadd_context/get_context/remove_context/context_itemhelpers, NO yield-data parsing. It simply does:Goal
Refactor the Python implementation so that:
A
ContextItemclass of its own handles serialization of a single context item. It should wrap/produce the canonical persisted shape:{"name": str, "isEdited": bool, "data": Any, "extraData": Dict[str, Any]}{"name", "isEdited", "data", "extraData"}), and_context_item_from_provider_yieldlogic — single provider key + optionalisXxxEdited/xxxExtraDatasiblings, ignoringisUsingJinjaVariables).ExecutionUnit.ExecutionUnitSchema'scontextfield). Prefer a Pydantic model (e.g. subclassContextItemSchemafrom ESSE, mirroring how TS usesContextItemSchema).datavalue passed in as a non-dict should be wrapped as{"value": data}exactly as the currentcontext_item(...)helper does, and_read_context_data(which unwraps{"value": ...}) should live on this class too.A
UnitContextcollection class (or thin wrapper) owns list-level logic. It should expose only the operations the unit actually needs, e.g.:get(name) -> Optional[ContextItem]get_data(name, default=None) -> Any(equivalent of currentExecutionUnit.get_context)add(item)/upsert(item)(replace-by-name semantics from_replace_context_item)remove(name)clear()__len__/__iter__List[ContextItemSchema]so the Pydantic field round-trips unchanged.Pick whichever shape is most idiomatic in Pydantic v2 — either a plain
class UnitContext(RootModel[List[ContextItem]])or a small standalone class that's converted via afield_validator/field_serializer. The goal is thatExecutionUnit.contextis that type and all list manipulation happens on it.Slim
ExecutionUnitback down. After the refactor,ExecutionUnitshould ideally contain only:context: UnitContextfield (with afield_validatorthat delegates toUnitContext/ContextItemfor coercion from raw dicts / lists, replacing the current_validate_context),add_context(item),get_context_item(name),get_context(name, default),set_context(items),remove_context(name),clear_context()— each one line that delegates toself.context.add_context_provider(provider)continues to work by callingself.add_context(provider.yield_data()).Remove from
ExecutionUnit:_context_item_name,_read_context_data,context_item,_replace_context_item,_normalized_context_item,_context_item_from_provider_yield. They belong onContextItem/UnitContext.Module placement. Put the new classes in a dedicated module, e.g.:
src/py/mat3ra/wode/units/context_item.py—ContextItemThis pull request was created from Copilot chat.