From d375ee52b0b35436b7e2e88de182fb645f50a1e3 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:03 +0900 Subject: [PATCH 01/13] refactor: Add `ParsedType` union alias for type annotations in `tlbparser`. --- comtypes/tools/tlbparser.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index 49d173ed..ee48412c 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -1,9 +1,11 @@ import os import sys from _ctypes import COMError +from collections.abc import Mapping from ctypes import alignment, c_void_p, sizeof, windll from ctypes.wintypes import MAX_PATH from typing import Any, Optional +from typing import Union as _UnionT from comtypes import automation, typeinfo from comtypes.tools import typedesc @@ -107,6 +109,18 @@ def midlSAFEARRAY(typ): # automation.VT_ARRAY = 8192 # automation.VT_BYREF = 16384 +ParsedType = _UnionT[ + typedesc.TypeLib, + typedesc.Constant, + typedesc.External, + typedesc.ComInterface, + typedesc.DispInterface, + typedesc.Typedef, + typedesc.Structure, + typedesc.Union, + typedesc.Enumeration, +] + ################################################################ @@ -670,7 +684,7 @@ def parse_LibraryDescription(self): ################################################################ - def parse(self): + def parse(self) -> Mapping[str, ParsedType]: self.parse_LibraryDescription() for i in range(self.tlib.GetTypeInfoCount()): From ef0521693273ac83e587c77311977170fd1d6bff Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:03 +0900 Subject: [PATCH 02/13] refactor: Remove unused import from `typedesc_base.py` and update linting rules in `pyproject.toml` --- comtypes/tools/typedesc_base.py | 2 -- pyproject.toml | 1 - 2 files changed, 3 deletions(-) diff --git a/comtypes/tools/typedesc_base.py b/comtypes/tools/typedesc_base.py index 5b311077..f11746a1 100644 --- a/comtypes/tools/typedesc_base.py +++ b/comtypes/tools/typedesc_base.py @@ -2,8 +2,6 @@ from typing import Any, Optional, SupportsInt from typing import Union as _UnionT -import comtypes - class Argument: "a Parameter in the argument list of a callable (Function, Method, ...)" diff --git a/pyproject.toml b/pyproject.toml index dcec9bf7..97360858 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,6 @@ ignore = ["E402"] "comtypes/server/register.py" = ["E713"] "comtypes/tools/codegenerator/packing.py" = ["F821", "F841"] "comtypes/tools/typedesc.py" = ["F403", "F405"] -"comtypes/tools/typedesc_base.py" = ["F401"] # gen directory "comtypes/gen/*" = ["E", "F", "I"] # stub From b1ec28eb94b3b696ba0ef56e9a7faf1027414148 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:03 +0900 Subject: [PATCH 03/13] refactor: Fix void FundamentalType size/alignment handling. There used to be a special-case path for `name="void"` where instance attributes `size` and `align` were not assigned, but in the current implementation that branch is already guarded by the type identity itself, so it is not a realistic runtime problem. In other words, `void` is already treated as an exceptional case at the parser boundary, and the implementation does not expect a generic attribute test such as `hasattr`/`getattr` to be needed for it. The policy here is to treat `void` as a sentinel value in this type parser even though C itself defines it as an incomplete type, for which `sizeof(void)` is not meaningful. `FundamentalType` is not a perfect model of C types; it is a Python-side representation that needs to expose `size` and `align` as attributes for downstream code to consume consistently. In that model, the `(0, 0)` assignment keeps `void` consistent without requiring a special case in the downstream code. This is therefore not a claim that `void` is a true zero-sized, zero-aligned C object in the language-theoretic sense; it is simply the parser's policy for encoding an incomplete type in a model that requires those fields to exist. --- comtypes/tools/typedesc_base.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/comtypes/tools/typedesc_base.py b/comtypes/tools/typedesc_base.py index f11746a1..fb9ba942 100644 --- a/comtypes/tools/typedesc_base.py +++ b/comtypes/tools/typedesc_base.py @@ -108,11 +108,10 @@ def __init__(self, name, returns): class FundamentalType: location = None - def __init__(self, name, size, align): + def __init__(self, name: str, size: int, align: int) -> None: self.name = name - if name != "void": - self.size = int(size) - self.align = int(align) + self.size = int(size) + self.align = int(align) class PointerType: From 26000d59a6982346d787ee1a70a1de1a0976621c Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:03 +0900 Subject: [PATCH 04/13] refactor: Explicitly import types from `typedesc_base` instead of using wildcard import. --- comtypes/tools/typedesc.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/comtypes/tools/typedesc.py b/comtypes/tools/typedesc.py index 755b6e02..302ff80a 100644 --- a/comtypes/tools/typedesc.py +++ b/comtypes/tools/typedesc.py @@ -7,7 +7,28 @@ from typing import Union as _UnionT from comtypes import typeinfo -from comtypes.tools.typedesc_base import * +from comtypes.tools.typedesc_base import Alias as Alias +from comtypes.tools.typedesc_base import Argument as Argument +from comtypes.tools.typedesc_base import ArrayType as ArrayType +from comtypes.tools.typedesc_base import Constructor as Constructor +from comtypes.tools.typedesc_base import CvQualifiedType as CvQualifiedType +from comtypes.tools.typedesc_base import Enumeration as Enumeration +from comtypes.tools.typedesc_base import EnumValue as EnumValue +from comtypes.tools.typedesc_base import Field as Field +from comtypes.tools.typedesc_base import File as File +from comtypes.tools.typedesc_base import Function as Function +from comtypes.tools.typedesc_base import FunctionType as FunctionType +from comtypes.tools.typedesc_base import FundamentalType as FundamentalType +from comtypes.tools.typedesc_base import Macro as Macro +from comtypes.tools.typedesc_base import Method as Method +from comtypes.tools.typedesc_base import OperatorFunction as OperatorFunction +from comtypes.tools.typedesc_base import PointerType as PointerType +from comtypes.tools.typedesc_base import Structure as Structure +from comtypes.tools.typedesc_base import StructureBody as StructureBody +from comtypes.tools.typedesc_base import StructureHead as StructureHead +from comtypes.tools.typedesc_base import Typedef as Typedef +from comtypes.tools.typedesc_base import Union as Union +from comtypes.tools.typedesc_base import Variable as Variable from comtypes.typeinfo import TLIBATTR, ITypeLib From 533a9646365afb48788b939368bf8b3074bc7e9e Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:03 +0900 Subject: [PATCH 05/13] refactor: Remove unused linting ignores for `typedesc.py`. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 97360858..e806166c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,6 @@ ignore = ["E402"] "comtypes/server/inprocserver.py" = ["E722"] "comtypes/server/register.py" = ["E713"] "comtypes/tools/codegenerator/packing.py" = ["F821", "F841"] -"comtypes/tools/typedesc.py" = ["F403", "F405"] # gen directory "comtypes/gen/*" = ["E", "F", "I"] # stub From cf66bccbc5be8b3e247399bd791a8d74c7589723 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:04 +0900 Subject: [PATCH 06/13] refactor: Add `CoClass` to `ParsedType` union for improved type annotations in `tlbparser`. --- comtypes/tools/tlbparser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index ee48412c..3ea6f70a 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -113,6 +113,7 @@ def midlSAFEARRAY(typ): typedesc.TypeLib, typedesc.Constant, typedesc.External, + typedesc.CoClass, typedesc.ComInterface, typedesc.DispInterface, typedesc.Typedef, From 25a5d48ca668b7e644fc7d6cb0b0032c6ae59a39 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:04 +0900 Subject: [PATCH 07/13] refactor: Update `_register` method signature to use `ParsedType`. --- comtypes/tools/tlbparser.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index 3ea6f70a..23f0ec38 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -602,7 +602,10 @@ def _typelib_module(self, tlib: Optional[typeinfo.ITypeLib] = None) -> str: return str(tlib.GetLibAttr()) def _register( - self, name: Optional[str], value: Any, tlib: Optional[typeinfo.ITypeLib] = None + self, + name: Optional[str], + value: ParsedType, + tlib: Optional[typeinfo.ITypeLib] = None, ) -> None: modname = self._typelib_module(tlib) fullname = f"{modname}.{name}" From 327681ac47fd25d5407bb7baef590dacae58e991 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:04 +0900 Subject: [PATCH 08/13] refactor: Adjust return type of `parse_typeinfo`. --- comtypes/tools/tlbparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index 23f0ec38..d3e9be9f 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -617,7 +617,7 @@ def _register( raise ValueError(f"Bug: Multiple registered name '{name}': {value!r}") self.items[fullname] = value - def parse_typeinfo(self, tinfo: typeinfo.ITypeInfo) -> Any: + def parse_typeinfo(self, tinfo: typeinfo.ITypeInfo) -> Optional[ParsedType]: name = tinfo.GetDocumentation(-1)[0] modname = self._typelib_module() try: From d7b1dc238355c30f1d84b5d115375b5e80e70c47 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:04 +0900 Subject: [PATCH 09/13] refactor: Introduce `SpecType` union for enhanced type annotations in `tlbparser`. --- comtypes/tools/tlbparser.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index d3e9be9f..4bf24238 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -122,6 +122,12 @@ def midlSAFEARRAY(typ): typedesc.Enumeration, ] +SpecType = _UnionT[ + typedesc.FundamentalType, + typedesc.PointerType, + typedesc.ArrayType, + typedesc.SAFEARRAYType, +] ################################################################ @@ -129,7 +135,9 @@ class Parser: tlib: typeinfo.ITypeLib items: dict[str, Any] - def make_type(self, tdesc: typeinfo.TYPEDESC, tinfo: typeinfo.ITypeInfo) -> Any: + def make_type( + self, tdesc: typeinfo.TYPEDESC, tinfo: typeinfo.ITypeInfo + ) -> _UnionT[ParsedType, SpecType]: if tdesc.vt in COMTYPES: return COMTYPES[tdesc.vt] if tdesc.vt == automation.VT_CARRAY: From b55fbf9b616fa476b172c9aa695a520ec9623815 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:04 +0900 Subject: [PATCH 10/13] refactor: Enhance type annotations for `generate` and `generate_all` methods in `CodeGenerator`. --- comtypes/tools/codegenerator/codegenerator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/comtypes/tools/codegenerator/codegenerator.py b/comtypes/tools/codegenerator/codegenerator.py index 53111d49..9e264017 100644 --- a/comtypes/tools/codegenerator/codegenerator.py +++ b/comtypes/tools/codegenerator/codegenerator.py @@ -7,7 +7,7 @@ import os import textwrap import warnings -from collections.abc import Iterator, Sequence +from collections.abc import Iterable, Iterator, Sequence from typing import Any, Literal, Optional from typing import Union as _UnionT @@ -81,7 +81,7 @@ def adjust_blank( yield self.stream self.last_item = item - def generate(self, item): + def generate(self, item: tlbparser.ParsedType) -> None: if item in self.done: return if self._is_interface_typedesc(item): @@ -104,7 +104,7 @@ def generate(self, item): self.done.add(item) mth(item) - def generate_all(self, items): + def generate_all(self, items: Iterable[tlbparser.ParsedType]) -> None: for item in items: self.generate(item) @@ -160,7 +160,7 @@ def _generate_typelib_path(self, filename): self.names.add("typelib_path") def generate_wrapper_code( - self, tdescs: Sequence[Any], filename: Optional[str] + self, tdescs: Sequence[tlbparser.ParsedType], filename: Optional[str] ) -> str: """Returns the code for the COM type library wrapper module. From edf682f35434b27181c7c8d12d0027271557ed96 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 21 Oct 2026 09:19:04 +0900 Subject: [PATCH 11/13] refactor: Update type annotations for `known_symbols` and `known_interfaces` in `CodeGenerator`. --- comtypes/tools/codegenerator/codegenerator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/comtypes/tools/codegenerator/codegenerator.py b/comtypes/tools/codegenerator/codegenerator.py index 9e264017..02dc6069 100644 --- a/comtypes/tools/codegenerator/codegenerator.py +++ b/comtypes/tools/codegenerator/codegenerator.py @@ -7,7 +7,7 @@ import os import textwrap import warnings -from collections.abc import Iterable, Iterator, Sequence +from collections.abc import Iterable, Iterator, Mapping, Sequence from typing import Any, Literal, Optional from typing import Union as _UnionT @@ -50,8 +50,8 @@ def __init__(self, known_symbols=None, known_interfaces=None) -> None: self.enums = namespaces.EnumerationNamespaces() self.unnamed_enum_members: list[tuple[str, int]] = [] self._to_type_name = TypeNamer() - self.known_symbols = known_symbols or {} - self.known_interfaces = known_interfaces or {} + self.known_symbols: Mapping[str, str] = known_symbols or {} + self.known_interfaces: Mapping[str, str] = known_interfaces or {} self.done = set() # type descriptions that have been generated self.names = set() # names that have been generated From 5461f88250479a9b07bb0881da7837a0950e0fed Mon Sep 17 00:00:00 2001 From: Jun Komoda <45822440+junkmd@users.noreply.github.com> Date: Wed, 21 Oct 2026 10:04:01 +0900 Subject: [PATCH 12/13] refactor: Change items type from `Any` to `ParsedType`. --- comtypes/tools/tlbparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index 4bf24238..c4d9ce51 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -133,7 +133,7 @@ def midlSAFEARRAY(typ): class Parser: tlib: typeinfo.ITypeLib - items: dict[str, Any] + items: dict[str, ParsedType] def make_type( self, tdesc: typeinfo.TYPEDESC, tinfo: typeinfo.ITypeInfo From 4053b501edfbc0c36a6f00ba98f14cd9aab7c4f1 Mon Sep 17 00:00:00 2001 From: Jun Komoda <45822440+junkmd@users.noreply.github.com> Date: Wed, 21 Oct 2026 11:03:52 +0900 Subject: [PATCH 13/13] fix: Switch it back to `Any` for now since I found that a wider range of types is needed. --- comtypes/tools/codegenerator/codegenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/comtypes/tools/codegenerator/codegenerator.py b/comtypes/tools/codegenerator/codegenerator.py index 02dc6069..a3a0c899 100644 --- a/comtypes/tools/codegenerator/codegenerator.py +++ b/comtypes/tools/codegenerator/codegenerator.py @@ -81,7 +81,7 @@ def adjust_blank( yield self.stream self.last_item = item - def generate(self, item: tlbparser.ParsedType) -> None: + def generate(self, item: Any) -> None: if item in self.done: return if self._is_interface_typedesc(item):