Metadata-Version: 2.4
Name: dynwinrt
Version: 0.1.0rc21
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Summary: Python bindings for dynamic WinRT API invocation
Author: Microsoft
License: MIT
Requires-Python: >=3.11, <3.15
Description-Content-Type: text/markdown
Project-URL: Homepage, https://github.com/microsoft/dynwinrt
Project-URL: Issues, https://github.com/microsoft/dynwinrt/issues
Project-URL: Repository, https://github.com/microsoft/dynwinrt

# dynwinrt

`dynwinrt` is the native CPython runtime for Python projections generated by
[`dynwinrt-codegen`](https://pypi.org/project/dynwinrt-codegen/). It supports
CPython 3.11–3.14 on Windows x64 and ARM64.

## Install

```powershell
python -m pip install --pre dynwinrt dynwinrt-codegen
dynwinrt-codegen generate --namespace Windows.Foundation --class-name Uri `
  --lang py --output generated_uri
```

Generated package manifests pin `dynwinrt` to the exact version of
`dynwinrt-codegen` that produced them. The runtime wheel includes
`__init__.pyi` and `py.typed` for static type checking.

Generated `IReference<T>` values are projected as `T | None`; native values,
`None`, and generated `IReference_*` wrappers are accepted as inputs.

## Async WinRT operations

Generated async methods return typed, asyncio-compatible operation objects:

```python
operation = writer.store_async()
stored_bytes = await operation
```

Their public types are `WinRTAsync[T]` and
`WinRTAsyncWithProgress[T, P]`; the concrete runtime wrappers remain private.

Regenerated bindings no longer block inside async methods. Existing code that
expects an immediate result must use `await operation` or `operation.wait()`.

`asyncio` task cancellation calls `IAsyncInfo.Cancel()` on the underlying
WinRT operation. Operations with supported progress values also expose
`operation.progress(callback)`. Fast operations can finish before registration;
in that case no future progress exists and registration is a no-op.

For scripts without an event loop, `operation.wait()` remains available as an
explicit blocking API. It rejects started operations when called from a running
asyncio loop or an STA thread, where blocking could freeze or deadlock the
caller.

WinRT HRESULT failures raise `OSError` (or a standard `OSError` subclass) with
the signed HRESULT in `error.winerror`. The exception message preserves
restricted WinRT error information when Windows provides it.

## Python-native values

Generated collection projections implement the standard `collections.abc`
protocols: vectors behave as sequences, maps as mappings, and WinRT iterables
and iterators work with `iter()` and `next()`. Mutable vectors support indexing,
slicing, assignment, insertion, and deletion; mutable maps support standard
mapping assignment and deletion.

Method inputs accept normal Python sequences and mappings in place of compatible
WinRT collection interfaces. Byte arrays accept `bytes` and `bytearray`; GUID,
`DateTime`, and `TimeSpan` values use `uuid.UUID`, `datetime.datetime`, and
`datetime.timedelta`.

Exceptions raised by Python event or delegate callbacks are reported through
`sys.unraisablehook`. The originating WinRT invocation receives
`0xA0EE4005` (`PYWINRT_E_UNRAISABLE_PYTHON_EXCEPTION`) instead of unconditional
success. Generated delegate parameters accept normal Python callables. WinRT
chooses the callback thread, so callbacks must not assume they run on the
registration thread or an asyncio event-loop thread. Keep each token returned by
`on_*` and pass it to the matching `off_*` when the subscription is no longer
needed. For callback-style cleanup, `subscribe_*` returns an idempotent
unsubscribe function. `once_*` subscribes for at most one callback invocation.

WinRT flags enums are projected as `enum.IntFlag`. Overloaded methods share one
Python name with runtime type/arity dispatch and `typing.overload` declarations.
Activatable runtime classes use normal constructors, for example
`Uri("https://example.com")`. Constructor overloads come only from WinMD
`ActivatableAttribute` and public `ComposableAttribute` declarations. Classes
without that metadata, including system-returned classes and protected-only
composition, raise a class-named `TypeError` on normal construction and their
stubs expose no public constructor. Native return values still use the internal
`_from_native`/`DynWinRTValue` wrapping path.

## Raw object projection

Use `project_as(value, Type)` when metadata returns `Object`/`IInspectable` but
the application knows the concrete generated type. This is common with XAML
APIs such as `XamlReader.load()` and `FrameworkElement.find_name()`:

```python
from dynwinrt import project_as
from generated.microsoft.ui.xaml.controls import Button, StackPanel
from generated.microsoft.ui.xaml.markup import XamlReader

raw_panel = XamlReader.load(XAML)
if raw_panel is None:
    raise RuntimeError("XamlReader returned no value")
panel = project_as(raw_panel, StackPanel)

raw_button = panel.find_name("Submit")
if raw_button is None:
    raise RuntimeError("Submit was not found")
button = project_as(raw_button, Button)
```

`project_as()` accepts generated runtime classes only and borrows its input:
the raw value or source wrapper remains valid. The returned wrapper owns the
QueryInterface result, participates in the active
`projected_lifetime_scope()`, and preserves the projection identity cache.
Classes with a verifiable default-interface IID remain valid projection
targets even when metadata exposes them only through `Object`/`IInspectable`.
Projection always performs QueryInterface, so a static-only declaration cannot
produce a wrapper unless the input actually implements that default interface.
Incompatible types raise the ordinary WinRT `OSError`. Static-only metadata
classes with no instance surface are not projection targets.

Use `wrapper.as_interface(InterfaceClass)` when converting an existing
wrapper to an interface view. Use `InterfaceClass.from_value(raw)` for a raw
`DynWinRTValue`. Do not call the internal `_from_native()` method from
application code.

## COM apartments and cleanup

Use `RoApartment` to initialize COM for a thread and balance every successful
initialization:

```python
with RoApartment(0):  # RO_INIT_SINGLETHREADED
    use_winrt()
```

Use `RoApartment(1)` for `RO_INIT_MULTITHREADED`. Nested contexts using the same
model are supported. Requesting a conflicting model raises `OSError` with
`RPC_E_CHANGED_MODE`. The low-level `ro_initialize()` API remains available, but
each successful call, including `S_FALSE`, must be paired with one
`ro_uninitialize()` call on the same thread.

Generated runtime classes that implement `IClosable` support `with` and an
idempotent `close()` method. Prefer deterministic cleanup instead of relying on
Python garbage collection.

## Experimental WinUI support

When the required WinUI metadata is generated, `Application.create()` installs
`XamlControlsResources` and configures unpackaged resource resolution.
`Application.create_with_metadata_provider(...)` is available when the
application supplies its own provider.

Python subclasses of public composable controls preserve one COM identity for
inherited properties and methods. Metadata-supported
`measure_override`, `arrange_override`, and `on_apply_template` callbacks run
synchronously on the creating UI apartment with the `contextvars` context
captured during construction. Unsupported native override shapes fail during
construction instead of falling back to an unsafe ABI.

After creating the generated application, publicly composable controls can
register a Python subclass for activation by `XamlReader`:

```python
from generated.microsoft.ui.xaml.controls import StackPanel
from generated.microsoft.ui.xaml.markup import XamlReader

class PythonPanel(StackPanel):
    def measure_override(self, available_size):
        return available_size

registration = StackPanel.register_xaml_runtime_class(
    "MyApp.Controls.PythonPanel",
    PythonPanel,
)
raw_panel = XamlReader.load(
    '<local:PythonPanel '
    'xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" '
    'xmlns:local="using:MyApp.Controls" />'
)
if raw_panel is None:
    raise RuntimeError("XamlReader returned no value")
panel = StackPanel(raw_panel)

# First remove every instance from the XAML tree and release application owners.
panel = None
raw_panel = None
registration.unregister()
registration.release_instances()
```

Registrations are process-local, and duplicate names fail. Unregistering,
closing, or dropping the registration prevents new XAML metadata lookups.
XAML-created Python owners remain rooted until `release_instances()`; call it
only after every corresponding native control has left the XAML tree.
Registration does not make the class globally activatable through
`RoActivateInstance`.

Generated `Application.start()` and `DispatcherQueue.run_event_loop()` calls
stay on the caller's native thread but release the Python GIL while WinUI pumps
messages. WinRT callbacks reacquire the GIL, and worker threads can use
`DispatcherQueue.try_enqueue()` to return to the UI thread.

Use a projection lifetime scope inside the COM apartment so wrappers release
their native values before `RoUninitialize`:

```python
from dynwinrt import RoApartment, projected_lifetime_scope

with RoApartment(0), projected_lifetime_scope():
    app = Application.create()
    # Create and use WinUI objects here.
```

Scopes nest in LIFO order. Wrappers that survive a closed scope remain Python
objects, but their native values are released and further WinRT calls fail.

Normal construction remains unavailable for protected-only composable classes
and system-returned classes without public activation metadata. Named Python
XAML registration does not support generic names, collection or dictionary
bases, markup-extension bases, or Python-defined XAML members.

## Develop

From `bindings\py`:

```powershell
python -m pip install "maturin>=1.11,<2" "pytest>=8.3.5" "mypy>=1.13,<2"
python -m maturin develop
python -m pytest
```

## Release process

The release tag supplies one unified npm/Cargo version. For example,
`v0.1.0-preview.21` produces npm version `0.1.0-preview.21` and Python version
`0.1.0rc21` after PEP 440 normalization.

1. GitHub Actions builds and consumes eight CPython 3.11–3.14 runtime wheels
   and two standalone codegen wheels on Windows x64 and native ARM64.
2. The official 1ES ADO pipeline builds both npm packages and waits for the
   complete Python wheel matrix.
3. ADO creates one shared GitHub Release with the npm tarballs. GitHub Actions
   attaches the ten tested Python wheels, and ADO downloads and revalidates the
   complete set.
4. With `DoEsrp` enabled, ADO publishes both npm packages. `PublishPyPI`
   defaults to enabled and publishes the eight `dynwinrt` wheels before the two
   `dynwinrt-codegen` wheels. Disable it only for a non-PyPI rehearsal.

PyPI publication uses the Microsoft ESRP release identity and is not available
from GitHub Actions.
