Resolve remaining type-checking errors. - #954
Merged
Merged
Conversation
… in `_memberspec.STDMETHOD`.
- Updated `STDMETHOD` signature in `_memberspec.py` to accept any `Sequence`
and cast to `tuple`.
- The `IUnknown._methods_` entry for `QueryInterface` still provides a list
(`[POINTER(GUID), POINTER(c_void_p)]`); `STDMETHOD` now internally converts
that list to a tuple, so no change to the interface definition is needed.
- This keeps `STDMETHOD` consistent with `COMMETHOD` and ensures that the
resulting `_ComMemberSpec` stores the `argtypes` as a concrete `tuple`,
matching the expectations of both helpers.
- Resolves the static type‑checking errors reported by type checkers.
This change resolves the type-checker error below.
```
> uvx pyright comtypes/_post_coinit/unknwn.py
path\to\comtypes\comtypes\_post_coinit\unknwn.py
...
path\to\comtypes\comtypes\_post_coinit\unknwn.py:389:46 - error: Argument of type "list[type[_Pointer[GUID]] | type[_Pointer[c_void_p]]]" cannot be assigned to parameter "argtypes" of type "tuple[type[_SimpleCData[Any]] | type[_Pointer[Any]] | type[CFuncPtr] | type[Union] | type[Structure] | type[Array[Any]], ...]" in function "STDMETHOD"
"list[type[_Pointer[GUID]] | type[_Pointer[c_void_p]]]" is not assignable to "tuple[type[_SimpleCData[Any]] | type[_Pointer[Any]] | type[CFuncPtr] | type[Union] | type[Structure] | type[Array[Any]], ...]" (reportArgumentType)
...
```
```
> uvx ty check comtypes/_post_coinit/unknwn.py
...
error[invalid-argument-type]: Argument to function `STDMETHOD` is incorrect
--> comtypes\_post_coinit\unknwn.py:389:46
|
389 | STDMETHOD(HRESULT, "QueryInterface", [POINTER(GUID), POINTER(c_void_p)]),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Expected `tuple[type[_SimpleCData[Any] | _Pointer[Any] | CFuncPtr | ... omitted 3 types], ...]`, found `list[type[_Pointer[GUID] | _Pointer[c_void_p]]]`
info: Function defined here
--> comtypes\_memberspec.py:168:5
|
168 | def STDMETHOD(
| ^^^^^^^^^
169 | restype: Optional[type["_CDataType"]],
170 | name: str,
171 | argtypes: tuple[type["_CDataType"], ...] = (),
| --------------------------------------------- Parameter declared here
...
```
…OD`.
- Added `_ResArgSpecElmType` alias representing argspec tuples with just flags
and return type.
- Updated `ArgSpecElmType` to include `_ResArgSpecElmType` alongside positional
and optional specs.
- This matches the usage in `automation.py`.
- Enables static type checkers to accept return‑value‑only argspecs without
extra string description.
This change resolves the type-checker error below.
```
> uvx pyright comtypes/_post_coinit/unknwn.py
path\to\comtypes\comtypes\automation.py
...
path\to\comtypes\comtypes\automation.py:778:52 - error: Argument of type "tuple[list[str], type[_Pointer[c_uint]]]" cannot be assigned to parameter "argspec" of type "ArgSpecElmType" in function "COMMETHOD"
Type "tuple[list[str], type[_Pointer[c_uint]]]" is not assignable to type "ArgSpecElmType"
"tuple[list[str], type[_Pointer[c_uint]]]" is not assignable to "tuple[list[str], type[_SimpleCData[Any]] | type[_Pointer[Any]] | type[CFuncPtr] | type[Union] | type[Structure] | type[Array[Any]], str]"
Tuple size mismatch; expected 3 but received 2
"tuple[list[str], type[_Pointer[c_uint]]]" is not assignable to "tuple[list[str], type[_SimpleCData[Any]] | type[_Pointer[Any]] | type[CFuncPtr] | type[Union] | type[Structure] | type[Array[Any]], str, Any]"
Tuple size mismatch; expected 4 but received 2 (reportArgumentType)
...
```
```
> uvx ty check comtypes/automation.py
...
error[invalid-argument-type]: Argument to function `COMMETHOD` is incorrect
--> comtypes\automation.py:778:52
|
778 | COMMETHOD([], HRESULT, "GetTypeInfoCount", (["out"], POINTER(UINT))),
| ^^^^^^^^^^^^^^^^^^^^^^^^ Expected `tuple[list[str], type[_SimpleCData[Any] | _Pointer[Any] | CFuncPtr | ... omitted 3 types], str] | tuple[list[str], type[_SimpleCData[Any] | _Pointer[Any] | CFuncPtr | ... omitted 3 types], str, Any]`, found `tuple[list[str], type[_Pointer[c_uint]]]`
info: type `tuple[list[str], type[_Pointer[c_uint]]]` is not assignable to any element of the union `tuple[list[str], type[_SimpleCData[Any] | _Pointer[Any] | CFuncPtr | ... omitted 3 types], str] | tuple[list[str], type[_SimpleCData[Any] | _Pointer[Any] | CFuncPtr | ... omitted 3 types], str, Any]`
info: ├── a tuple of length 2 is not assignable to a tuple of length 3
info: └── a tuple of length 2 is not assignable to a tuple of length 4
info: Function defined here
--> comtypes\_memberspec.py:205:5
|
205 | def COMMETHOD(
| ^^^^^^^^^
206 | idlflags: Sequence[_UnionT[int, str]],
207 | restype: Optional[type["_CDataType"]],
208 | methodname: str,
209 | *argspec: "hints.ArgSpecElmType",
| -------------------------------- Parameter declared here
...
```
…THOD`, `DISPPROPERTY`, and `COMMETHOD`.
- Updated `DISPMETHOD` and `DISPPROPERTY` to call `tuple(idlflags)` with a
`# type: ignore` comment because the incoming `idlflags` sequence may contain
a mix of `int` and `str` (e.g., `(dispid, "readonly")`).
The static type checker expects a fixed‑length tuple of either only strings
or a `dispid` followed by strings, which does not match the runtime
representation.
- Updated `COMMETHOD` similarly, adding `# type: ignore` to the
`tuple(idlflags)` conversion.
- These changes keep the runtime behavior unchanged (the function still
receives a tuple) while silencing type‑checker errors about the
incompatibility of the input sequence type.
- The function signatures continue to accept a flexible `Sequence` for
`idlflags`; the `type: ignore` acknowledges that the cast cannot be expressed
precisely in static typing.
This change resolves the type-checker error below.
```
> uvx pyright comtypes/_memberspec.py
path\to\comtypes\comtypes\_memberspec.py
...
path\to\comtypes\comtypes\_memberspec.py:184:48 - error: Argument of type "tuple[int | str, ...]" cannot be assigned to parameter "idlflags" of type "_DispIdlFlags" in function "__new__"
Type "tuple[int | str, ...]" is not assignable to type "_DispIdlFlags"
"tuple[int | str, ...]" is not assignable to "tuple[dispid, helpstring, *tuple[str, ...]]"
Tuple size mismatch; expected 2 or more but received indeterminate
"tuple[int | str, ...]" is not assignable to "tuple[dispid, *tuple[str, ...]]"
Tuple size mismatch; expected 1 or more but received indeterminate (reportArgumentType)
path\to\comtypes\comtypes\_memberspec.py:193:50 - error: Argument of type "tuple[int | str, ...]" cannot be assigned to parameter "idlflags" of type "_DispIdlFlags" in function "__new__"
Type "tuple[int | str, ...]" is not assignable to type "_DispIdlFlags"
"tuple[int | str, ...]" is not assignable to "tuple[dispid, helpstring, *tuple[str, ...]]"
Tuple size mismatch; expected 2 or more but received indeterminate
"tuple[int | str, ...]" is not assignable to "tuple[dispid, *tuple[str, ...]]"
Tuple size mismatch; expected 1 or more but received indeterminate (reportArgumentType)
path\to\comtypes\comtypes\_memberspec.py:229:46 - error: Argument of type "tuple[int | str, ...]" cannot be assigned to parameter "idlflags" of type "_ComIdlFlags | _DispIdlFlags" in function "__new__"
Type "tuple[int | str, ...]" is not assignable to type "_ComIdlFlags | _DispIdlFlags"
"tuple[int | str, ...]" is not assignable to "tuple[str, ...]"
Tuple entry 1 is incorrect type
Type "int | str" is not assignable to type "str"
"int" is not assignable to "str"
"tuple[int | str, ...]" is not assignable to "tuple[helpstring, *tuple[str, ...]]"
Tuple size mismatch; expected 1 or more but received indeterminate
"tuple[int | str, ...]" is not assignable to "tuple[dispid, helpstring, *tuple[str, ...]]"
... (reportArgumentType)
...
```
```
> uvx ty check comtypes/_memberspec.py
...
error[invalid-argument-type]: Argument is incorrect
--> comtypes\_memberspec.py:184:48
|
184 | return _DispMemberSpec("DISPMETHOD", name, tuple(idlflags), restype, argspec)
| ^^^^^^^^^^^^^^^ Expected `tuple[dispid, *tuple[str, ...]]`, found `tuple[int | str, ...]`
error[invalid-argument-type]: Argument is incorrect
--> comtypes\_memberspec.py:193:50
|
193 | return _DispMemberSpec("DISPPROPERTY", name, tuple(idlflags), proptype, ())
| ^^^^^^^^^^^^^^^ Expected `tuple[dispid, *tuple[str, ...]]`, found `tuple[int | str, ...]`
error[invalid-argument-type]: Argument is incorrect
--> comtypes\_memberspec.py:229:46
|
229 | restype, name, argtypes, paramflags, tuple(idlflags), helptext
| ^^^^^^^^^^^^^^^ Expected `tuple[str, ...] | tuple[dispid, *tuple[str, ...]]`, found `tuple[int | str, ...]`
info: type `tuple[int | str, ...]` is not assignable to any element of the union `tuple[str, ...] | tuple[dispid, *tuple[str, ...]]`
info: ├── element `int` of union `int | str` is not assignable to `str`
info: └── ... omitted 1 union element without additional context
...
```
…HOD`, `DISPMETHOD`, `DISPPROPERTY`, `COMMETHOD`) in `_memberspec`.
…type` (type["_CDataType"]). This reflects that a dispinterface property never returns `null`/`void`, so `None` is never a valid `proptype`.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #954 +/- ##
=======================================
Coverage 88.98% 88.98%
=======================================
Files 140 140
Lines 13678 13678
=======================================
Hits 12171 12171
Misses 1507 1507 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR is a follow-up to #949 (commit 7ca1829).
Enabling PEP 561 discovery in that PR surfaced some type-checking errors that were missed at review time.
Changes
1.
STDMETHOD: AcceptSequenceinstead oftupleforargtypesIUnknown._methods_passes alistto theargtypesargument ofSTDMETHOD.The previous annotation specified
tuplefor this argument, causing areportArgumentTypeerror in bothpyrightandty.The argument is now annotated with the abstract type
Sequence[type[_CDataType]]instead of a concrete type, and converted to atupleinternally. This is consistent withCOMMETHOD.2.
ArgSpecElmType: Add length-2 return-value argspec variantautomation.pyuses(["out"], POINTER(UINT))— a 2-element argspec for a return value with no parameter name._ResArgSpecElmTypehas been added tohints.pyito cover this pattern and included inArgSpecElmType.3.
DISPMETHOD/DISPPROPERTY/COMMETHOD: Suppressidlflagscast errortuple(idlflags)producestuple[int | str, ...], which is not directly assignable to the narrowly-typed_DispIdlFlags/_ComIdlFlagsfields.A
# type: ignorecomment suppresses the false-positive at each call site; runtime behaviour is unchanged.4. Add detailed docstrings to COM method helper functions in
_memberspec.The semantics of the arguments are now explained in the docstring.
5. Update
DISPPROPERTYsignature to use a non-optionalproptypeThis reflects that a dispinterface property never returns
null/void, soNoneis never a validproptype.Related
Remaining work
A suitable test double has not yet been found for these cases.
Rather than defining a fictional interface or specifier specifically for testing, I believe a more robust approach would be to find an existing, working interface definition that naturally satisfies the requirements being tested.