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.
- {comtypes-1.1.14 → comtypes-1.2.1}/CHANGES.txt +37 -0
- comtypes-1.2.1/PKG-INFO +79 -0
- comtypes-1.2.1/README.md +59 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/__init__.py +302 -555
- comtypes-1.2.1/comtypes/_memberspec.py +520 -0
- comtypes-1.2.1/comtypes/_npsupport.py +143 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/automation.py +99 -11
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/__init__.py +80 -26
- comtypes-1.2.1/comtypes/client/_generate.py +274 -0
- comtypes-1.2.1/comtypes/hints.pyi +26 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/persist.py +14 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/safearray.py +22 -21
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/__init__.py +0 -7
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_client.py +35 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dict.py +0 -4
- comtypes-1.2.1/comtypes/test/test_npsupport.py +343 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_safearray.py +2 -235
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_variant.py +6 -59
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/codegenerator.py +454 -337
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/tlbparser.py +56 -75
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/typedesc.py +31 -3
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/typedesc_base.py +28 -1
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/typeinfo.py +291 -121
- comtypes-1.2.1/comtypes.egg-info/PKG-INFO +79 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/SOURCES.txt +4 -1
- {comtypes-1.1.14 → comtypes-1.2.1}/setup.cfg +0 -1
- {comtypes-1.1.14 → comtypes-1.2.1}/setup.py +15 -8
- comtypes-1.1.14/PKG-INFO +0 -50
- comtypes-1.1.14/README.md +0 -31
- comtypes-1.1.14/comtypes/client/_generate.py +0 -257
- comtypes-1.1.14/comtypes/npsupport.py +0 -125
- comtypes-1.1.14/comtypes.egg-info/PKG-INFO +0 -50
- {comtypes-1.1.14 → comtypes-1.2.1}/LICENSE.txt +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/MANIFEST.in +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/clear_comtypes_cache.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/GUID.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_comobject.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_meta.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_safearray.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_code_cache.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_constants.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_events.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/dynamic.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/lazybind.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/connectionpoints.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/errorinfo.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/git.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/hresult.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/logutil.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/messageloop.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/patcher.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/__init__.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/automation.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/connectionpoints.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/inprocserver.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/localserver.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/register.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/w_getopt.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/shelllink.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/find_memleak.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/runtests.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/setup.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_BSTR.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_GUID.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_QueryService.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_agilent.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_avmc.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_basic.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_casesensitivity.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_collections.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_comserver.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_createwrappers.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dispinterface.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dyndispatch.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_excel.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_findgendir.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_getactiveobj.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_ie.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_msscript.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_outparam.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_propputref.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_sapi.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_server.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_showevents.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_subinterface.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_typeinfo.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_urlhistory.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_win32com_interop.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_wmi.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_word.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/util.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/viewobject.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/dependency_links.txt +0 -0
- {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"]
|