Skip to content

Commit c6f8004

Browse files
authored
Add method annotations (all args and return-values are Any) (#490)
* add stuffs to `comtypes/hints.pyi` * add `...Annotator`s to `comtypes/tools/codegenerator.py` * add `comtypes/tools/typeannotator.py` and move `...Annotator`s from `comtypes/tools/codegenerator.py`
1 parent afc6488 commit c6f8004

File tree

3 files changed

+580
-2
lines changed

3 files changed

+580
-2
lines changed

comtypes/hints.pyi

Lines changed: 241 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,244 @@
1-
# symbols those what might occur recursive imports in runtime.
1+
# This stub contains...
2+
# - symbols those what might occur recursive imports in runtime.
3+
# - utilities for type hints.
4+
import sys
5+
from typing import (
6+
Any,
7+
Callable,
8+
Generic,
9+
Iterator,
10+
List,
11+
NoReturn,
12+
Tuple,
13+
Type,
14+
TypeVar,
15+
Optional,
16+
overload,
17+
Union as _UnionT,
18+
)
19+
20+
if sys.version_info >= (3, 8):
21+
from typing import Protocol
22+
else:
23+
from typing_extensions import Protocol
24+
if sys.version_info >= (3, 10):
25+
from typing import Concatenate, ParamSpec
26+
else:
27+
from typing_extensions import Concatenate, ParamSpec
28+
if sys.version_info >= (3, 11):
29+
from typing import Self
30+
else:
31+
from typing_extensions import Self
32+
233
from comtypes.automation import IDispatch as IDispatch, VARIANT as VARIANT
334
from comtypes.server import IClassFactory as IClassFactory
435
from comtypes.typeinfo import ITypeInfo as ITypeInfo
36+
37+
class _MethodTypeDesc(Protocol):
38+
arguments: List[Tuple[Any, str, List[str], Optional[Any]]]
39+
idlflags: List[str]
40+
name: str
41+
42+
_P_Put = ParamSpec("_P_Put")
43+
_R_Put = TypeVar("_R_Put")
44+
_P_PutRef = ParamSpec("_P_PutRef")
45+
_R_PutRef = TypeVar("_R_PutRef")
46+
47+
def put_or_putref(
48+
put: Callable[_P_Put, _R_Put], putref: Callable[_P_PutRef, _R_PutRef]
49+
) -> _UnionT[Callable[_P_Put, _R_Put], Callable[_P_PutRef, _R_PutRef]]: ...
50+
51+
_T_Inst = TypeVar("_T_Inst")
52+
_T_SetVal = TypeVar("_T_SetVal")
53+
_P_Get = ParamSpec("_P_Get")
54+
_R_Get = TypeVar("_R_Get")
55+
_P_Set = ParamSpec("_P_Set")
56+
57+
class _GetSetNormalProperty(Generic[_T_Inst, _R_Get, _T_SetVal]):
58+
fget: Callable[[_T_Inst], Any]
59+
fset: Callable[[_T_Inst, _T_SetVal], Any]
60+
61+
@overload
62+
def __get__(self, instance: None, owner: Type[_T_Inst]) -> Self: ...
63+
@overload
64+
def __get__(self, instance: _T_Inst, owner: Optional[Type[_T_Inst]]) -> _R_Get: ...
65+
def __set__(self, instance: _T_Inst, value: _T_SetVal) -> None: ...
66+
67+
class _GetOnlyNormalProperty(Generic[_T_Inst, _R_Get]):
68+
fget: Callable[[_T_Inst], Any]
69+
70+
@overload
71+
def __get__(self, instance: None, owner: Type[_T_Inst]) -> Self: ...
72+
@overload
73+
def __get__(self, instance: _T_Inst, owner: Optional[Type[_T_Inst]]) -> _R_Get: ...
74+
def __set__(self, instance: _T_Inst, value: Any) -> NoReturn: ...
75+
76+
class _SetOnlyNormalProperty(Generic[_T_Inst, _T_SetVal]):
77+
fget: Callable[[_T_Inst], Any]
78+
fset: Callable[[_T_Inst, _T_SetVal], Any]
79+
80+
@overload
81+
def __get__(self, instance: None, owner: Type[_T_Inst]) -> Self: ...
82+
@overload
83+
def __get__(
84+
self, instance: _T_Inst, owner: Optional[Type[_T_Inst]]
85+
) -> NoReturn: ...
86+
def __set__(self, instance: _T_Inst, value: _T_SetVal) -> None: ...
87+
88+
@overload
89+
def normal_property(
90+
fget: Callable[[_T_Inst], _R_Get],
91+
) -> _GetOnlyNormalProperty[_T_Inst, _R_Get]: ...
92+
@overload
93+
def normal_property(
94+
*, fset: Callable[[_T_Inst, _T_SetVal], Any]
95+
) -> _SetOnlyNormalProperty[_T_Inst, _T_SetVal]: ...
96+
@overload
97+
def normal_property(
98+
fget: Callable[[_T_Inst], _R_Get], fset: Callable[[_T_Inst, _T_SetVal], Any]
99+
) -> _GetSetNormalProperty[_T_Inst, _R_Get, _T_SetVal]: ...
100+
101+
class _GetSetBoundNamedProperty(Generic[_T_Inst, _P_Get, _R_Get, _P_Set]):
102+
name: str
103+
fget: Callable[Concatenate[_T_Inst, _P_Get], _R_Get]
104+
fset: Callable[Concatenate[_T_Inst, _P_Set], Any]
105+
__doc__: Optional[str]
106+
def __getitem__(self, index: Any) -> _R_Get: ...
107+
def __call__(self, *args: _P_Get.args, **kwargs: _P_Get.kwargs) -> _R_Get: ...
108+
def __setitem__(self, index: Any, value: Any) -> None: ...
109+
def __iter__(self) -> NoReturn: ...
110+
111+
class _GetSetNamedProperty(Generic[_T_Inst, _P_Get, _R_Get, _P_Set]):
112+
name: str
113+
fget: Callable[Concatenate[_T_Inst, _P_Get], _R_Get]
114+
fset: Callable[Concatenate[_T_Inst, _P_Set], Any]
115+
__doc__: Optional[str]
116+
117+
@overload
118+
def __get__(self, instance: None, owner: Type[_T_Inst]) -> Self: ...
119+
@overload
120+
def __get__(
121+
self, instance: _T_Inst, owner: Optional[Type[_T_Inst]]
122+
) -> _GetSetBoundNamedProperty[_T_Inst, _P_Get, _R_Get, _P_Set]: ...
123+
def __set__(self, instance: _T_Inst, value: Any) -> NoReturn: ...
124+
125+
class _GetOnlyBoundNamedProperty(Generic[_T_Inst, _P_Get, _R_Get]):
126+
name: str
127+
fget: Callable[Concatenate[_T_Inst, _P_Get], _R_Get]
128+
__doc__: Optional[str]
129+
def __getitem__(self, index: Any) -> _R_Get: ...
130+
def __call__(self, *args: _P_Get.args, **kwargs: _P_Get.kwargs) -> _R_Get: ...
131+
def __setitem__(self, index: Any, value: Any) -> NoReturn: ...
132+
def __iter__(self) -> NoReturn: ...
133+
134+
class _GetOnlyNamedProperty(Generic[_T_Inst, _P_Get, _R_Get]):
135+
name: str
136+
fget: Callable[Concatenate[_T_Inst, _P_Get], _R_Get]
137+
__doc__: Optional[str]
138+
139+
@overload
140+
def __get__(self, instance: None, owner: Type[_T_Inst]) -> Self: ...
141+
@overload
142+
def __get__(
143+
self, instance: _T_Inst, owner: Optional[Type[_T_Inst]]
144+
) -> _GetOnlyBoundNamedProperty[_T_Inst, _P_Get, _R_Get]: ...
145+
def __set__(self, instance: _T_Inst, value: Any) -> NoReturn: ...
146+
147+
class _SetOnlyBoundNamedProperty(Generic[_T_Inst, _P_Set]):
148+
name: str
149+
fset: Callable[Concatenate[_T_Inst, _P_Set], Any]
150+
__doc__: Optional[str]
151+
def __getitem__(self, index: Any) -> NoReturn: ...
152+
def __call__(self, *args: Any, **kwargs: Any) -> NoReturn: ...
153+
def __setitem__(self, index: Any, value: Any) -> None: ...
154+
def __iter__(self) -> NoReturn: ...
155+
156+
class _SetOnlyNamedProperty(Generic[_T_Inst, _P_Set]):
157+
name: str
158+
fset: Callable[Concatenate[_T_Inst, _P_Set], Any]
159+
__doc__: Optional[str]
160+
161+
@overload
162+
def __get__(self, instance: None, owner: Type[_T_Inst]) -> Self: ...
163+
@overload
164+
def __get__(
165+
self, instance: _T_Inst, owner: Optional[Type[_T_Inst]]
166+
) -> _SetOnlyBoundNamedProperty[_T_Inst, _P_Set]: ...
167+
def __set__(self, instance: _T_Inst, value: Any) -> NoReturn: ...
168+
169+
@overload
170+
def named_property(
171+
name: str, fget: Callable[Concatenate[_T_Inst, _P_Get], _R_Get]
172+
) -> _GetOnlyNamedProperty[_T_Inst, _P_Get, _R_Get]: ...
173+
@overload
174+
def named_property(
175+
name: str, *, fset: Callable[Concatenate[_T_Inst, _P_Set], Any]
176+
) -> _SetOnlyNamedProperty[_T_Inst, _P_Set]: ...
177+
@overload
178+
def named_property(
179+
name: str,
180+
fget: Callable[Concatenate[_T_Inst, _P_Get], _R_Get],
181+
fset: Callable[Concatenate[_T_Inst, _P_Set], Any],
182+
) -> _GetSetNamedProperty[_T_Inst, _P_Get, _R_Get, _P_Set]: ...
183+
184+
# for dunder methods those what be patched to ComInterface by metaclasses.
185+
186+
class _Descriptor(Protocol[_T_Inst, _R_Get]):
187+
@overload
188+
def __get__(self, instance: None, owner: Type[_T_Inst]) -> Self: ...
189+
@overload
190+
def __get__(self, instance: _T_Inst, owner: Optional[Type[_T_Inst]]) -> _R_Get: ...
191+
192+
# `__len__` for objects with `Count`
193+
@overload
194+
def to_dunder_len(count: _Descriptor[_T_Inst, int]) -> Callable[[_T_Inst], int]: ...
195+
@overload
196+
def to_dunder_len(count: Any) -> Callable[..., NoReturn]: ...
197+
198+
# `__iter__` for objects with `_NewEnum`
199+
_T_E = TypeVar("_T_E")
200+
201+
@overload
202+
def to_dunder_iter(
203+
newenum: _UnionT[
204+
_Descriptor[_T_Inst, Iterator[_T_E]], Callable[[_T_Inst], Iterator[_T_E]]
205+
]
206+
) -> Callable[[_T_Inst], Iterator[_T_E]]: ...
207+
@overload
208+
def to_dunder_iter(newenum: Any) -> Callable[..., NoReturn]: ...
209+
210+
# ... for objects with `Item`
211+
# `__call__`
212+
@overload
213+
def to_dunder_call(
214+
item: _UnionT[
215+
_GetSetNamedProperty[_T_Inst, _P_Get, _R_Get, ...],
216+
_GetOnlyNamedProperty[_T_Inst, _P_Get, _R_Get],
217+
Callable[Concatenate[_T_Inst, _P_Get], _R_Get],
218+
]
219+
) -> Callable[Concatenate[_T_Inst, _P_Get], _R_Get]: ...
220+
@overload
221+
def to_dunder_call(item: Any) -> Callable[..., NoReturn]: ...
222+
223+
# `__getitem__`
224+
@overload
225+
def to_dunder_getitem(
226+
item: _UnionT[
227+
_GetSetNamedProperty[_T_Inst, _P_Get, _R_Get, ...],
228+
_GetOnlyNamedProperty[_T_Inst, _P_Get, _R_Get],
229+
Callable[Concatenate[_T_Inst, _P_Get], _R_Get],
230+
]
231+
) -> Callable[Concatenate[_T_Inst, _P_Get], _R_Get]: ...
232+
@overload
233+
def to_dunder_getitem(item: Any) -> Callable[..., NoReturn]: ...
234+
235+
# `__setitem__`
236+
@overload
237+
def to_dunder_setitem(
238+
item: _UnionT[
239+
_GetSetNamedProperty[_T_Inst, ..., Any, _P_Set],
240+
_SetOnlyNamedProperty[_T_Inst, _P_Set],
241+
]
242+
) -> Callable[Concatenate[_T_Inst, _P_Set], Any]: ...
243+
@overload
244+
def to_dunder_setitem(item: Any) -> Callable[..., NoReturn]: ...

comtypes/tools/codegenerator.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
import comtypes
2424
from comtypes import typeinfo
25-
from comtypes.tools import tlbparser, typedesc
25+
from comtypes.tools import tlbparser, typedesc, typeannotator
2626

2727

2828
version = comtypes.__version__
@@ -561,6 +561,12 @@ def generate_wrapper_code(
561561
print("# -*- coding: mbcs -*-", file=output)
562562
print(file=output)
563563
print(self.imports.getvalue(), file=output)
564+
print("from typing import TYPE_CHECKING", file=output)
565+
print(file=output)
566+
print("if TYPE_CHECKING:", file=output)
567+
print(" from typing import Any, Tuple", file=output)
568+
print(" from comtypes import hints", file=output)
569+
print(file=output)
564570
print(file=output)
565571
print(self.declarations.getvalue(), file=output)
566572
print(file=output)
@@ -1100,6 +1106,12 @@ def ComInterfaceHead(self, head: typedesc.ComInterfaceHead) -> None:
11001106
print(" return item", file=self.stream)
11011107
print(" raise IndexError(index)", file=self.stream)
11021108

1109+
annotaions = typeannotator.ComInterfaceMembersAnnotator(head.itf).generate()
1110+
if annotaions:
1111+
print(file=self.stream)
1112+
print(" if TYPE_CHECKING: # commembers", file=self.stream)
1113+
print(annotaions, file=self.stream, end="")
1114+
11031115
print(file=self.stream)
11041116
print(file=self.stream)
11051117

@@ -1221,6 +1233,13 @@ def DispInterfaceHead(self, head: typedesc.DispInterfaceHead) -> None:
12211233
print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
12221234
print(" _idlflags_ = %s" % head.itf.idlflags, file=self.stream)
12231235
print(" _methods_ = []", file=self.stream)
1236+
1237+
annotaions = typeannotator.DispInterfaceMembersAnnotator(head.itf).generate()
1238+
if annotaions:
1239+
print(file=self.stream)
1240+
print(" if TYPE_CHECKING: # dispmembers", file=self.stream)
1241+
print(annotaions, file=self.stream, end="")
1242+
12241243
print(file=self.stream)
12251244
print(file=self.stream)
12261245

0 commit comments

Comments
 (0)