comtypes 1.1.14__zip → 1.2.1__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. {comtypes-1.1.14 → comtypes-1.2.1}/CHANGES.txt +37 -0
  2. comtypes-1.2.1/PKG-INFO +79 -0
  3. comtypes-1.2.1/README.md +59 -0
  4. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/__init__.py +302 -555
  5. comtypes-1.2.1/comtypes/_memberspec.py +520 -0
  6. comtypes-1.2.1/comtypes/_npsupport.py +143 -0
  7. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/automation.py +99 -11
  8. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/__init__.py +80 -26
  9. comtypes-1.2.1/comtypes/client/_generate.py +274 -0
  10. comtypes-1.2.1/comtypes/hints.pyi +26 -0
  11. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/persist.py +14 -0
  12. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/safearray.py +22 -21
  13. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/__init__.py +0 -7
  14. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_client.py +35 -0
  15. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dict.py +0 -4
  16. comtypes-1.2.1/comtypes/test/test_npsupport.py +343 -0
  17. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_safearray.py +2 -235
  18. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_variant.py +6 -59
  19. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/codegenerator.py +454 -337
  20. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/tlbparser.py +56 -75
  21. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/typedesc.py +31 -3
  22. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/typedesc_base.py +28 -1
  23. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/typeinfo.py +291 -121
  24. comtypes-1.2.1/comtypes.egg-info/PKG-INFO +79 -0
  25. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/SOURCES.txt +4 -1
  26. {comtypes-1.1.14 → comtypes-1.2.1}/setup.cfg +0 -1
  27. {comtypes-1.1.14 → comtypes-1.2.1}/setup.py +15 -8
  28. comtypes-1.1.14/PKG-INFO +0 -50
  29. comtypes-1.1.14/README.md +0 -31
  30. comtypes-1.1.14/comtypes/client/_generate.py +0 -257
  31. comtypes-1.1.14/comtypes/npsupport.py +0 -125
  32. comtypes-1.1.14/comtypes.egg-info/PKG-INFO +0 -50
  33. {comtypes-1.1.14 → comtypes-1.2.1}/LICENSE.txt +0 -0
  34. {comtypes-1.1.14 → comtypes-1.2.1}/MANIFEST.in +0 -0
  35. {comtypes-1.1.14 → comtypes-1.2.1}/clear_comtypes_cache.py +0 -0
  36. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/GUID.py +0 -0
  37. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_comobject.py +0 -0
  38. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_meta.py +0 -0
  39. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_safearray.py +0 -0
  40. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_code_cache.py +0 -0
  41. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_constants.py +0 -0
  42. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_events.py +0 -0
  43. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/dynamic.py +0 -0
  44. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/lazybind.py +0 -0
  45. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/connectionpoints.py +0 -0
  46. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/errorinfo.py +0 -0
  47. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/git.py +0 -0
  48. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/hresult.py +0 -0
  49. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/logutil.py +0 -0
  50. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/messageloop.py +0 -0
  51. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/patcher.py +0 -0
  52. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/__init__.py +0 -0
  53. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/automation.py +0 -0
  54. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/connectionpoints.py +0 -0
  55. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/inprocserver.py +0 -0
  56. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/localserver.py +0 -0
  57. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/register.py +0 -0
  58. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/w_getopt.py +0 -0
  59. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/shelllink.py +0 -0
  60. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.idl +0 -0
  61. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.py +0 -0
  62. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.tlb +0 -0
  63. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.idl +0 -0
  64. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.py +0 -0
  65. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.tlb +0 -0
  66. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/find_memleak.py +0 -0
  67. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/mylib.idl +0 -0
  68. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/mytypelib.idl +0 -0
  69. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/runtests.py +0 -0
  70. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/setup.py +0 -0
  71. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_BSTR.py +0 -0
  72. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_DISPPARAMS.py +0 -0
  73. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_GUID.py +0 -0
  74. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_QueryService.py +0 -0
  75. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_agilent.py +0 -0
  76. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_avmc.py +0 -0
  77. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_basic.py +0 -0
  78. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_casesensitivity.py +0 -0
  79. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_collections.py +0 -0
  80. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_comserver.py +0 -0
  81. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_createwrappers.py +0 -0
  82. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dispinterface.py +0 -0
  83. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dyndispatch.py +0 -0
  84. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_excel.py +0 -0
  85. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_findgendir.py +0 -0
  86. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_getactiveobj.py +0 -0
  87. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_ie.py +0 -0
  88. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_jscript.js +0 -0
  89. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_msscript.py +0 -0
  90. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_outparam.py +0 -0
  91. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_propputref.py +0 -0
  92. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_pump_events.py +0 -0
  93. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_sapi.py +0 -0
  94. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_server.py +0 -0
  95. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_showevents.py +0 -0
  96. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_subinterface.py +0 -0
  97. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_typeinfo.py +0 -0
  98. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_urlhistory.py +0 -0
  99. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_win32com_interop.py +0 -0
  100. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_wmi.py +0 -0
  101. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_word.py +0 -0
  102. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/__init__.py +0 -0
  103. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/util.py +0 -0
  104. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/viewobject.py +0 -0
  105. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/dependency_links.txt +0 -0
  106. {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/top_level.txt +0 -0
@@ -0,0 +1,520 @@
1
+ import ctypes
2
+
3
+ import comtypes
4
+ from comtypes import TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from comtypes import _CData
8
+ from typing import (
9
+ Any, Callable, Dict, Iterator, List, Optional, Tuple, Type, Union as _UnionT
10
+ )
11
+ PositionalParamFlagType = Tuple[int, Optional[str]]
12
+ OptionalParamFlagType = Tuple[int, Optional[str], Any]
13
+ ParamFlagType = _UnionT[PositionalParamFlagType, OptionalParamFlagType]
14
+ PositionalArgSpecElmType = Tuple[List[str], Type[_CData], str]
15
+ OptionalArgSpecElmType = Tuple[List[str], Type[_CData], str, Any]
16
+ ArgSpecElmType = _UnionT[PositionalArgSpecElmType, OptionalArgSpecElmType]
17
+
18
+
19
+ _PARAMFLAGS = {
20
+ "in": 1,
21
+ "out": 2,
22
+ "lcid": 4,
23
+ "retval": 8,
24
+ "optional": 16,
25
+ }
26
+
27
+
28
+ def _encode_idl(names):
29
+ # sum up all values found in _PARAMFLAGS, ignoring all others.
30
+ return sum([_PARAMFLAGS.get(n, 0) for n in names])
31
+
32
+
33
+ _NOTHING = object()
34
+
35
+
36
+ def _unpack_argspec(idl, typ, name=None, defval=_NOTHING):
37
+ # type: (List[str], Type[_CData], Optional[str], Any) -> Tuple[List[str], Type[_CData], Optional[str], Any]
38
+ return idl, typ, name, defval
39
+
40
+
41
+ def _resolve_argspec(items):
42
+ # type: (Tuple[ArgSpecElmType, ...]) -> Tuple[Tuple[ParamFlagType, ...], Tuple[Type[_CData], ...]]
43
+ """Unpacks and converts from argspec to paramflags and argtypes.
44
+
45
+ - paramflags is a sequence of `(pflags: int, argname: str, | None[, defval: Any])`.
46
+ - argtypes is a sequence of `type[_CData]`.
47
+ """
48
+ from comtypes.automation import VARIANT
49
+
50
+ paramflags = []
51
+ argtypes = []
52
+ for item in items:
53
+ idl, typ, argname, defval = _unpack_argspec(*item) # type: ignore
54
+ pflags = _encode_idl(idl)
55
+ if "optional" in idl:
56
+ if defval is _NOTHING:
57
+ if typ is VARIANT:
58
+ defval = VARIANT.missing
59
+ elif typ is ctypes.POINTER(VARIANT):
60
+ defval = ctypes.pointer(VARIANT.missing)
61
+ else:
62
+ # msg = ("'optional' only allowed for VARIANT and VARIANT*, not for %s" % typ.__name__)
63
+ # warnings.warn(msg, IDLWarning, stacklevel=2)
64
+ defval = typ()
65
+ if defval is _NOTHING:
66
+ paramflags.append((pflags, argname))
67
+ else:
68
+ paramflags.append((pflags, argname, defval))
69
+ argtypes.append(typ)
70
+ return tuple(paramflags), tuple(argtypes)
71
+
72
+
73
+ class _MemberSpec(object):
74
+ """Specifier of a slot of method or property."""
75
+ __slots__ = ("name", "idlflags", "restype")
76
+ def __init__(self, name, idlflags, restype):
77
+ self.name = name # type: str
78
+ self.idlflags = idlflags # type: Tuple[_UnionT[str, int], ...]
79
+ self.restype = restype # type: Optional[Type[_CData]]
80
+
81
+ def is_prop(self):
82
+ # type: () -> bool
83
+ propflags = ("propget", "propput", "propputref")
84
+ return any(f in propflags for f in self.idlflags)
85
+
86
+
87
+ class _ComMemberSpec(_MemberSpec):
88
+ """Specifier for a slot of COM method or property."""
89
+ __slots__ = ("argtypes", "paramflags", "doc")
90
+
91
+ def __init__(self, restype, name, argtypes, paramflags, idlflags, doc):
92
+ self.argtypes = argtypes # type: Tuple[Type[_CData], ...]
93
+ self.paramflags = paramflags # type: Optional[Tuple[ParamFlagType, ...]]
94
+ self.doc = doc # type: Optional[str]
95
+ super(_ComMemberSpec, self).__init__(name, idlflags, restype)
96
+
97
+ def __iter__(self):
98
+ # for backward compatibility:
99
+ # A function that returns this object used to return a `tuple`.
100
+ # So it is implemented as unpackable as well.
101
+ for item in (self.restype, self.name, self.argtypes, self.paramflags, self.idlflags, self.doc):
102
+ yield item
103
+
104
+
105
+ class _DispMemberSpec(_MemberSpec):
106
+ """Specifier for a slot of dispinterface method or property."""
107
+ __slots__ = ("what", "argspec")
108
+
109
+ def __init__(self, what, name, idlflags, restype, argspec):
110
+ self.what = what # type: str
111
+ self.argspec = argspec # type: Tuple[ArgSpecElmType, ...]
112
+ super(_DispMemberSpec, self).__init__(name, idlflags, restype)
113
+
114
+ @property
115
+ def memid(self):
116
+ # type: () -> int
117
+ try:
118
+ return [x for x in self.idlflags if isinstance(x, int)][0]
119
+ except IndexError:
120
+ raise TypeError("no dispid found in idlflags")
121
+
122
+ def __iter__(self):
123
+ # for backward compatibility:
124
+ # A function that returns this object used to return a `tuple`.
125
+ # So it is implemented as unpackable as well.
126
+ for item in (self.what, self.name, self.idlflags, self.restype, self.argspec):
127
+ yield item
128
+
129
+
130
+ def _fix_inout_args(func, argtypes, paramflags):
131
+ # type: (Callable[..., Any], Tuple[Type[_CData], ...], Tuple[ParamFlagType, ...]) -> Callable[..., Any]
132
+ """This function provides a workaround for a bug in `ctypes`.
133
+
134
+ [in, out] parameters must be converted with the argtype's `from_param`
135
+ method BEFORE they are passed to the `_ctypes.build_callargs` function
136
+ in `Modules/_ctypes/_ctypes.c`.
137
+ """
138
+ # For details see below.
139
+ #
140
+ # TODO: The workaround should be disabled when a ctypes
141
+ # version is used where the bug is fixed.
142
+ SIMPLETYPE = type(ctypes.c_int)
143
+ BYREFTYPE = type(ctypes.byref(ctypes.c_int()))
144
+ def call_with_inout(self, *args, **kw):
145
+ args = list(args)
146
+ # Indexed by order in the output
147
+ outargs = {}
148
+ outnum = 0
149
+ for i, info in enumerate(paramflags):
150
+ direction = info[0]
151
+ if direction & 3 == 3:
152
+ # This is an [in, out] parameter.
153
+ #
154
+ # Determine name and required type of the parameter.
155
+ name = info[1]
156
+ # [in, out] parameters are passed as pointers,
157
+ # this is the pointed-to type:
158
+ atyp = argtypes[i]._type_
159
+
160
+ # Get the actual parameter, either as positional or
161
+ # keyword arg.
162
+ try:
163
+ try:
164
+ v = args[i]
165
+ except IndexError:
166
+ v = kw[name]
167
+ except KeyError:
168
+ # no parameter was passed, make an empty one
169
+ # of the required type
170
+ v = atyp()
171
+ else:
172
+ # parameter was passed, call .from_param() to
173
+ # convert it to a ctypes type.
174
+ if getattr(v, "_type_", None) is atyp:
175
+ # Array of or pointer to type 'atyp' was
176
+ # passed, pointer to 'atyp' expected.
177
+ pass
178
+ elif type(atyp) is SIMPLETYPE:
179
+ # The from_param method of simple types
180
+ # (c_int, c_double, ...) returns a byref()
181
+ # object which we cannot use since later
182
+ # it will be wrapped in a pointer. Simply
183
+ # call the constructor with the argument
184
+ # in that case.
185
+ v = atyp(v)
186
+ else:
187
+ v = atyp.from_param(v)
188
+ assert not isinstance(v, BYREFTYPE)
189
+ outargs[outnum] = v
190
+ outnum += 1
191
+ if len(args) > i:
192
+ args[i] = v
193
+ else:
194
+ kw[name] = v
195
+ elif direction & 2 == 2:
196
+ outnum += 1
197
+ rescode = func(self, *args, **kw)
198
+ # If there is only a single output value, then do not expect it to
199
+ # be iterable.
200
+ if outnum == 1: # rescode is not iterable
201
+ if len(outargs) == 1:
202
+ rescode = rescode.__ctypes_from_outparam__()
203
+ return rescode
204
+ rescode = list(rescode)
205
+ for outnum, o in outargs.items():
206
+ rescode[outnum] = o.__ctypes_from_outparam__()
207
+ return rescode
208
+ return call_with_inout
209
+
210
+
211
+ class PropertyMapping(object):
212
+ def __init__(self):
213
+ self._data = {} # type: Dict[Tuple[str, Optional[str], int], List[Optional[Callable[..., Any]]]]
214
+
215
+ def add_propget(self, name, doc, nargs, func):
216
+ # type: (str, Optional[str], int, Callable[..., Any]) -> None
217
+ self._data.setdefault((name, doc, nargs), [None, None, None])[0] = func
218
+
219
+ def add_propput(self, name, doc, nargs, func):
220
+ # type: (str, Optional[str], int, Callable[..., Any]) -> None
221
+ self._data.setdefault((name, doc, nargs), [None, None, None])[1] = func
222
+
223
+ def add_propputref(self, name, doc, nargs, func):
224
+ # type: (str, Optional[str], int, Callable[..., Any]) -> None
225
+ self._data.setdefault((name, doc, nargs), [None, None, None])[2] = func
226
+
227
+ def __iter__(self):
228
+ # type: () -> Iterator[Tuple[str, Optional[str], int, Optional[Callable[..., Any]], Optional[Callable[..., Any]]]]
229
+ for (name, doc, nargs), (fget, propput, propputref) in self._data.items():
230
+ if propput is not None and propputref is not None:
231
+ # Create a setter method that examines the argument type
232
+ # and calls 'propputref' if it is an Object (in the VB
233
+ # sense), or call 'propput' otherwise.
234
+ put, putref = propput, propputref
235
+ def put_or_putref(self, *args):
236
+ if comtypes._is_object(args[-1]):
237
+ return putref(self, *args)
238
+ return put(self, *args)
239
+ fset = put_or_putref
240
+ elif propputref is not None:
241
+ fset = propputref
242
+ else:
243
+ fset = propput
244
+ yield (name, doc, nargs, fget, fset)
245
+
246
+
247
+ class PropertyGenerator(object):
248
+ def __init__(self, cls_name):
249
+ # type: (str) -> None
250
+ self._mapping = PropertyMapping()
251
+ self._cls_name = cls_name
252
+
253
+ def add(self, m, func):
254
+ # type: (_MemberSpec, Callable[..., Any]) -> None
255
+ """Adds member spec and func to mapping."""
256
+ if "propget" in m.idlflags:
257
+ name, doc, nargs = self.to_propget_keys(m)
258
+ self._mapping.add_propget(name, doc, nargs, func)
259
+ elif "propput" in m.idlflags:
260
+ name, doc, nargs = self.to_propput_keys(m)
261
+ self._mapping.add_propput(name, doc, nargs, func)
262
+ elif "propputref" in m.idlflags:
263
+ name, doc, nargs = self.to_propputref_keys(m)
264
+ self._mapping.add_propputref(name, doc, nargs, func)
265
+ else:
266
+ raise TypeError("no propflag found in idlflags")
267
+
268
+ # The following code assumes that the docstrings for
269
+ # propget and propput are identical.
270
+ def __iter__(self):
271
+ # type: () -> Iterator[Tuple[str, _UnionT[property, named_property]]]
272
+ for name, doc, nargs, fget, fset in self._mapping:
273
+ if nargs == 0:
274
+ prop = property(fget, fset, None, doc)
275
+ else:
276
+ # Hm, must be a descriptor where the __get__ method
277
+ # returns a bound object having __getitem__ and
278
+ # __setitem__ methods.
279
+ prop = named_property("%s.%s" % (self._cls_name, name), fget, fset, doc)
280
+ yield (name, prop)
281
+
282
+ def to_propget_keys(self, m):
283
+ # type: (_MemberSpec) -> Tuple[str, Optional[str], int]
284
+ raise NotImplementedError
285
+
286
+ def to_propput_keys(self, m):
287
+ # type: (_MemberSpec) -> Tuple[str, Optional[str], int]
288
+ raise NotImplementedError
289
+
290
+ def to_propputref_keys(self, m):
291
+ # type: (_MemberSpec) -> Tuple[str, Optional[str], int]
292
+ raise NotImplementedError
293
+
294
+
295
+ class ComPropertyGenerator(PropertyGenerator):
296
+ # XXX Hm. What, when paramflags is None?
297
+ # Or does have '0' values?
298
+ # Seems we loose then, at least for properties...
299
+ def to_propget_keys(self, m):
300
+ # type: (_ComMemberSpec) -> Tuple[str, Optional[str], int]
301
+ assert m.name.startswith("_get_")
302
+ assert m.paramflags is not None
303
+ nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)])
304
+ # XXX or should we do this?
305
+ # nargs = len([f for f in paramflags if (f[0] & 1) or (f[0] == 0)])
306
+ return m.name[len("_get_"):], m.doc, nargs
307
+
308
+ def to_propput_keys(self, m):
309
+ # type: (_ComMemberSpec) -> Tuple[str, Optional[str], int]
310
+ assert m.name.startswith("_set_")
311
+ assert m.paramflags is not None
312
+ nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)]) - 1
313
+ return m.name[len("_set_"):], m.doc, nargs
314
+
315
+ def to_propputref_keys(self, m):
316
+ # type: (_ComMemberSpec) -> Tuple[str, Optional[str], int]
317
+ assert m.name.startswith("_setref_")
318
+ assert m.paramflags is not None
319
+ nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)]) - 1
320
+ return m.name[len("_setref_"):], m.doc, nargs
321
+
322
+
323
+ class DispPropertyGenerator(PropertyGenerator):
324
+ def to_propget_keys(self, m):
325
+ # type: (_DispMemberSpec) -> Tuple[str, Optional[str], int]
326
+ return m.name, None, len(m.argspec)
327
+
328
+ def to_propput_keys(self, m):
329
+ # type: (_DispMemberSpec) -> Tuple[str, Optional[str], int]
330
+ return m.name, None, len(m.argspec) - 1
331
+
332
+ def to_propputref_keys(self, m):
333
+ # type: (_DispMemberSpec) -> Tuple[str, Optional[str], int]
334
+ return m.name, None, len(m.argspec) - 1
335
+
336
+
337
+ class ComMemberGenerator(object):
338
+ def __init__(self, cls_name, vtbl_offset, iid):
339
+ # type: (str, int, comtypes.GUID) -> None
340
+ self._vtbl_offset = vtbl_offset
341
+ self._iid = iid
342
+ self._props = ComPropertyGenerator(cls_name)
343
+ # sequence of (name: str, func: Callable, raw_func: Callable, is_prop: bool)
344
+ self._mths = [] # type: List[Tuple[str, Callable[..., Any], Callable[..., Any], bool]]
345
+ self._member_index = 0
346
+
347
+ def add(self, m):
348
+ # type: (_ComMemberSpec) -> None
349
+ proto = ctypes.WINFUNCTYPE(m.restype, *m.argtypes)
350
+ # a low level unbound method calling the com method.
351
+ # attach it with a private name (__com_AddRef, for example),
352
+ # so that custom method implementations can call it.
353
+ vidx = self._member_index + self._vtbl_offset
354
+ # If the method returns a HRESULT, we pass the interface iid,
355
+ # so that we can request error info for the interface.
356
+ iid = self._iid if m.restype == ctypes.HRESULT else None
357
+ raw_func = proto(vidx, m.name, None, iid) # low level
358
+ func = self._fix_args(m, proto(vidx, m.name, m.paramflags, iid)) # high level
359
+ func.__doc__ = m.doc
360
+ func.__name__ = m.name # for pyhelp
361
+ is_prop = m.is_prop()
362
+ if is_prop:
363
+ self._props.add(m, func)
364
+ self._mths.append((m.name, func, raw_func, is_prop))
365
+ self._member_index += 1
366
+
367
+ def _fix_args(self, m, func):
368
+ # type: (_ComMemberSpec, Callable[..., Any]) -> Callable[..., Any]
369
+ """This is a workaround. See `_fix_inout_args` docstring and comments."""
370
+ if m.paramflags:
371
+ dirflags = [(p[0]&3) for p in m.paramflags]
372
+ if 3 in dirflags:
373
+ return _fix_inout_args(func, m.argtypes, m.paramflags)
374
+ return func
375
+
376
+ def methods(self):
377
+ return iter(self._mths)
378
+
379
+ def properties(self):
380
+ return iter(self._props)
381
+
382
+
383
+ class DispMemberGenerator(object):
384
+ def __init__(self, cls_name):
385
+ # type: (str) -> None
386
+ self._props = DispPropertyGenerator(cls_name)
387
+ # sequence of (name: str, func_or_prop: Callable | property, is_prop: bool)
388
+ self._items = [] # type: List[Tuple[str, _UnionT[Callable[..., Any], property], bool]]
389
+
390
+ def add(self, m):
391
+ # type: (_DispMemberSpec) -> None
392
+ if m.what == "DISPPROPERTY": # DISPPROPERTY
393
+ assert not m.argspec # XXX does not yet work for properties with parameters
394
+ is_prop = True
395
+ accessor = self._make_disp_property(m)
396
+ self._items.append((m.name, accessor, is_prop))
397
+ else: # DISPMETHOD
398
+ func = self._make_disp_method(m)
399
+ func.__name__ = m.name
400
+ is_prop = m.is_prop()
401
+ if is_prop:
402
+ self._props.add(m, func)
403
+ else:
404
+ self._items.append((m.name, func, is_prop))
405
+
406
+ def _make_disp_property(self, m):
407
+ # type: (_DispMemberSpec) -> property
408
+ # XXX doc string missing in property
409
+ memid = m.memid
410
+ def fget(obj):
411
+ return obj.Invoke(memid, _invkind=2) # DISPATCH_PROPERTYGET
412
+ if "readonly" in m.idlflags:
413
+ return property(fget)
414
+ def fset(obj, value):
415
+ # Detect whether to use DISPATCH_PROPERTYPUT or
416
+ # DISPATCH_PROPERTYPUTREF
417
+ invkind = 8 if comtypes._is_object(value) else 4
418
+ return obj.Invoke(memid, value, _invkind=invkind)
419
+ return property(fget, fset)
420
+
421
+ # Should the funcs/mths we create have restype and/or argtypes attributes?
422
+ def _make_disp_method(self, m):
423
+ # type: (_DispMemberSpec) -> Callable[..., Any]
424
+ memid = m.memid
425
+ if "propget" in m.idlflags:
426
+ def getfunc(obj, *args, **kw):
427
+ return obj.Invoke(memid, _invkind=2, *args, **kw) # DISPATCH_PROPERTYGET
428
+ return getfunc
429
+ elif "propput" in m.idlflags:
430
+ def putfunc(obj, *args, **kw):
431
+ return obj.Invoke(memid, _invkind=4, *args, **kw) # DISPATCH_PROPERTYPUT
432
+ return putfunc
433
+ elif "propputref" in m.idlflags:
434
+ def putreffunc(obj, *args, **kw):
435
+ return obj.Invoke(memid, _invkind=8, *args, **kw) # DISPATCH_PROPERTYPUTREF
436
+ return putreffunc
437
+ # a first attempt to make use of the restype. Still, support for
438
+ # named arguments and default argument values should be added.
439
+ if hasattr(m.restype, "__com_interface__"):
440
+ interface = m.restype.__com_interface__ # type: ignore
441
+ def comitffunc(obj, *args, **kw):
442
+ result = obj.Invoke(memid, _invkind=1, *args, **kw)
443
+ if result is None:
444
+ return
445
+ return result.QueryInterface(interface)
446
+ return comitffunc
447
+ def func(obj, *args, **kw):
448
+ return obj.Invoke(memid, _invkind=1, *args, **kw) # DISPATCH_METHOD
449
+ return func
450
+
451
+ def items(self):
452
+ return iter(self._items)
453
+
454
+ def properties(self):
455
+ return iter(self._props)
456
+
457
+
458
+ ################################################################
459
+ # helper classes for COM propget / propput
460
+ # Should they be implemented in C for speed?
461
+
462
+ class bound_named_property(object):
463
+ def __init__(self, name, fget, fset, instance):
464
+ self.name = name
465
+ self.instance = instance
466
+ self.fget = fget
467
+ self.fset = fset
468
+
469
+ def __getitem__(self, index):
470
+ if self.fget is None:
471
+ raise TypeError("unsubscriptable object")
472
+ if isinstance(index, tuple):
473
+ return self.fget(self.instance, *index)
474
+ elif index == comtypes._all_slice:
475
+ return self.fget(self.instance)
476
+ else:
477
+ return self.fget(self.instance, index)
478
+
479
+ def __call__(self, *args):
480
+ if self.fget is None:
481
+ raise TypeError("object is not callable")
482
+ return self.fget(self.instance, *args)
483
+
484
+ def __setitem__(self, index, value):
485
+ if self.fset is None:
486
+ raise TypeError("object does not support item assignment")
487
+ if isinstance(index, tuple):
488
+ self.fset(self.instance, *(index + (value,)))
489
+ elif index == comtypes._all_slice:
490
+ self.fset(self.instance, value)
491
+ else:
492
+ self.fset(self.instance, index, value)
493
+
494
+ def __repr__(self):
495
+ return "<bound_named_property %r at %x>" % (self.name, id(self))
496
+
497
+ def __iter__(self):
498
+ """ Explicitly disallow iteration. """
499
+ msg = "%r is not iterable" % self.name
500
+ raise TypeError(msg)
501
+
502
+
503
+ class named_property(object):
504
+ def __init__(self, name, fget=None, fset=None, doc=None):
505
+ self.name = name
506
+ self.fget = fget
507
+ self.fset = fset
508
+ self.__doc__ = doc
509
+
510
+ def __get__(self, instance, owner=None):
511
+ if instance is None:
512
+ return self
513
+ return bound_named_property(self.name, self.fget, self.fset, instance)
514
+
515
+ # Make this a data descriptor
516
+ def __set__(self, instance):
517
+ raise AttributeError("Unsettable attribute")
518
+
519
+ def __repr__(self):
520
+ return "<named_property %r at %x>" % (self.name, id(self))
@@ -0,0 +1,143 @@
1
+ """ Consolidation of numpy support utilities. """
2
+ import sys
3
+
4
+ is_64bits = sys.maxsize > 2**32
5
+
6
+
7
+ class Interop:
8
+ """ Class encapsulating all the functionality necessary to allow interop of
9
+ comtypes with numpy. Needs to be enabled with the "enable()" method.
10
+ """
11
+ def __init__(self):
12
+ self.enabled = False
13
+ self.VARIANT_dtype = None
14
+ self.typecodes = {}
15
+ self.datetime64 = None
16
+ self.com_null_date64 = None
17
+
18
+ def _make_variant_dtype(self):
19
+ """ Create a dtype for VARIANT. This requires support for Unions, which
20
+ is available in numpy version 1.7 or greater.
21
+
22
+ This does not support the decimal type.
23
+
24
+ Returns None if the dtype cannot be created.
25
+ """
26
+ if not self.enabled:
27
+ return None
28
+ # pointer typecode
29
+ ptr_typecode = '<u8' if is_64bits else '<u4'
30
+
31
+ _tagBRECORD_format = [
32
+ ('pvRecord', ptr_typecode),
33
+ ('pRecInfo', ptr_typecode),
34
+ ]
35
+
36
+ # overlapping typecodes only allowed in numpy version 1.7 or greater
37
+ U_VARIANT_format = dict(
38
+ names=[
39
+ 'VT_BOOL', 'VT_I1', 'VT_I2', 'VT_I4', 'VT_I8', 'VT_INT',
40
+ 'VT_UI1', 'VT_UI2', 'VT_UI4', 'VT_UI8', 'VT_UINT', 'VT_R4',
41
+ 'VT_R8', 'VT_CY', 'c_wchar_p', 'c_void_p', 'pparray',
42
+ 'bstrVal', '_tagBRECORD',
43
+ ],
44
+ formats=[
45
+ '<i2', '<i1', '<i2', '<i4', '<i8', '<i4', '<u1', '<u2', '<u4',
46
+ '<u8', '<u4', '<f4', '<f8', '<i8', ptr_typecode, ptr_typecode,
47
+ ptr_typecode, ptr_typecode, _tagBRECORD_format,
48
+ ],
49
+ offsets=[0] * 19 # This is what makes it a union
50
+ )
51
+
52
+ tagVARIANT_format = [
53
+ ("vt", '<u2'),
54
+ ("wReserved1", '<u2'),
55
+ ("wReserved2", '<u2'),
56
+ ("wReserved3", '<u2'),
57
+ ("_", U_VARIANT_format),
58
+ ]
59
+
60
+ return self.numpy.dtype(tagVARIANT_format)
61
+
62
+ def _check_ctypeslib_typecodes(self):
63
+ if not self.enabled:
64
+ return {}
65
+ import numpy as np
66
+ from numpy import ctypeslib
67
+ try:
68
+ from numpy.ctypeslib import _typecodes
69
+ except ImportError:
70
+ from numpy.ctypeslib import as_ctypes_type
71
+
72
+ dtypes_to_ctypes = {}
73
+
74
+ for tp in set(np.sctypeDict.values()):
75
+ try:
76
+ ctype_for = as_ctypes_type(tp)
77
+ dtypes_to_ctypes[np.dtype(tp).str] = ctype_for
78
+ except NotImplementedError:
79
+ continue
80
+ ctypeslib._typecodes = dtypes_to_ctypes
81
+ return ctypeslib._typecodes
82
+
83
+ def isndarray(self, value):
84
+ """ Check if a value is an ndarray.
85
+
86
+ This cannot succeed if numpy is not available.
87
+
88
+ """
89
+ if not self.enabled:
90
+ if hasattr(value, "__array_interface__"):
91
+ raise ValueError(
92
+ (
93
+ "Argument {0} appears to be a numpy.ndarray, but "
94
+ "comtypes numpy support has not been enabled. Please "
95
+ "try calling comtypes.npsupport.enable_numpy_interop()"
96
+ " before passing ndarrays as parameters."
97
+ ).format(value)
98
+ )
99
+ return False
100
+
101
+ return isinstance(value, self.numpy.ndarray)
102
+
103
+ def isdatetime64(self, value):
104
+ """ Check if a value is a datetime64.
105
+
106
+ This cannot succeed if datetime64 is not available.
107
+
108
+ """
109
+ if not self.enabled:
110
+ return False
111
+ return isinstance(value, self.numpy.datetime64)
112
+
113
+ @property
114
+ def numpy(self):
115
+ """ The numpy package.
116
+ """
117
+ if self.enabled:
118
+ import numpy
119
+ return numpy
120
+ raise ImportError(
121
+ "In comtypes>=1.2.0 numpy interop must be explicitly enabled with "
122
+ "comtypes.npsupport.enable_numpy_interop before attempting to use "
123
+ "numpy features."
124
+ )
125
+
126
+ def enable(self):
127
+ """ Enables numpy/comtypes interop.
128
+ """
129
+ # don't do this twice
130
+ if self.enabled:
131
+ return
132
+ # first we have to be able to import numpy
133
+ import numpy
134
+ # if that succeeded we can be enabled
135
+ self.enabled = True
136
+ self.VARIANT_dtype = self._make_variant_dtype()
137
+ self.typecodes = self._check_ctypeslib_typecodes()
138
+ self.com_null_date64 = self.numpy.datetime64("1899-12-30T00:00:00", "ns")
139
+
140
+
141
+ interop = Interop()
142
+
143
+ __all__ = ["interop"]