Add an opt-in value view for WinRT Object-valued maps in Python - #195
Merged
leileizhang (lei9444) merged 7 commits intoSep 28, 2026
Conversation
dynwinrt.values.object_value_view(mapping, *, preserve_type=False) wraps a generated IMap or IMapView wrapper whose values are Object, such as PropertySet, ValueSet or DeviceInformation.properties. It returns a live MutableObjectValueView or read-only ObjectValueView that holds no WinRT reference of its own: reads unbox with unbox_object(), writes box with to_winrt_object()'s default rules, and view.raw is the generated map. QueryInterface for IMap/IMapView<String or Guid, Object> confirms the value type, so other maps such as StringMap raise TypeError, and the overloads reject them statically. A box without a Python form (an unsupported PropertyType or a DateTime outside datetime's range) reads back raw so that dict(view) does not fail on one odd entry. Generated code, unbox_object() and to_winrt_object() are unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
update() writes through __setitem__ and to_winrt_object(), so its overloads now accept any value, as item assignment already does. They mirror MutableMapping.update(), which allows keyword arguments only for str keys. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
setdefault() now accepts any default that to_winrt_object() accepts, like __setitem__ and update(), and returns the read type: after storing a missing key it reads the value back, so (1, 2) returns [1, 2] and a runtime object its DynWinRTValue. MutableMapping.setdefault() would return the default itself. A targeted type: ignore[override] covers typeshed's self-typed overload, which infers "-> None" for a value type that includes None. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mark only binding-classified unsupported PropertyTypes so a supported IPropertyValue getter that returns the same HRESULT still propagates. Verify that a generated wrapper's actual map dispatch pointer is the reflexive IMap/IMapView<String or Guid, Object> pointer, rejecting another map wrapper on the same COM identity while preserving .raw. Constrain the public view key type to str or UUID. Add a synthetic dual-map COM object, getter-error identity checks, strict mypy/Pyright key controls, and generated Guid-map E2E coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
leileizhang (lei9444)
merged commit Sep 28, 2026
ae7fee8
into
lei9444-explicit-python-object-boxing
2 checks passed
leileizhang (lei9444)
deleted the
lei9444-python-object-map-value-view
branch
September 28, 2026 14:01
leileizhang (lei9444)
added a commit
that referenced
this pull request
Sep 29, 2026
…on (#194) * Add explicit WinRT Object boxing and type-preserving unboxing to Python Generated Object positions stay native (IInspectable); applications now convert boxed values explicitly at the boundaries that want value semantics. Core: PropertyValueData models every PropertyType that has a payload (37 of 41), unbox_property_value reports payload-less boxes as Unsupported, and box_property_value creates system PropertyValue boxes. JavaScript keeps its exact behavior and messages through a compile-only adapter. Python: - unbox_object additionally supports DateTime, TimeSpan, Point, Size, Rect, their arrays and InspectableArray (elements unboxed by the same rules); already-supported types return the same values, and payload-less boxes still raise OSError. - unbox_object(raw, preserve_type=True) returns dynwinrt.values tags and typed arrays, so to_winrt_object restores the exact PropertyType and value. - to_winrt_object(value, property_type=None) boxes only unambiguous values: a plain int is Int32 only, lists must be homogeneous, and enum members, empty or mixed lists and InspectableArray need an explicit type. - The tags, typed arrays, Point/Size/Rect and PropertyType live in the new dynwinrt.values submodule, outside the top-level namespace. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Cover explicit Object conversion with generated-binding E2E checks Python-only checks on generated bindings: - object_value_roundtrip: every PropertyValue.create_* factory (37 PropertyTypes) round-trips through unbox_object(preserve_type=True) and to_winrt_object with its exact PropertyType, and dynwinrt.values.PropertyType matches the metadata enum. - object_value_storage_properties: a temporary file's System.Size unboxes as UInt64 in preserve mode and System.DateModified as an aware datetime. - object_value_device_properties: DeviceInformation.properties values unbox as str, bool and UUID, skipping gracefully without devices. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Add an opt-in value view for WinRT Object-valued maps in Python (#195) * Add an opt-in value view for WinRT Object-valued maps in Python dynwinrt.values.object_value_view(mapping, *, preserve_type=False) wraps a generated IMap or IMapView wrapper whose values are Object, such as PropertySet, ValueSet or DeviceInformation.properties. It returns a live MutableObjectValueView or read-only ObjectValueView that holds no WinRT reference of its own: reads unbox with unbox_object(), writes box with to_winrt_object()'s default rules, and view.raw is the generated map. QueryInterface for IMap/IMapView<String or Guid, Object> confirms the value type, so other maps such as StringMap raise TypeError, and the overloads reject them statically. A box without a Python form (an unsupported PropertyType or a DateTime outside datetime's range) reads back raw so that dict(view) does not fail on one odd entry. Generated code, unbox_object() and to_winrt_object() are unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Type MutableObjectValueView.update() like item assignment update() writes through __setitem__ and to_winrt_object(), so its overloads now accept any value, as item assignment already does. They mirror MutableMapping.update(), which allows keyword arguments only for str keys. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Type MutableObjectValueView.setdefault() like item assignment setdefault() now accepts any default that to_winrt_object() accepts, like __setitem__ and update(), and returns the read type: after storing a missing key it reads the value back, so (1, 2) returns [1, 2] and a runtime object its DynWinRTValue. MutableMapping.setdefault() would return the default itself. A targeted type: ignore[override] covers typeshed's self-typed overload, which infers "-> None" for a value type that includes None. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Address Object map view review findings Mark only binding-classified unsupported PropertyTypes so a supported IPropertyValue getter that returns the same HRESULT still propagates. Verify that a generated wrapper's actual map dispatch pointer is the reflexive IMap/IMapView<String or Guid, Object> pointer, rejecting another map wrapper on the same COM identity while preserving .raw. Constrain the public view key type to str or UUID. Add a synthetic dual-map COM object, getter-error identity checks, strict mypy/Pyright key controls, and generated Guid-map E2E coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Validate Object map dispatch metadata Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Regress released Object map views with updated runtime Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Fix observable Object map view dispatch Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Keep unpublished Object conversion notes out of preview.22 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.
Problem
Code that reads and writes many values in
PropertySet,ValueSet,DeviceInformation.propertiesor maps returned byretrieve_properties_async()must wrap every access inunbox_object()orto_winrt_object().Key changes
dynwinrt.values.object_value_view(mapping, *, preserve_type=False)returns a liveMutableObjectValueViewforIMapand a read-onlyObjectValueViewforIMapView.to_winrt_object()'s default rules;.rawremains the original generated map with native values and COM identity.PropertyTypeboxes and out-of-rangeDateTimeboxes read back raw. Supported getter failures still propagate unchanged._obj/_collection_objdispatch path. The view validates that declaration and QI support without assuming non-IUnknown pointer identity.strandUUID, and rejects integer-keyed maps.Notes
IMap/IMapViewwrapper.IPropertySetwrappers are not Python mappings; usevalues.as_interface(IMap_String_Object).