Python readiness checklist

September 3, 2026 ยท View on GitHub

This checklist records the shipped Python preview and tracks the remaining work toward a stable, broadly supported WinRT projection. The dynwinrt runtime and standalone dynwinrt-codegen command are published on PyPI.

See docs/guides/python/python-ui-ecosystem.md for research on Python UI frameworks, static pywinrt adoption, real integrations, and the value of a dynamic projection.

Target states

  • Data API preview (shipped): a clean machine can install wheels and generated bindings, then call supported Windows SDK APIs without Rust, Node.js, or a source checkout.
  • Data API release (in progress): generated APIs follow normal Python semantics for typing, async, events, collections, errors, and lifecycle.
  • WinUI preview (x64 validated): Python can bootstrap the Windows App SDK, enter an STA, construct composable WinUI classes, and load Fluent resources. Native ARM64 immediate teardown remains tracked in issue #116.

Verified baseline

  • The PyO3 runtime builds on Windows ARM64.
  • Generated Windows.Foundation.Uri bindings import and call real WinRT APIs on ARM64.
  • Python generation emits .py implementations.
  • --lang py emits .pyi, __init__.pyi, and py.typed by default.
  • Generated Python E2E covers 42 API specs and 88 checks.
  • Runtime primitives exist for arrays, structs, delegates, events, cancellation, progress callbacks, vectors, and maps.
  • Python codegen snapshots cover the Uri implementation and stubs.

P0: generated package correctness

  • Replace eager cross-module runtime imports with cycle-safe lazy resolution.
  • Keep referenced types visible to static type checkers through TYPE_CHECKING imports.
  • Model WinRT runtime-class and interface compatibility structurally in input annotations without changing runtime inheritance.
  • Add an import regression for a real cyclic graph such as Windows.Data.Xml.Dom.XmlDocument.
  • Preserve Uri implementation and .pyi snapshots.
  • Organize output by WinRT namespace instead of one flat short-name namespace.
  • Derive Python symbols, implementation modules, facade modules, and stable path hashes from a namespace- and kind-preserving semantic type identity, including recursively closed generic arguments.
  • Keep same-short-name types available through their namespace facades, omit ambiguous root exports, and use deterministic qualified aliases in consumer modules instead of selecting a short-name ABI implicitly.
  • Pass an immutable Python projection context through generation and rendering instead of installing thread-local module-layout state.
  • Detect and reject namespace/type filename collisions.
  • Add stage/swap generation and remove stale Python output.
  • Emit a consumable Python package manifest with an exact runtime dependency.
  • Emit one canonical module and Python class per WinRT struct instead of duplicating incompatible struct classes in every consumer module.
  • Make root and namespace exports lazy, keep ABI helpers in type-specific facades, and expose only Python types from public package indexes.

P0: runtime and generated API agreement

  • Ship a .pyi and py.typed marker for the dynwinrt extension.
  • Return declared enum members as generated IntEnum instances while preserving unknown values as integers.
  • Use invoke_all() for arbitrary multiple-out methods.
  • Add Python E2E for IVector.IndexOf and other multiple-out methods.
  • Project IReference<T> return positions as T | None.
  • Accept T | None in IReference<T> input positions.
  • Project null reference returns and reference-array elements as T | None consistently in runtime code and stubs.
  • Project IReference<T> struct fields as native T | None on reads while accepting native values, None, and legacy wrappers on writes.
  • Preserve the full UInt32 / UInt64 range when converting to Python integers.
  • Make Python stubs part of E2E and run a static type checker.
  • Make .pyi generation the default for --lang py.
  • Pass full-package mypy --strict, including collection overrides and cross-module struct arguments.

P0: async semantics

  • Return a Python awaitable instead of blocking inside generated async methods.
  • Integrate WinRT completion with an asyncio event loop.
  • Propagate Python cancellation to IAsyncInfo.Cancel.
  • Expose progress without forcing generated wrappers to call .wait().
  • Keep an explicit blocking API for scripts and non-async hosts.
  • Reject blocking waits from an STA when they could deadlock.

P0: CI and distribution

  • Execute all tests under bindings/py/tests in CI.
  • Build and install wheels before running Python E2E.
  • Complete the first live CPython 3.11โ€“3.14 x64/ARM64 release-matrix run. Native ARM64 builds and isolated consumers run on GitHub-hosted Windows ARM64 runners.
  • Remove unverified PyPy metadata.
  • Derive Python artifact versions from ordinary v<version> release tags, inject them only into ephemeral CI workspaces, and attach the complete wheel set to the shared JavaScript GitHub release.
  • Publish signed/provenanced wheels to an approved internal Python feed.
  • Route production PyPI publication through the official 1ES ADO release pipeline and Microsoft ESRP identity. PublishPyPI is enabled by default for tag releases and can be disabled for non-PyPI rehearsals.
  • Complete one-time ESRP/PyPI onboarding for dynwinrt and dynwinrt-codegen, including release owners and approvers.
  • Add complete tested Python wheel assets and installation notes to GitHub releases.
  • Provide a Python-native codegen CLI wheel using maturin binary bindings.
  • Add clean, isolated wheel consumers that import/call stock WinRT and run codegen with Cargo/Rust unavailable.

P1: Python-native behavior

  • Map HRESULT failures to OSError with a stable .winerror.
  • Include restricted WinRT error information when available.
  • Surface Python callback failures instead of returning unconditional success to WinRT.
  • Document callback threads and require explicit event unsubscription.
  • Preserve token-based on_* / off_* compatibility and provide idempotent subscribe_* and reentrancy-safe once_* helpers.
  • Convert TypedEventHandler / EventHandler callback arguments to typed projected Python values.
  • Implement Python collection protocols for iterable, vector, and map projections.
  • Accept normal Python sequences, mappings, bytes, UUIDs, datetimes, and timedeltas where the WinRT signature permits them.
  • Emit IntFlag for flags enums.
  • Add overload-aware runtime dispatch and typing.overload stubs.
  • Generate idiomatic constructors such as Uri(...) while retaining an internal wrapper path for returned native objects.
  • Expose project_as(value, Type) for typed, non-consuming projection of raw Object/IInspectable values to RuntimeClasses, matching JavaScript projectAs; use as_interface() / interface from_value() for QI views.
  • Declare non-suppressing runtime and generated context managers as Literal[False].
  • Replace deprecated PyO3 automatic FromPyObject behavior explicitly.
  • Document COM apartment ownership and provide a balanced context manager.

P1: tooling and documentation

  • Add a Python configuration surface to winapp CLI or a dedicated Python orchestration command.
  • Generate package names and imports consistently across Windows SDK, Windows App SDK, and custom WinMD namespaces.
  • Add runnable samples for files, notifications, imaging, async, events, collections, and custom WinMD consumption.
  • Document generated-code version compatibility with dynwinrt.
  • Add troubleshooting for metadata, apartment, bootstrap, architecture, and wheel compatibility failures.
  • Add progress-callback tests for worker-thread delivery and operations that complete concurrently with callback registration.

WinUI milestone

  • Project public composable __init__ overloads without requiring the ABI-only outer parameter. The low-level factory method remains available for parity and still exposes its raw ABI shape.
  • Keep protected composable constructors out of generated Python __init__ overloads.
  • Make WinMD activation/composition metadata the constructor boundary: system-returned and protected-composition classes retain native wrapping but reject public construction and expose no constructible .pyi overload.
  • Add a reusable outer/inner aggregation host for public composable Python subclasses, preserving controlling COM identity and inner ownership.
  • Add metadata-driven local overridable-interface vtables for public composable subclasses, including native-invoked FrameworkElement measure/arrange/template callbacks and fail-closed ABI validation.
  • Register arbitrary Python runtime-class names and compose them into the XAML metadata-provider chain so custom types can be instantiated by name from XAML markup.
  • Make Windows App SDK initialization idempotent and version-aware.
  • Auto-discover or explicitly provision the bootstrap DLL.
  • Expose the selected framework resources.pri path.
  • Add Python-specific implicit XAML metadata provider generation.
  • Generate the specialized Application.create_with_metadata_provider() and Fluent-resource bootstrap helpers with matching .pyi declarations.
  • Run Application.start, Application, Window, Grid, Button, and TextBlock on an STA in a live x64 WinUI E2E.
  • Validate worker-thread and asyncio scheduling while the WinUI DispatcherQueue owns the UI thread, including a WinRT async completion and try_enqueue back to the UI thread.
  • Add projected lifetime scopes that release UI/COM wrappers before apartment teardown.
  • Add awaitable DispatcherQueue result/error/priority scheduling helpers.
  • Project IObservableVector<T> as a mutable Python sequence with typed VectorChanged events.
  • Add a GIL-safe Python IElementFactory bridge and live ItemsRepeater get/recycle identity coverage.
  • Load and validate Fluent Light, Dark, and High Contrast resources.
  • Add a real Python WinUI application E2E on x64.
  • Add Python WinUI application E2E coverage on ARM64.

Later

  • Preserve projected object identity where it affects Python semantics.
  • Support delegates with more than two ABI parameters.
  • Add zero-copy Python buffer protocol integration.
  • Add performance benchmarks against pywinrt for representative APIs.
  • Add diagnostics for active COM wrappers, delegates, and async operations.

Current implementation slice

  1. Make generated runtime imports cycle-safe.
  2. Add a real cyclic-package import regression.
  3. Re-run Python snapshots, codegen tests, and generated Python E2E.
  4. Return known enum values as generated IntEnum instances.
  5. Verify Calendar.day_of_week is a DayOfWeek at runtime.
  6. Use invoke_all() for arbitrary multiple-out methods.
  7. Model FillArray as caller-owned (capacity, buffer) ABI.
  8. Verify Python and JavaScript IndexOf and GetMany, including zero items.
  9. Ship typed dynwinrt wheels and validate the native extension stubs.
  10. Generate Python stubs by default and type-check generated E2E APIs.
  11. Unbox IReference<T> returns as T | None.
  12. Box native Python values and None for IReference<T> inputs.
  13. Map synchronous and asynchronous HRESULT failures to OSError.
  14. Preserve signed HRESULTs in .winerror and captured WinRT error messages.
  15. Project WinRT collections through Python sequence, mapping, and iterator protocols.
  16. Accept Python-native containers, bytes, UUID, datetime, and timedelta values.
  17. Route delegate exceptions through sys.unraisablehook and fail WinRT invocation.
  18. Emit IntFlag, overload dispatch/stubs, and idiomatic runtime-class constructors.
  19. Balance COM initialization with RoApartment and add deterministic IClosable cleanup.
  20. Make reference returns null-safe without lying in generated annotations.
  21. Preserve UInt32 / UInt64 values across the Python boundary.
  22. Project and box IReference<T> struct fields, including struct-valued T.
  23. Add typed event arguments while preserving token subscriptions and adding idempotent unsubscribe helpers.
  24. Project public composable constructors and reject protected composition.
  25. Add an experimental, typed WinUI Application bootstrap path backed by a shared codegen/winrt/extensions/winui spec consumed by both JavaScript and Python projection.
  26. Run a real unpackaged x64 Python WinUI app with Fluent resources, Window/Grid/Button/TextBlock, automation-driven Click, and clean apartment shutdown.
  27. Release the GIL around blocking WinUI host calls and verify asyncio worker progress, WinRT async completion, and DispatcherQueue UI dispatch.