Skip to content

Introduce CI type-checking #951

Description

@junkmd

Hello comtypesers!

Inspired by recent work and discussions in #947 and #949, I believe we must ensure this static typing quality directly in CI.
To guarantee reliable type inference moving forward, I propose to integrate static type checking into our CI pipeline.

I think that one of the defining strengths of comtypes is that it allows us to interact with COM interfaces as statically-typed Python classes generated via client.GetModule—a key differentiator from IDispatch-based libraries.

Along with this change, support for Python 3.9 will be dropped, making Python 3.10+ required.

What is the CI Type-Checking Setup?

To continuously verify that both statically defined modules and dynamically generated code expose correct types, I have set up a standalone type verification harness:

  1. Clean Installation Verification:
    The workflow builds comtypes as an sdist, installs it into an isolated virtual environment (.venv), and verifies type hints against the installed package.
  2. Multi-Checker Coverage:
    Different type checkers have different inference rules and strictness.
    The CI job validates our code against type checkers.
  3. Targeted Typetests:
    Under type-check/tests/, test cases explicitly exercise type inference across:
    • Package typing export (py.typed and public API visibility)
    • Dynamically generated COM classes via client.GetModule

Why Drop Python 3.9?

  1. Python 3.9 is Past EOL:
    Python 3.9 reached its official End of Life (EOL) about a year ago.
  2. Ecosystem & Mypy 2.x Requirements:
    Key dependencies and tooling in the typing ecosystem have moved on.
    Specifically, mypy 2.x has already dropped support for Python 3.9.
    Maintaining compatibility with 3.9 while running modern type checkers adds unjustified maintenance friction.
  3. Modern Type Syntax (| via PEP 604):
    Dropping Python 3.9 allows us to modernize all type annotations by adopting the standard pipe operator (int | str instead of Union[int, str], str | None instead of Optional[str]).
    This improves readability across both hand-written modules and dynamically generated code.

Transition Plan & Phasing

To balance developer experience and backward compatibility, I plan to roll this out in phases:

  1. First Step: CI Type-Checking on Python 3.10+:
    The type-checking CI pipeline will initially target Python 3.10 and newer (3.10, 3.11, 3.12, 3.13, 3.14).
  2. Runtime Support for Python 3.9:
    For the time being, runtime compatibility with Python 3.9 will be maintained, and the A | B union syntax will NOT be introduced into the main codebase yet (standard unit tests will continue to run on Python 3.9).
  3. Post-1.5.0 Support Drop:
    However, after the 1.5.0 release, Python 3.9 is very likely to be dropped from supported Python versions entirely.

I look forward to hearing your thoughts and feedback!

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    citestsenhance or fix teststypingrelated to Python static typing system

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions