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,274 @@
1
+ from __future__ import print_function
2
+ import ctypes
3
+ import importlib
4
+ import logging
5
+ import os
6
+ import sys
7
+ import types
8
+ if sys.version_info >= (3, 0):
9
+ base_text_type = str
10
+ import winreg
11
+ else:
12
+ base_text_type = basestring
13
+ import _winreg as winreg
14
+
15
+ from comtypes import GUID, TYPE_CHECKING, typeinfo
16
+ import comtypes.client
17
+ from comtypes.tools import codegenerator, tlbparser
18
+
19
+ if TYPE_CHECKING:
20
+ from typing import Any, Tuple, List, Optional, Dict, Union as _UnionT
21
+
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ PATH = os.environ["PATH"].split(os.pathsep)
26
+
27
+
28
+ def _my_import(fullname):
29
+ # type: (str) -> types.ModuleType
30
+ """helper function to import dotted modules"""
31
+ import comtypes.gen as g
32
+ if comtypes.client.gen_dir and comtypes.client.gen_dir not in g.__path__:
33
+ g.__path__.append(comtypes.client.gen_dir) # type: ignore
34
+ return importlib.import_module(fullname)
35
+
36
+
37
+ def _resolve_filename(tlib_string, dirpath):
38
+ # type: (str, str) -> Tuple[str, bool]
39
+ """Tries to make sense of a type library specified as a string.
40
+
41
+ Args:
42
+ tlib_string: type library designator
43
+ dirpath: a directory to relativize the location
44
+
45
+ Returns:
46
+ (abspath, True) or (relpath, False):
47
+ where relpath is an unresolved path.
48
+ """
49
+ assert isinstance(tlib_string, base_text_type)
50
+ # pathname of type library
51
+ if os.path.isabs(tlib_string):
52
+ # a specific location
53
+ return tlib_string, True
54
+ elif dirpath:
55
+ abspath = os.path.normpath(os.path.join(dirpath, tlib_string))
56
+ if os.path.exists(abspath):
57
+ return abspath, True
58
+ # try with respect to cwd (if _getmodule executed from command line)
59
+ abspath = os.path.abspath(tlib_string)
60
+ if os.path.exists(abspath):
61
+ return abspath, True
62
+ # Otherwise it may still be that the file is on Windows search
63
+ # path for typelibs, and we leave the pathname alone.
64
+ return tlib_string, False
65
+
66
+
67
+ def GetModule(tlib):
68
+ # type: (_UnionT[Any, typeinfo.ITypeLib]) -> types.ModuleType
69
+ """Create a module wrapping a COM typelibrary on demand.
70
+
71
+ 'tlib' must be ...
72
+ - an `ITypeLib` COM pointer instance
73
+ - an absolute pathname of a type library
74
+ - a relative pathname of a type library
75
+ - interpreted as relative to the callers `__file__`, if this exists
76
+ - a COM CLSID `GUID`
77
+ - a `tuple`/`list` specifying the typelib
78
+ - `List[_UnionT[str, int]]`
79
+ - `(libid: str[, wMajorVerNum: int, wMinorVerNum: int[, lcid: int]])`
80
+ - an object with `_reg_libid_: str` and `_reg_version_: Iterable[int]`
81
+
82
+ This function determines the module name from the typelib
83
+ attributes, then tries to import it. If that fails because the
84
+ module doesn't exist, the module is generated into the
85
+ `comtypes.gen` package.
86
+
87
+ It is possible to delete the whole `comtypes/gen` directory to
88
+ remove all generated modules, the directory and the `__init__.py`
89
+ file in it will be recreated when needed.
90
+
91
+ If `comtypes.gen.__path__` is not a directory (in a frozen
92
+ executable it lives in a zip archive), generated modules are only
93
+ created in memory without writing them to the file system.
94
+
95
+ Example:
96
+ GetModule("UIAutomationCore.dll")
97
+
98
+ would create modules named
99
+
100
+ `comtypes.gen._944DE083_8FB8_45CF_BCB7_C477ACB2F897_L_M_m`
101
+ - typelib wrapper module
102
+ - where L, M, m are numbers of Lcid, Major-ver, minor-ver
103
+ `comtypes.gen.UIAutomationClient`
104
+ - friendly named module
105
+
106
+ containing the Python wrapper code for the type library used by
107
+ UIAutomation. The former module contains all the code, the
108
+ latter is a short stub loading the former.
109
+ """
110
+ if isinstance(tlib, base_text_type):
111
+ tlib_string = tlib
112
+ # if a relative pathname is used, we try to interpret it relative to
113
+ # the directory of the calling module (if not from command line)
114
+ frame = sys._getframe(1)
115
+ _file_ = frame.f_globals.get("__file__", None) # type: str
116
+ pathname, is_abs = _resolve_filename(tlib_string, _file_ and os.path.dirname(_file_))
117
+ logger.debug("GetModule(%s), resolved: %s", pathname, is_abs)
118
+ tlib = _load_tlib(pathname) # don't register
119
+ if not is_abs:
120
+ # try to get path after loading, but this only works if already registered
121
+ pathname = tlbparser.get_tlib_filename(tlib)
122
+ if pathname is None:
123
+ logger.info("GetModule(%s): could not resolve to a filename", tlib)
124
+ pathname = tlib_string
125
+ # if above path torture resulted in an absolute path, then the file exists (at this point)!
126
+ assert not(os.path.isabs(pathname)) or os.path.exists(pathname)
127
+ else:
128
+ pathname = None
129
+ tlib = _load_tlib(tlib)
130
+ logger.debug("GetModule(%s)", tlib.GetLibAttr())
131
+ # create and import the real typelib wrapper module
132
+ mod = _create_wrapper_module(tlib, pathname)
133
+ # try to get the friendly-name, if not, returns the real typelib wrapper module
134
+ modulename = codegenerator.name_friendly_module(tlib)
135
+ if modulename is None:
136
+ return mod
137
+ if sys.version_info < (3, 0):
138
+ modulename = modulename.encode("mbcs")
139
+ # create and import the friendly-named module
140
+ return _create_friendly_module(tlib, modulename)
141
+
142
+
143
+ def _load_tlib(obj):
144
+ # type: (Any) -> typeinfo.ITypeLib
145
+ """Load a pointer of ITypeLib on demand."""
146
+ # obj is a filepath or a ProgID
147
+ if isinstance(obj, base_text_type):
148
+ # in any case, attempt to load and if tlib_string is not valid, then raise
149
+ # as "OSError: [WinError -2147312566] Error loading type library/DLL"
150
+ return typeinfo.LoadTypeLibEx(obj)
151
+ # obj is a tlib GUID contain a clsid
152
+ elif isinstance(obj, GUID):
153
+ clsid = str(obj)
154
+ # lookup associated typelib in registry
155
+ with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\TypeLib" % clsid) as key:
156
+ libid = winreg.EnumValue(key, 0)[1]
157
+ with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\Version" % clsid) as key:
158
+ ver = winreg.EnumValue(key, 0)[1].split(".")
159
+ return typeinfo.LoadRegTypeLib(GUID(libid), int(ver[0]), int(ver[1]), 0)
160
+ # obj is a sequence containing libid
161
+ elif isinstance(obj, (tuple, list)):
162
+ libid, ver = obj[0], obj[1:]
163
+ if not ver: # case of version numbers are not containing
164
+ with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"TypeLib\%s" % libid) as key:
165
+ ver = [int(v, base=16) for v in winreg.EnumKey(key, 0).split(".")]
166
+ return typeinfo.LoadRegTypeLib(GUID(libid), *ver)
167
+ # obj is a COMObject implementation
168
+ elif hasattr(obj, "_reg_libid_"):
169
+ return typeinfo.LoadRegTypeLib(GUID(obj._reg_libid_), *obj._reg_version_)
170
+ # obj is a pointer of ITypeLib
171
+ elif isinstance(obj, ctypes.POINTER(typeinfo.ITypeLib)):
172
+ return obj # type: ignore
173
+ raise TypeError("'%r' is not supported type for loading typelib" % obj)
174
+
175
+
176
+ def _create_module_in_file(modulename, code):
177
+ # type: (str, str) -> types.ModuleType
178
+ """create module in file system, and import it"""
179
+ # `modulename` is 'comtypes.gen.xxx'
180
+ filename = "%s.py" % modulename.split(".")[-1]
181
+ with open(os.path.join(comtypes.client.gen_dir, filename), "w") as ofi:
182
+ print(code, file=ofi)
183
+ # clear the import cache to make sure Python sees newly created modules
184
+ if hasattr(importlib, "invalidate_caches"):
185
+ importlib.invalidate_caches()
186
+ return _my_import(modulename)
187
+
188
+
189
+ def _create_module_in_memory(modulename, code):
190
+ # type: (str, str) -> types.ModuleType
191
+ """create module in memory system, and import it"""
192
+ # `modulename` is 'comtypes.gen.xxx'
193
+ import comtypes.gen as g
194
+ mod = types.ModuleType(modulename)
195
+ abs_gen_path = os.path.abspath(g.__path__[0]) # type: ignore
196
+ mod.__file__ = os.path.join(abs_gen_path, "<memory>")
197
+ exec(code, mod.__dict__)
198
+ sys.modules[modulename] = mod
199
+ setattr(g, modulename.split(".")[-1], mod)
200
+ return mod
201
+
202
+
203
+ def _create_friendly_module(tlib, modulename):
204
+ # type: (typeinfo.ITypeLib, str) -> types.ModuleType
205
+ """helper which creates and imports the friendly-named module."""
206
+ try:
207
+ mod = _my_import(modulename)
208
+ except Exception as details:
209
+ logger.info("Could not import %s: %s", modulename, details)
210
+ else:
211
+ return mod
212
+ # the module is always regenerated if the import fails
213
+ logger.info("# Generating %s", modulename)
214
+ # determine the Python module name
215
+ modname = codegenerator.name_wrapper_module(tlib).split(".")[-1]
216
+ code = "from comtypes.gen import %s\n" % modname
217
+ code += "globals().update(%s.__dict__)\n" % modname
218
+ code += "__name__ = '%s'" % modulename
219
+ if comtypes.client.gen_dir is None:
220
+ return _create_module_in_memory(modulename, code)
221
+ return _create_module_in_file(modulename, code)
222
+
223
+
224
+ def _create_wrapper_module(tlib, pathname):
225
+ # type: (typeinfo.ITypeLib, Optional[str]) -> types.ModuleType
226
+ """helper which creates and imports the real typelib wrapper module."""
227
+ modulename = codegenerator.name_wrapper_module(tlib)
228
+ if modulename in sys.modules:
229
+ return sys.modules[modulename]
230
+ try:
231
+ return _my_import(modulename)
232
+ except Exception as details:
233
+ logger.info("Could not import %s: %s", modulename, details)
234
+ # generate the module since it doesn't exist or is out of date
235
+ logger.info("# Generating %s", modulename)
236
+ p = tlbparser.TypeLibParser(tlib)
237
+ if pathname is None:
238
+ pathname = tlbparser.get_tlib_filename(tlib)
239
+ items = list(p.parse().values())
240
+ codegen = codegenerator.CodeGenerator(_get_known_symbols())
241
+ code = codegen.generate_code(items, filename=pathname)
242
+ for ext_tlib in codegen.externals: # generates dependency COM-lib modules
243
+ GetModule(ext_tlib)
244
+ if comtypes.client.gen_dir is None:
245
+ return _create_module_in_memory(modulename, code)
246
+ return _create_module_in_file(modulename, code)
247
+
248
+
249
+ def _get_known_symbols():
250
+ # type: () -> Dict[str, str]
251
+ known_symbols = {} # type: Dict[str, str]
252
+ for mod_name in (
253
+ "comtypes.persist",
254
+ "comtypes.typeinfo",
255
+ "comtypes.automation",
256
+ "comtypes",
257
+ "ctypes.wintypes",
258
+ "ctypes"
259
+ ):
260
+ mod = importlib.import_module(mod_name)
261
+ if hasattr(mod, "__known_symbols__"):
262
+ names = mod.__known_symbols__ # type: List[str]
263
+ else:
264
+ names = list(mod.__dict__)
265
+ for name in names:
266
+ known_symbols[name] = mod.__name__
267
+ return known_symbols
268
+
269
+ ################################################################
270
+
271
+
272
+ if __name__ == "__main__":
273
+ # When started as script, generate typelib wrapper from .tlb file.
274
+ GetModule(sys.argv[1])
@@ -0,0 +1,26 @@
1
+ from typing import (
2
+ Any, Callable, Generic, NoReturn, Optional, overload, SupportsIndex,
3
+ Type, TypeVar, Union as _UnionT,
4
+ )
5
+
6
+ # symbols those what might occur recursive imports in runtime.
7
+ from comtypes.automation import IDispatch as IDispatch, VARIANT as VARIANT
8
+ from comtypes.server import IClassFactory as IClassFactory
9
+ from comtypes.typeinfo import ITypeInfo as ITypeInfo
10
+
11
+
12
+ def AnnoField() -> Any:
13
+ """**THIS IS `TYPE_CHECKING` ONLY SYMBOL.
14
+
15
+ This is workaround for class field type annotations for old
16
+ python versions.
17
+
18
+ Examples:
19
+ # instead of class field annotation, like below
20
+
21
+ class Foo:
22
+ # spam: int # <- not available in old versions.
23
+ if TYPE_CHECKING:
24
+ spam = AnnoField() # type: int # <- available in old versions.
25
+ """
26
+ ...
@@ -210,3 +210,17 @@ class DictPropertyBag(COMObject):
210
210
  val = var[0].value
211
211
  self.values[name] = val
212
212
  return S_OK
213
+
214
+
215
+ __known_symbols__ = [
216
+ 'CLIPFORMAT', 'DictPropertyBag', 'IErrorLog', 'IPersistFile',
217
+ 'IPersistPropertyBag', 'IPersistPropertyBag2', 'IPropertyBag',
218
+ 'IPropertyBag2', 'tagPROPBAG2', 'PROPBAG2_TYPE_DATA',
219
+ 'PROPBAG2_TYPE_MONIKER', 'PROPBAG2_TYPE_OBJECT', 'PROPBAG2_TYPE_STORAGE',
220
+ 'PROPBAG2_TYPE_STREAM', 'PROPBAG2_TYPE_UNDEFINED', 'PROPBAG2_TYPE_URL',
221
+ 'STGM_CONVERT', 'STGM_CREATE', 'STGM_DELETEONRELEASE', 'STGM_DIRECT',
222
+ 'STGM_DIRECT_SWMR', 'STGM_FAILIFTHERE', 'STGM_NOSCRATCH',
223
+ 'STGM_NOSNAPSHOT', 'STGM_PRIORITY', 'STGM_READ', 'STGM_READWRITE',
224
+ 'STGM_SHARE_DENY_NONE', 'STGM_SHARE_DENY_READ', 'STGM_SHARE_DENY_WRITE',
225
+ 'STGM_SHARE_EXCLUSIVE', 'STGM_SIMPLE', 'STGM_TRANSACTED', 'STGM_WRITE',
226
+ ]
@@ -1,11 +1,11 @@
1
1
  import threading
2
2
  import array
3
+ import comtypes
3
4
  from ctypes import (POINTER, Structure, byref, cast, c_long, memmove, pointer,
4
5
  sizeof)
5
- from comtypes import _safearray, IUnknown, com_interface_registry, npsupport
6
+ from comtypes import _safearray, IUnknown, com_interface_registry
6
7
  from comtypes.patcher import Patch
7
8
 
8
- numpy = npsupport.numpy
9
9
  _safearray_type_cache = {}
10
10
 
11
11
 
@@ -27,6 +27,7 @@ class _SafeArrayAsNdArrayContextManager(object):
27
27
  thread_local = threading.local()
28
28
 
29
29
  def __enter__(self):
30
+ comtypes.npsupport.enable()
30
31
  try:
31
32
  self.thread_local.count += 1
32
33
  except AttributeError:
@@ -113,7 +114,7 @@ def _make_safearray_type(itemtype):
113
114
  one-dimensional arrays. To create multidimensional arrys,
114
115
  numpy arrays must be passed.
115
116
  """
116
- if npsupport.isndarray(value):
117
+ if comtypes.npsupport.isndarray(value):
117
118
  return cls.create_from_ndarray(value, extra)
118
119
 
119
120
  # For VT_UNKNOWN or VT_DISPATCH, extra must be a pointer to
@@ -156,18 +157,18 @@ def _make_safearray_type(itemtype):
156
157
  from comtypes.automation import VARIANT
157
158
  # If processing VARIANT, makes sure the array type is correct.
158
159
  if cls._itemtype_ is VARIANT:
159
- if value.dtype != npsupport.VARIANT_dtype:
160
+ if value.dtype != comtypes.npsupport.VARIANT_dtype:
160
161
  value = _ndarray_to_variant_array(value)
161
162
  else:
162
163
  ai = value.__array_interface__
163
164
  if ai["version"] != 3:
164
165
  raise TypeError("only __array_interface__ version 3 supported")
165
- if cls._itemtype_ != npsupport.typecodes[ai["typestr"]]:
166
+ if cls._itemtype_ != comtypes.npsupport.typecodes[ai["typestr"]]:
166
167
  raise TypeError("Wrong array item type")
167
168
 
168
169
  # SAFEARRAYs have Fortran order; convert the numpy array if needed
169
170
  if not value.flags.f_contiguous:
170
- value = numpy.array(value, order="F")
171
+ value = comtypes.npsupport.numpy.array(value, order="F")
171
172
 
172
173
  # For VT_UNKNOWN or VT_DISPATCH, extra must be a pointer to
173
174
  # the GUID of the interface.
@@ -240,15 +241,13 @@ def _make_safearray_type(itemtype):
240
241
 
241
242
  if dim == 0:
242
243
  if safearray_as_ndarray:
243
- import numpy
244
- return numpy.array()
244
+ return comtypes.npsupport.numpy.array()
245
245
  return tuple()
246
246
  elif dim == 1:
247
247
  num_elements = self._get_size(1)
248
248
  result = self._get_elements_raw(num_elements)
249
249
  if safearray_as_ndarray:
250
- import numpy
251
- return numpy.asarray(result)
250
+ return comtypes.npsupport.numpy.asarray(result)
252
251
  return tuple(result)
253
252
  elif dim == 2:
254
253
  # get the number of elements in each dimension
@@ -258,8 +257,7 @@ def _make_safearray_type(itemtype):
258
257
  # this must be reshaped and transposed because it is
259
258
  # flat, and in VB order
260
259
  if safearray_as_ndarray:
261
- import numpy
262
- return numpy.asarray(result).reshape((cols, rows)).T
260
+ return comtypes.npsupport.numpy.asarray(result).reshape((cols, rows)).T
263
261
  result = [tuple(result[r::rows]) for r in range(rows)]
264
262
  return tuple(result)
265
263
  else:
@@ -270,8 +268,7 @@ def _make_safearray_type(itemtype):
270
268
  for d in range(1, dim+1)]
271
269
  row = self._get_row(0, indexes, lowerbounds, upperbounds)
272
270
  if safearray_as_ndarray:
273
- import numpy
274
- return numpy.asarray(row)
271
+ return comtypes.npsupport.numpy.asarray(row)
275
272
  return row
276
273
 
277
274
  def _get_elements_raw(self, num_elements):
@@ -315,8 +312,8 @@ def _make_safearray_type(itemtype):
315
312
  # XXX Only try to convert types known to
316
313
  # numpy.ctypeslib.
317
314
  if (safearray_as_ndarray and self._itemtype_ in
318
- list(npsupport.typecodes.keys())):
319
- arr = numpy.ctypeslib.as_array(ptr,
315
+ list(comtypes.npsupport.typecodes.keys())):
316
+ arr = comtypes.npsupport.numpy.ctypeslib.as_array(ptr,
320
317
  (num_elements,))
321
318
  return arr.copy()
322
319
  return ptr[:num_elements]
@@ -372,17 +369,20 @@ def _make_safearray_type(itemtype):
372
369
  def _ndarray_to_variant_array(value):
373
370
  """ Convert an ndarray to VARIANT_dtype array """
374
371
  # Check that variant arrays are supported
375
- if npsupport.VARIANT_dtype is None:
372
+ if comtypes.npsupport.interop.VARIANT_dtype is None:
376
373
  msg = "VARIANT ndarrays require NumPy 1.7 or newer."
377
374
  raise RuntimeError(msg)
375
+ numpy = comtypes.npsupport.interop.numpy
378
376
 
379
377
  # special cases
380
- if numpy.issubdtype(value.dtype, npsupport.datetime64):
378
+ if numpy.issubdtype(value.dtype, comtypes.npsupport.interop.datetime64):
381
379
  return _datetime64_ndarray_to_variant_array(value)
382
380
 
383
381
  from comtypes.automation import VARIANT
384
382
  # Empty array
385
- varr = numpy.zeros(value.shape, npsupport.VARIANT_dtype, order='F')
383
+ varr = numpy.zeros(
384
+ value.shape, comtypes.npsupport.interop.VARIANT_dtype, order='F'
385
+ )
386
386
  # Convert each value to a variant and put it in the array.
387
387
  varr.flat = [VARIANT(v) for v in value.flat]
388
388
  return varr
@@ -394,11 +394,12 @@ def _datetime64_ndarray_to_variant_array(value):
394
394
  # since midnight 30 December 1899. Hours and minutes are represented as
395
395
  # fractional days.
396
396
  from comtypes.automation import VT_DATE
397
+ numpy = comtypes.npsupport.interop.numpy
397
398
  value = numpy.array(value, "datetime64[ns]")
398
- value = value - npsupport.com_null_date64
399
+ value = value - comtypes.npsupport.interop.com_null_date64
399
400
  # Convert to days
400
401
  value = value / numpy.timedelta64(1, 'D')
401
- varr = numpy.zeros(value.shape, npsupport.VARIANT_dtype, order='F')
402
+ varr = numpy.zeros(value.shape, comtypes.npsupport.interop.VARIANT_dtype, order='F')
402
403
  varr['vt'] = VT_DATE
403
404
  varr['_']['VT_R8'].flat = value.flat
404
405
  return varr
@@ -10,13 +10,6 @@ import unittest
10
10
 
11
11
  use_resources = ["*"]
12
12
 
13
- def get_numpy():
14
- '''Get numpy if it is available.'''
15
- try:
16
- import numpy
17
- return numpy
18
- except ImportError:
19
- return None
20
13
 
21
14
  def register_server(source_dir):
22
15
  """ Register testing server appropriate for the python architecture.
@@ -69,6 +69,11 @@ class Test_GetModule(ut.TestCase):
69
69
  mod = comtypes.client.GetModule(clsid)
70
70
  self.assertEqual(mod.MediaPlayer._reg_clsid_, clsid)
71
71
 
72
+ def test_ptr_itypelib(self):
73
+ from comtypes import typeinfo
74
+ mod = comtypes.client.GetModule(typeinfo.LoadTypeLibEx("scrrun.dll"))
75
+ self.assertIs(mod, Scripting)
76
+
72
77
  def test_imports_IEnumVARIANT_from_other_generated_modules(self):
73
78
  # NOTE: `codegenerator` generates code that contains unused imports,
74
79
  # but removing them are attracting wierd bugs in library-wrappers
@@ -84,6 +89,36 @@ class Test_GetModule(ut.TestCase):
84
89
  # NOTE: `WindowsInstaller`, which has `Patch` definition in dll.
85
90
  comtypes.client.GetModule("msi.dll")
86
91
 
92
+ def test_raises_typerror_if_takes_unsupported(self):
93
+ with self.assertRaises(TypeError):
94
+ comtypes.client.GetModule(object())
95
+
96
+
97
+ class Test_KnownSymbols(ut.TestCase):
98
+ # It is guaranteed that each element of `__known_symbols__` is in
99
+ # each module's namespace.
100
+ # If this test fails, `ImportError` or `AttributeError` may be raised
101
+ # when generating a `comtypes.gen._xxx...` in runtime.
102
+ def _doit(self, mod):
103
+ for s in mod.__known_symbols__:
104
+ self.assertTrue(hasattr(mod, s))
105
+
106
+ def test_symbols_in_comtypes(self):
107
+ import comtypes
108
+ self._doit(comtypes)
109
+
110
+ def test_symbols_in_comtypes_automation(self):
111
+ import comtypes.automation
112
+ self._doit(comtypes.automation)
113
+
114
+ def test_symbols_in_comtypes_typeinfo(self):
115
+ import comtypes.typeinfo
116
+ self._doit(comtypes.typeinfo)
117
+
118
+ def test_symbols_in_comtypes_persist(self):
119
+ import comtypes.persist
120
+ self._doit(comtypes.persist)
121
+
87
122
 
88
123
  class Test_CreateObject(ut.TestCase):
89
124
  def test_progid(self):
@@ -7,10 +7,6 @@ from comtypes.client import CreateObject
7
7
  from comtypes.client.lazybind import Dispatch
8
8
 
9
9
 
10
- def setUpModule():
11
- raise unittest.SkipTest("Depends on `comtypes.safearray` which depends on numpy which isn't "
12
- "listed in project dependencies.")
13
-
14
10
  class Test(unittest.TestCase):
15
11
  def test_dict(self):
16
12
  d = CreateObject("Scripting.Dictionary", dynamic=True)