From f95643706ac28e5581bebcc446f2ceb8541ec364 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:19 +0900 Subject: [PATCH 01/12] style: Remove redundant warnings import and streamline warning usage in `Parser` class. --- comtypes/tools/tlbparser.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index 123b9838..727598ac 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -1,5 +1,6 @@ import os import sys +import warnings from _ctypes import COMError from collections.abc import Mapping from ctypes import alignment, c_void_p, sizeof, windll @@ -191,8 +192,6 @@ def make_type( f"\n\tGetRefTypeInfo failed in {tlib_name}: {details}" f"\n\tgenerating type '{type_name}' instead" ) - import warnings - warnings.warn(message, UserWarning) result = typedesc.Structure( type_name, align=8, members=[], bases=[], size=0 @@ -321,8 +320,6 @@ def ParseInterface( # It's an interface without methods anyway. if itf_name != "IOleControlTypes": message = f"Ignoring interface {itf_name} which has no base interface" - import warnings - warnings.warn(message, UserWarning) return None From 7b726d840c051b82f25198581acc529f590df17a Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 02/12] fix: Optimize handling of `IUnknown` and `IDispatch` in Parser to reduce redundancy. --- comtypes/tools/tlbparser.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index 727598ac..f6ae1117 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -8,7 +8,7 @@ from typing import Any, Optional, TypeVar from typing import Union as _UnionT -from comtypes import automation, typeinfo +from comtypes import IUnknown, automation, typeinfo from comtypes.tools import typedesc # Is the process 64-bit? @@ -159,6 +159,12 @@ def midlSAFEARRAY(typ: _PT) -> typedesc.SAFEARRAYType[_PT]: ################################################################ +# To suppress obvious, non-essential warnings. +# Cast to str only once to avoid redundant work. +_IID_IUnknown = str(IUnknown._iid_) +_IID_IDispatch = str(automation.IDispatch._iid_) + + class Parser: tlib: typeinfo.ITypeLib items: dict[str, ParsedType] @@ -324,6 +330,16 @@ def ParseInterface( return None iid = str(ta.guid) + # IUnknown and IDispatch are fundamental COM interfaces, so reuse + # their canonical type-model constants instead of rebuilding a + # model from the type library. This avoids redundant work and + # keeps the handling of these well-known symbols consistent. + if iid == _IID_IUnknown: + self._register(itf_name, IUNKNOWN_type) + return IUNKNOWN_type + if iid == _IID_IDispatch: + self._register(itf_name, IDISPATCH_type) + return IDISPATCH_type idlflags = self.interface_type_flags(ta.wTypeFlags) itf = typedesc.ComInterface(itf_name, None, iid, idlflags, itf_doc) self._register(itf_name, itf) From 4141cf6621ee8282493fe7ededf389a9d60a8345 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 03/12] refactor: Annotate interface bases with valid `typedesc` types. --- comtypes/tools/typedesc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/comtypes/tools/typedesc.py b/comtypes/tools/typedesc.py index 70121ac8..5fcd1917 100644 --- a/comtypes/tools/typedesc.py +++ b/comtypes/tools/typedesc.py @@ -177,7 +177,7 @@ class DispInterface: def __init__( self, name: str, - base: Any, + base: "_UnionT[ComInterface, DispInterface, External]", iid: str, idlflags: list[str], doc: Optional[str], @@ -218,7 +218,7 @@ class ComInterface: def __init__( self, name: str, - base: "Optional[ComInterface]", + base: "_UnionT[None, ComInterface, External]", iid: str, idlflags: list[str], doc: Optional[str], From 3a578a4eca14d36abadf78bd5af56a0cb1075ff8 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 04/12] refactor: Annotate structure members as fields. The parser only passes `Field` objects to records and unions, but `_Struct_Union_Base` allowed `Field`, `Method`, and `Constructor` members. Update its member annotation to reflect the objects actually produced by the parser. --- comtypes/tools/typedesc_base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/comtypes/tools/typedesc_base.py b/comtypes/tools/typedesc_base.py index 1cd1352a..44dd2910 100644 --- a/comtypes/tools/typedesc_base.py +++ b/comtypes/tools/typedesc_base.py @@ -1,6 +1,5 @@ # typedesc.py - classes representing C type descriptions from typing import Any, Generic, Optional, SupportsInt, TypeVar, final -from typing import Union as _UnionT _TD = TypeVar("_TD") @@ -167,7 +166,7 @@ def __init__(self, struct: "_Struct_Union_Base") -> None: class _Struct_Union_Base: name: str align: int - members: list[_UnionT["Field", Method, Constructor]] + members: list["Field"] bases: list["_Struct_Union_Base"] artificial: Optional[Any] size: Optional[int] From 42a3a1d27eb15f25b9877ec9c7a1c9278653700e Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 05/12] refactor: Remove method branches from structure generation The parser only passes `Field` objects to records and unions, but the structure generator still handled the unused `Method` and `Constructor` members. This suggests that this part of `typedesc` came from an older, more general C or C++ type model. Remove those branches so the model matches the COM type library rules, and generate structure packing and fields directly. --- comtypes/tools/codegenerator/codegenerator.py | 60 ++++--------------- 1 file changed, 11 insertions(+), 49 deletions(-) diff --git a/comtypes/tools/codegenerator/codegenerator.py b/comtypes/tools/codegenerator/codegenerator.py index b8f44961..e4233f4b 100644 --- a/comtypes/tools/codegenerator/codegenerator.py +++ b/comtypes/tools/codegenerator/codegenerator.py @@ -449,34 +449,26 @@ def Union(self, union: typedesc.Union) -> None: def StructureBody(self, body: typedesc.StructureBody) -> None: fields: list[typedesc.Field] = [] - methods: list[typedesc.Method] = [] for m in body.struct.members: if isinstance(m, typedesc.Field): fields.append(m) if isinstance(m.typ, typedesc.Typedef): self.generate(get_real_type(m.typ)) self.generate(m.typ) - elif isinstance(m, typedesc.Method): - methods.append(m) - self.generate(m.returns) - self.generate_all(m.iterArgTypes()) - elif isinstance(m, typedesc.Constructor): - pass # we don't need _pack_ on Unions (I hope, at least), and not # on COM interfaces: - if not methods: - try: - pack = packing.calc_packing(body.struct, fields) - if pack is not None: - with self.adjust_blank("attribute") as ofi: - print(f"{body.struct.name}._pack_ = {pack}", file=ofi) - except packing.PackingError as details: - # if packing fails, write a warning comment to the output. - message = f"Structure {body.struct.name}: {details}" - warnings.warn(message, UserWarning) - with self.adjust_blank("comment") as ofi: - print(f"# WARNING: {details}", file=ofi) + try: + pack = packing.calc_packing(body.struct, fields) + if pack is not None: + with self.adjust_blank("attribute") as ofi: + print(f"{body.struct.name}._pack_ = {pack}", file=ofi) + except packing.PackingError as details: + # if packing fails, write a warning comment to the output. + message = f"Structure {body.struct.name}: {details}" + warnings.warn(message, UserWarning) + with self.adjust_blank("comment") as ofi: + print(f"# WARNING: {details}", file=ofi) if fields: if body.struct.bases: assert len(body.struct.bases) == 1 @@ -489,10 +481,6 @@ def StructureBody(self, body: typedesc.StructureBody) -> None: elif body.struct.name not in packing.dont_assert_size: with self.adjust_blank("assert") as ofi: self._write_structbody_size_assertion(body, ofi) - if methods: - self.imports.add("comtypes", "COMMETHOD") - with self.adjust_blank("attribute") as ofi: - self._write_structbody_commethods(body, methods, ofi) def _write_structbody_fields( self, @@ -537,32 +525,6 @@ def _write_structbody_size_assertion( align = body.struct.align // 8 print(f"assert alignment({name}) == {align}, alignment({name})", file=ofi) - def _write_structbody_commethods( - self, - body: typedesc.StructureBody, - methods: list[typedesc.Method], - ofi: io.StringIO, - ) -> None: - print(f"{body.struct.name}._methods_ = [", file=ofi) - if body.struct.location: - print(f"# {body.struct.location}", file=ofi) - for m in methods: - if m.location: - print(f" # {m.location}", file=ofi) - print( - ( - " COMMETHOD(\n" - " [],\n" - f" {self._to_type_name(m.returns)},\n" - f" '{m.name}',\n" - ), - file=ofi, - ) - for a in m.iterArgTypes(): - print(f" ([], {self._to_type_name(a)}),\n", file=ofi) - print(" ),", file=ofi) - print("]", file=ofi) - ################################################################ # top-level typedesc generators # From b67f28324410f94ef355dfc873cabddc3ab6a83f Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 06/12] refactor: Remove unused method handling from structure headers The parser only passes `Field` objects to records and unions, but the structure header generator still checked for unused `Method` members. This suggests that this part of `typedesc` came from an older, more general C or C++ type model. Remove that obsolete branch so the model matches the COM type library rules. --- comtypes/tools/codegenerator/heads.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/comtypes/tools/codegenerator/heads.py b/comtypes/tools/codegenerator/heads.py index 9831cd41..0de66559 100644 --- a/comtypes/tools/codegenerator/heads.py +++ b/comtypes/tools/codegenerator/heads.py @@ -47,14 +47,7 @@ def write(self, head: typedesc.StructureHead, basenames: Sequence[str]) -> None: print(" return arr[0]", file=self.stream) else: - methods = [m for m in head.struct.members if type(m) is typedesc.Method] - - if methods: - # Hm. We cannot generate code for IUnknown... - print("assert 0, 'cannot generate code for IUnknown'", file=self.stream) - print(f"class {head.struct.name}(_com_interface):", file=self.stream) - print(" pass", file=self.stream) - elif type(head.struct) is typedesc.Structure: + if type(head.struct) is typedesc.Structure: print(f"class {head.struct.name}(Structure):", file=self.stream) if hasattr(head.struct, "_recordinfo_"): print( From 7c0351b6eeabea6b045b230aad79d519ff38fdac Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 07/12] refactor: Remove legacy method helpers from structure headers The parser only passes `Field` objects to records and unions, but the structure header generator still emitted helpers based on unused `Method` members. This suggests that this part of `typedesc` came from an older, more general C or C++ type model. Remove those obsolete branches so the model matches the COM type library rules. --- comtypes/tools/codegenerator/heads.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/comtypes/tools/codegenerator/heads.py b/comtypes/tools/codegenerator/heads.py index 0de66559..f3352be0 100644 --- a/comtypes/tools/codegenerator/heads.py +++ b/comtypes/tools/codegenerator/heads.py @@ -22,9 +22,6 @@ def write(self, head: typedesc.StructureHead, basenames: Sequence[str]) -> None: if head.struct.location: print(f"# {head.struct.location}", file=self.stream) if basenames: - method_names = [ - m.name for m in head.struct.members if type(m) is typedesc.Method - ] print( f"class {head.struct.name}({', '.join(basenames)}):", file=self.stream, @@ -33,18 +30,6 @@ def write(self, head: typedesc.StructureHead, basenames: Sequence[str]) -> None: " _iid_ = GUID('{}') # please look up iid and fill in!", file=self.stream, ) - if "Enum" in method_names: - print(" def __iter__(self):", file=self.stream) - print(" return self.Enum()", file=self.stream) - elif method_names == "Next Skip Reset Clone".split(): - print(" def __iter__(self):", file=self.stream) - print(" return self", file=self.stream) - print(file=self.stream) - print(" def next(self):", file=self.stream) - print(" arr, fetched = self.Next(1)", file=self.stream) - print(" if fetched == 0:", file=self.stream) - print(" raise StopIteration", file=self.stream) - print(" return arr[0]", file=self.stream) else: if type(head.struct) is typedesc.Structure: From b213926527f239a884e09247f3648c40f44eadd7 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 08/12] refactor: Remove legacy base output for structures Records and unions are data types in the COM type library model. The parser provides their fields, while the older structure header path also emitted base classes and an IID. Remove that legacy output so generated structure headers reflect the data-only model. --- comtypes/tools/codegenerator/codegenerator.py | 6 +--- comtypes/tools/codegenerator/heads.py | 33 +++++-------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/comtypes/tools/codegenerator/codegenerator.py b/comtypes/tools/codegenerator/codegenerator.py index e4233f4b..aec4b3d1 100644 --- a/comtypes/tools/codegenerator/codegenerator.py +++ b/comtypes/tools/codegenerator/codegenerator.py @@ -431,12 +431,8 @@ def StructureHead(self, head: typedesc.StructureHead) -> None: for struct in head.struct.bases: self.generate(struct.get_head()) self.more.add(struct) - basenames = [self._to_type_name(b) for b in head.struct.bases] - if basenames: - self.imports.add("comtypes", "GUID") - with self.adjust_blank("class") as ofi: - heads.StructureHeadWriter(ofi).write(head, basenames) + heads.StructureHeadWriter(ofi).write(head) self.names.add(head.struct.name) def Structure(self, struct: typedesc.Structure) -> None: diff --git a/comtypes/tools/codegenerator/heads.py b/comtypes/tools/codegenerator/heads.py index f3352be0..52f32af1 100644 --- a/comtypes/tools/codegenerator/heads.py +++ b/comtypes/tools/codegenerator/heads.py @@ -1,5 +1,4 @@ import io -from collections.abc import Sequence from typing import Optional from comtypes.tools import typedesc @@ -18,32 +17,18 @@ class StructureHeadWriter: def __init__(self, stream: io.StringIO) -> None: self.stream = stream - def write(self, head: typedesc.StructureHead, basenames: Sequence[str]) -> None: + def write(self, head: typedesc.StructureHead) -> None: if head.struct.location: print(f"# {head.struct.location}", file=self.stream) - if basenames: - print( - f"class {head.struct.name}({', '.join(basenames)}):", - file=self.stream, - ) - print( - " _iid_ = GUID('{}') # please look up iid and fill in!", - file=self.stream, - ) - - else: - if type(head.struct) is typedesc.Structure: - print(f"class {head.struct.name}(Structure):", file=self.stream) - if hasattr(head.struct, "_recordinfo_"): - print( - f" _recordinfo_ = {head.struct._recordinfo_!r}", - file=self.stream, - ) - else: - print(" pass", file=self.stream) - elif type(head.struct) is typedesc.Union: - print(f"class {head.struct.name}(Union):", file=self.stream) + if type(head.struct) is typedesc.Structure: + print(f"class {head.struct.name}(Structure):", file=self.stream) + if hasattr(head.struct, "_recordinfo_"): + print(f" _recordinfo_ = {head.struct._recordinfo_!r}", file=self.stream) + else: print(" pass", file=self.stream) + elif type(head.struct) is typedesc.Union: + print(f"class {head.struct.name}(Union):", file=self.stream) + print(" pass", file=self.stream) class LibraryHeadWriter: From e31197fcd7288089a8090b2d0603f9af1fd9a262 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 09/12] refactor: Stop traversing legacy structure bases Records and unions are data types in the COM type library model. Their members are fields, and the parser does not provide structure base types. Remove the code-generator traversal of those obsolete bases so generation follows the data-only model. --- comtypes/tools/codegenerator/codegenerator.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/comtypes/tools/codegenerator/codegenerator.py b/comtypes/tools/codegenerator/codegenerator.py index aec4b3d1..5510450e 100644 --- a/comtypes/tools/codegenerator/codegenerator.py +++ b/comtypes/tools/codegenerator/codegenerator.py @@ -428,9 +428,6 @@ def FundamentalType(self, item: typedesc.FundamentalType) -> None: pass # we should check if this is known somewhere def StructureHead(self, head: typedesc.StructureHead) -> None: - for struct in head.struct.bases: - self.generate(struct.get_head()) - self.more.add(struct) with self.adjust_blank("class") as ofi: heads.StructureHeadWriter(ofi).write(head) self.names.add(head.struct.name) @@ -466,9 +463,6 @@ def StructureBody(self, body: typedesc.StructureBody) -> None: with self.adjust_blank("comment") as ofi: print(f"# WARNING: {details}", file=ofi) if fields: - if body.struct.bases: - assert len(body.struct.bases) == 1 - self.generate(body.struct.bases[0].get_body()) with self.adjust_blank("attribute") as ofi: self._write_structbody_fields(body, fields, ofi) if body.struct.size is None: From b632e27f3807b21ada8c22e2da3bba044855ba53 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 10/12] refactor: Remove structure bases from the COM type model Records and unions are data types in the COM type library model. The parser only provides their fields, so the obsolete `bases` parameter and stored base types are unnecessary. Remove them from the type descriptions, parser calls, packing support, and related packing tests. --- comtypes/test/test_packing.py | 10 +++------- comtypes/tools/codegenerator/heads.py | 4 +++- comtypes/tools/codegenerator/packing.py | 3 --- comtypes/tools/tlbparser.py | 8 +------- comtypes/tools/typedesc_base.py | 5 ----- 5 files changed, 7 insertions(+), 23 deletions(-) diff --git a/comtypes/test/test_packing.py b/comtypes/test/test_packing.py index d24f4e8f..13bbfef7 100644 --- a/comtypes/test/test_packing.py +++ b/comtypes/test/test_packing.py @@ -15,16 +15,12 @@ class CalcPackingTest(unittest.TestCase): def test_returns_none_for_default_packing(self): # A naturally laid out single-field struct needs no explicit packing. field = _make_field("a", 32, 32, 0) - struct = typedesc.Structure( - "Good", align=32, members=[field], bases=[], size=32 - ) + struct = typedesc.Structure("Good", align=32, members=[field], size=32) self.assertIsNone(calc_packing(struct, [field])) def test_incomplete_struct_returns_none(self): field = _make_field("a", 32, 32, 0) - struct = typedesc.Structure( - "Incomplete", align=32, members=[field], bases=[], size=None - ) + struct = typedesc.Structure("Incomplete", align=32, members=[field], size=None) self.assertIsNone(calc_packing(struct, [field])) def test_raises_packing_error_with_details_when_layout_is_inconsistent(self): @@ -36,7 +32,7 @@ def test_raises_packing_error_with_details_when_layout_is_inconsistent(self): # ``except ... as`` target after it had been cleared, raising # ``UnboundLocalError`` and masking the real ``PackingError``. field = _make_field("x", 32, 32, 64) - struct = typedesc.Structure("Bad", align=32, members=[field], bases=[], size=96) + struct = typedesc.Structure("Bad", align=32, members=[field], size=96) with self.assertRaises(PackingError) as ctx: calc_packing(struct, [field]) message = str(ctx.exception) diff --git a/comtypes/tools/codegenerator/heads.py b/comtypes/tools/codegenerator/heads.py index 52f32af1..ef5becf0 100644 --- a/comtypes/tools/codegenerator/heads.py +++ b/comtypes/tools/codegenerator/heads.py @@ -23,7 +23,9 @@ def write(self, head: typedesc.StructureHead) -> None: if type(head.struct) is typedesc.Structure: print(f"class {head.struct.name}(Structure):", file=self.stream) if hasattr(head.struct, "_recordinfo_"): - print(f" _recordinfo_ = {head.struct._recordinfo_!r}", file=self.stream) + print( + f" _recordinfo_ = {head.struct._recordinfo_!r}", file=self.stream + ) else: print(" pass", file=self.stream) elif type(head.struct) is typedesc.Union: diff --git a/comtypes/tools/codegenerator/packing.py b/comtypes/tools/codegenerator/packing.py index b9c219a4..f081b1da 100644 --- a/comtypes/tools/codegenerator/packing.py +++ b/comtypes/tools/codegenerator/packing.py @@ -8,9 +8,6 @@ def _calc_packing(struct, fields, pack, isStruct): return -1 if struct.name in dont_assert_size: return None - if struct.bases: - size = struct.bases[0].size - total_align = struct.bases[0].align else: size = 0 total_align = 8 # in bits diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index f6ae1117..189a28b3 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -50,7 +50,6 @@ def PTR(typ: _PT) -> typedesc.PointerType[_PT]: "VARIANT", align=alignment(automation.VARIANT) * 8, members=[], - bases=[], size=sizeof(automation.VARIANT) * 8, ) @@ -85,7 +84,6 @@ def PTR(typ: _PT) -> typedesc.PointerType[_PT]: "DECIMAL", align=alignment(automation.DECIMAL) * 8, members=[], - bases=[], size=sizeof(automation.DECIMAL) * 8, ) @@ -199,9 +197,7 @@ def make_type( f"\n\tgenerating type '{type_name}' instead" ) warnings.warn(message, UserWarning) - result = typedesc.Structure( - type_name, align=8, members=[], bases=[], size=0 - ) + result = typedesc.Structure(type_name, align=8, members=[], size=0) return result result = self.parse_typeinfo(ti) assert result is not None, ti.GetDocumentation(-1)[0] @@ -241,7 +237,6 @@ def ParseRecord( struct_name, align=ta.cbAlignment * 8, members=members, - bases=[], size=ta.cbSizeInstance * 8, ) self._register(struct_name, struct) @@ -616,7 +611,6 @@ def ParseUnion( union_name, align=ta.cbAlignment * 8, members=members, - bases=[], size=ta.cbSizeInstance * 8, ) self._register(union_name, union) diff --git a/comtypes/tools/typedesc_base.py b/comtypes/tools/typedesc_base.py index 44dd2910..ccd94910 100644 --- a/comtypes/tools/typedesc_base.py +++ b/comtypes/tools/typedesc_base.py @@ -167,7 +167,6 @@ class _Struct_Union_Base: name: str align: int members: list["Field"] - bases: list["_Struct_Union_Base"] artificial: Optional[Any] size: Optional[int] _recordinfo_: tuple[str, int, int, int, str] @@ -192,14 +191,12 @@ def __init__( name: str, align: SupportsInt, members: list["Field"], - bases: list[Any], size: Optional[SupportsInt], artificial: Optional[Any] = None, ) -> None: self.name = name self.align = int(align) self.members = members - self.bases = bases self.artificial = artificial if size is not None: self.size = int(size) @@ -215,14 +212,12 @@ def __init__( name: str, align: SupportsInt, members: list["Field"], - bases: list[Any], size: Optional[SupportsInt], artificial: Optional[Any] = None, ) -> None: self.name = name self.align = int(align) self.members = members - self.bases = bases self.artificial = artificial if size is not None: self.size = int(size) From 680befd5df57e4b03be64d30d7cd6f282b3e631b Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 13:44:20 +0900 Subject: [PATCH 11/12] refactor: Simplify structure initialization in `_calc_packing` function --- comtypes/tools/codegenerator/packing.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/comtypes/tools/codegenerator/packing.py b/comtypes/tools/codegenerator/packing.py index f081b1da..5d389233 100644 --- a/comtypes/tools/codegenerator/packing.py +++ b/comtypes/tools/codegenerator/packing.py @@ -8,9 +8,8 @@ def _calc_packing(struct, fields, pack, isStruct): return -1 if struct.name in dont_assert_size: return None - else: - size = 0 - total_align = 8 # in bits + size = 0 + total_align = 8 # in bits for i, f in enumerate(fields): if f.bits: # this code cannot handle bit field sizes. # print "##XXX FIXME" From c59788d0df8373f4c3288068213bbde2521840e2 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Oct 2026 14:01:16 +0900 Subject: [PATCH 12/12] refactor: Use `isinstance` for type checking in `StructureHeadWriter`. --- comtypes/tools/codegenerator/heads.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/comtypes/tools/codegenerator/heads.py b/comtypes/tools/codegenerator/heads.py index ef5becf0..1baf68d3 100644 --- a/comtypes/tools/codegenerator/heads.py +++ b/comtypes/tools/codegenerator/heads.py @@ -20,7 +20,7 @@ def __init__(self, stream: io.StringIO) -> None: def write(self, head: typedesc.StructureHead) -> None: if head.struct.location: print(f"# {head.struct.location}", file=self.stream) - if type(head.struct) is typedesc.Structure: + if isinstance(head.struct, typedesc.Structure): print(f"class {head.struct.name}(Structure):", file=self.stream) if hasattr(head.struct, "_recordinfo_"): print( @@ -28,7 +28,7 @@ def write(self, head: typedesc.StructureHead) -> None: ) else: print(" pass", file=self.stream) - elif type(head.struct) is typedesc.Union: + elif isinstance(head.struct, typedesc.Union): print(f"class {head.struct.name}(Union):", file=self.stream) print(" pass", file=self.stream)