Skip to content

Commit 11410ce

Browse files
authored
add type annotations other than Dispatch func (#444)
1 parent 6b551a4 commit 11410ce

File tree

1 file changed

+35
-29
lines changed

1 file changed

+35
-29
lines changed

comtypes/client/dynamic.py

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import ctypes
2+
from typing import Any, Dict, Optional, Set, Type, TypeVar
23

34
from comtypes import automation
45
from comtypes.client import lazybind
5-
from comtypes import COMError, hresult as hres, _is_object
6+
from comtypes import COMError, GUID, IUnknown, hresult as hres, _is_object
67

8+
9+
_T_IUnknown = TypeVar("_T_IUnknown", bound=IUnknown)
710
# These errors generally mean the property or method exists,
811
# but can't be used in this context - eg, property instead of a method, etc.
912
# Used to determine if we have a real error or not.
@@ -17,8 +20,9 @@
1720

1821

1922
def Dispatch(obj):
20-
# Wrap an object in a Dispatch instance, exposing methods and properties
21-
# via fully dynamic dispatch
23+
"""Wrap an object in a Dispatch instance, exposing methods and properties
24+
via fully dynamic dispatch.
25+
"""
2226
if isinstance(obj, _Dispatch):
2327
return obj
2428
if isinstance(obj, ctypes.POINTER(automation.IDispatch)):
@@ -33,19 +37,19 @@ def Dispatch(obj):
3337
class MethodCaller:
3438
# Wrong name: does not only call methods but also handle
3539
# property accesses.
36-
def __init__(self, _id, _obj):
40+
def __init__(self, _id: int, _obj: "_Dispatch") -> None:
3741
self._id = _id
3842
self._obj = _obj
3943

40-
def __call__(self, *args):
44+
def __call__(self, *args: Any) -> Any:
4145
return self._obj._comobj.Invoke(self._id, *args)
4246

43-
def __getitem__(self, *args):
47+
def __getitem__(self, *args: Any) -> Any:
4448
return self._obj._comobj.Invoke(
4549
self._id, *args, _invkind=automation.DISPATCH_PROPERTYGET
4650
)
4751

48-
def __setitem__(self, *args):
52+
def __setitem__(self, *args: Any) -> None:
4953
if _is_object(args[-1]):
5054
self._obj._comobj.Invoke(
5155
self._id, *args, _invkind=automation.DISPATCH_PROPERTYPUTREF
@@ -57,22 +61,26 @@ def __setitem__(self, *args):
5761

5862

5963
class _Dispatch(object):
60-
# Expose methods and properties via fully dynamic dispatch
61-
def __init__(self, comobj):
64+
"""Expose methods and properties via fully dynamic dispatch."""
65+
66+
_comobj: automation.IDispatch
67+
_ids: Dict[str, int]
68+
_methods: Set[str]
69+
70+
def __init__(self, comobj: "ctypes._Pointer[automation.IDispatch]"):
6271
self.__dict__["_comobj"] = comobj
63-
self.__dict__[
64-
"_ids"
65-
] = {} # Tiny optimization: trying not to use GetIDsOfNames more than once
72+
# Tiny optimization: trying not to use GetIDsOfNames more than once
73+
self.__dict__["_ids"] = {}
6674
self.__dict__["_methods"] = set()
6775

68-
def __enum(self):
69-
e = self._comobj.Invoke(-4) # DISPID_NEWENUM
76+
def __enum(self) -> automation.IEnumVARIANT:
77+
e: IUnknown = self._comobj.Invoke(-4) # DISPID_NEWENUM
7078
return e.QueryInterface(automation.IEnumVARIANT)
7179

72-
def __hash__(self):
80+
def __hash__(self) -> int:
7381
return hash(self._comobj)
7482

75-
def __getitem__(self, index):
83+
def __getitem__(self, index: Any) -> Any:
7684
enum = self.__enum()
7785
if index > 0:
7886
if 0 != enum.Skip(index):
@@ -82,11 +90,13 @@ def __getitem__(self, index):
8290
raise IndexError("index out of range")
8391
return item
8492

85-
def QueryInterface(self, interface, iid=None):
93+
def QueryInterface(
94+
self, interface: Type[_T_IUnknown], iid: Optional[GUID] = None
95+
) -> _T_IUnknown:
8696
"""QueryInterface is forwarded to the real com object."""
8797
return self._comobj.QueryInterface(interface, iid)
8898

89-
def _FlagAsMethod(self, *names):
99+
def _FlagAsMethod(self, *names: str) -> None:
90100
"""Flag these attribute names as being methods.
91101
Some objects do not correctly differentiate methods and
92102
properties, leading to problems when calling these methods.
@@ -100,7 +110,7 @@ def _FlagAsMethod(self, *names):
100110
"""
101111
self._methods.update(names)
102112

103-
def __getattr__(self, name):
113+
def __getattr__(self, name: str) -> Any:
104114
if name.startswith("__") and name.endswith("__"):
105115
raise AttributeError(name)
106116
# tc = self._comobj.GetTypeInfo(0).QueryInterface(comtypes.typeinfo.ITypeComp)
@@ -119,20 +129,16 @@ def __getattr__(self, name):
119129
try:
120130
result = self._comobj.Invoke(dispid, _invkind=flags)
121131
except COMError as err:
122-
(hresult, text, details) = err.args
132+
(hresult, _, _) = err.args
123133
if hresult in ERRORS_BAD_CONTEXT:
124134
result = MethodCaller(dispid, self)
125135
self.__dict__[name] = result
126136
else:
127-
# The line break is important for 2to3 to work correctly
128-
raise
129-
except:
130-
# The line break is important for 2to3 to work correctly
131-
raise
137+
raise err
132138

133139
return result
134140

135-
def __setattr__(self, name, value):
141+
def __setattr__(self, name: str, value: Any) -> None:
136142
dispid = self._ids.get(name)
137143
if not dispid:
138144
dispid = self._comobj.GetIDsOfNames(name)[0]
@@ -142,7 +148,7 @@ def __setattr__(self, name, value):
142148
flags = 8 if _is_object(value) else 4
143149
return self._comobj.Invoke(dispid, value, _invkind=flags)
144150

145-
def __iter__(self):
151+
def __iter__(self) -> "_Collection":
146152
return _Collection(self.__enum())
147153

148154
# def __setitem__(self, index, value):
@@ -156,10 +162,10 @@ def __iter__(self):
156162

157163

158164
class _Collection(object):
159-
def __init__(self, enum):
165+
def __init__(self, enum: automation.IEnumVARIANT):
160166
self.enum = enum
161167

162-
def __next__(self):
168+
def __next__(self) -> Any:
163169
item, fetched = self.enum.Next(1)
164170
if fetched:
165171
return item

0 commit comments

Comments
 (0)