Skip to content

Add an opt-in value view for WinRT Object-valued maps in Python - #195

Open
leileizhang (lei9444) wants to merge 3 commits into
lei9444-explicit-python-object-boxingfrom
lei9444-python-object-map-value-view
Open

leileizhang (lei9444) wants to merge 3 commits into
lei9444-explicit-python-object-boxingfrom
lei9444-python-object-map-value-view

Conversation

@lei9444

Copy link
Copy Markdown
Contributor

Problem

Code that reads and writes many values in PropertySet, ValueSet, DeviceInformation.properties or the map from retrieve_properties_async() has to wrap every access in unbox_object() or to_winrt_object() (#194).

Key changes

  • dynwinrt.values.object_value_view(mapping, *, preserve_type=False) returns a live view:

    • a MutableObjectValueView (MutableMapping) for a generated IMap wrapper;
    • a read-only ObjectValueView (Mapping) for an IMapView wrapper.

    The view holds no WinRT reference of its own.

  • Reads unbox with unbox_object(). WinRT null reads as None. A runtime object comes back as its DynWinRTValue. So does a box with no Python form: an unsupported PropertyType, or a DateTime outside datetime's range.

  • Writes use to_winrt_object()'s default rules, and its errors propagate unchanged.

  • view.raw is the generated map. Its values stay native and keep their COM identity.

  • A QueryInterface check confirms IMap/IMapView<String or Guid, Object>. Any other map, such as StringMap, raises TypeError, and the typing overloads reject it too.

  • Tests:

    • pytest over real PropertySet, ValueSet, StringMap and MediaPropertySet maps;
    • E2E checks with generated bindings, including device and file properties;
    • a mypy --strict consumer check.

Notes

  • Stacked on Add explicit WinRT Object boxing and type-preserving unboxing to Python #194.
  • Opt-in only. Generated code, unbox_object() and to_winrt_object() are unchanged, and there are no codegen or native changes.
  • Generated IPropertySet wrappers, such as ApplicationDataContainer.values, are not Python mappings. Pass values.as_interface(IMap_String_Object) instead.
  • JavaScript parity is a follow-up.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant