comtypes 1.4.2__zip → 1.4.4__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 (121) hide show
  1. {comtypes-1.4.2 → comtypes-1.4.4}/CHANGES.txt +22 -2
  2. {comtypes-1.4.2/comtypes.egg-info → comtypes-1.4.4}/PKG-INFO +30 -3
  3. {comtypes-1.4.2 → comtypes-1.4.4}/README.md +28 -1
  4. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/__init__.py +6 -8
  5. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/automation.py +26 -2
  6. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/hints.pyi +15 -0
  7. comtypes-1.4.4/comtypes/test/mylib.tlb +0 -0
  8. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_GUID.py +23 -2
  9. comtypes-1.4.4/comtypes/test/test_dispifc_records.py +90 -0
  10. comtypes-1.4.4/comtypes/test/test_findgendir.py +87 -0
  11. comtypes-1.4.4/comtypes/test/urlhist.tlb +0 -0
  12. comtypes-1.4.4/comtypes/tools/codegenerator/__init__.py +5 -0
  13. {comtypes-1.4.2/comtypes/tools → comtypes-1.4.4/comtypes/tools/codegenerator}/codegenerator.py +56 -721
  14. comtypes-1.4.4/comtypes/tools/codegenerator/helpers.py +357 -0
  15. comtypes-1.4.4/comtypes/tools/codegenerator/modulenamer.py +24 -0
  16. comtypes-1.4.4/comtypes/tools/codegenerator/namespaces.py +212 -0
  17. comtypes-1.4.4/comtypes/tools/codegenerator/packing.py +81 -0
  18. {comtypes-1.4.2/comtypes/tools → comtypes-1.4.4/comtypes/tools/codegenerator}/typeannotator.py +18 -3
  19. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/tools/tlbparser.py +19 -49
  20. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/tools/typedesc.py +57 -9
  21. {comtypes-1.4.2 → comtypes-1.4.4/comtypes.egg-info}/PKG-INFO +30 -3
  22. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes.egg-info/SOURCES.txt +13 -3
  23. comtypes-1.4.4/pyproject.toml +3 -0
  24. comtypes-1.4.4/setup.cfg +51 -0
  25. comtypes-1.4.4/setup.py +117 -0
  26. comtypes-1.4.2/comtypes/test/test_findgendir.py +0 -94
  27. comtypes-1.4.2/setup.cfg +0 -4
  28. comtypes-1.4.2/setup.py +0 -172
  29. {comtypes-1.4.2 → comtypes-1.4.4}/LICENSE.txt +0 -0
  30. {comtypes-1.4.2 → comtypes-1.4.4}/MANIFEST.in +0 -0
  31. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/GUID.py +0 -0
  32. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/_comobject.py +0 -0
  33. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/_memberspec.py +0 -0
  34. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/_meta.py +0 -0
  35. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/_npsupport.py +0 -0
  36. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/_safearray.py +0 -0
  37. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/clear_cache.py +0 -0
  38. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/client/__init__.py +0 -0
  39. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/client/_code_cache.py +0 -0
  40. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/client/_constants.py +0 -0
  41. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/client/_events.py +0 -0
  42. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/client/_generate.py +0 -0
  43. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/client/dynamic.py +0 -0
  44. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/client/lazybind.py +0 -0
  45. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/connectionpoints.py +0 -0
  46. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/errorinfo.py +0 -0
  47. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/git.py +0 -0
  48. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/hresult.py +0 -0
  49. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/logutil.py +0 -0
  50. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/messageloop.py +0 -0
  51. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/patcher.py +0 -0
  52. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/persist.py +0 -0
  53. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/safearray.py +0 -0
  54. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/server/__init__.py +0 -0
  55. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/server/automation.py +0 -0
  56. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/server/connectionpoints.py +0 -0
  57. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/server/inprocserver.py +0 -0
  58. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/server/localserver.py +0 -0
  59. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/server/register.py +0 -0
  60. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/server/w_getopt.py +0 -0
  61. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/shelllink.py +0 -0
  62. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/TestComServer.idl +0 -0
  63. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/TestComServer.py +0 -0
  64. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/TestComServer.tlb +0 -0
  65. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/TestDispServer.idl +0 -0
  66. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/TestDispServer.py +0 -0
  67. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/TestDispServer.tlb +0 -0
  68. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/__init__.py +0 -0
  69. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/find_memleak.py +0 -0
  70. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/mylib.idl +0 -0
  71. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/mytypelib.idl +0 -0
  72. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/runtests.py +0 -0
  73. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/setup.py +0 -0
  74. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_BSTR.py +0 -0
  75. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_DISPPARAMS.py +0 -0
  76. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_QueryService.py +0 -0
  77. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_agilent.py +0 -0
  78. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_avmc.py +0 -0
  79. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_basic.py +0 -0
  80. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_casesensitivity.py +0 -0
  81. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_clear_cache.py +0 -0
  82. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_client.py +0 -0
  83. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_client_dynamic.py +0 -0
  84. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_client_regenerate_modules.py +0 -0
  85. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_collections.py +0 -0
  86. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_comserver.py +0 -0
  87. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_createwrappers.py +0 -0
  88. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_dict.py +0 -0
  89. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_dispinterface.py +0 -0
  90. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_dyndispatch.py +0 -0
  91. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_excel.py +0 -0
  92. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_getactiveobj.py +0 -0
  93. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_ie.py +0 -0
  94. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_ienum.py +0 -0
  95. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_imfattributes.py +0 -0
  96. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_inout_args.py +0 -0
  97. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_jscript.js +0 -0
  98. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_msscript.py +0 -0
  99. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_npsupport.py +0 -0
  100. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_outparam.py +0 -0
  101. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_propputref.py +0 -0
  102. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_pump_events.py +0 -0
  103. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_safearray.py +0 -0
  104. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_sapi.py +0 -0
  105. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_server.py +0 -0
  106. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_showevents.py +0 -0
  107. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_subinterface.py +0 -0
  108. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_typeinfo.py +0 -0
  109. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_urlhistory.py +0 -0
  110. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_variant.py +0 -0
  111. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_win32com_interop.py +0 -0
  112. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_wmi.py +0 -0
  113. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/test/test_word.py +0 -0
  114. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/tools/__init__.py +0 -0
  115. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/tools/typedesc_base.py +0 -0
  116. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/typeinfo.py +0 -0
  117. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/util.py +0 -0
  118. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes/viewobject.py +0 -0
  119. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes.egg-info/dependency_links.txt +0 -0
  120. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes.egg-info/entry_points.txt +0 -0
  121. {comtypes-1.4.2 → comtypes-1.4.4}/comtypes.egg-info/top_level.txt +0 -0
@@ -0,0 +1,357 @@
1
+ import keyword
2
+ from typing import Any
3
+ from typing import List, Tuple
4
+ from typing import Iterator
5
+ from typing import Union as _UnionT
6
+
7
+ import comtypes
8
+ from comtypes.tools import typedesc
9
+ from comtypes.tools.codegenerator.modulenamer import name_wrapper_module
10
+
11
+
12
+ class lcid(object):
13
+ def __repr__(self):
14
+ return "_lcid"
15
+
16
+
17
+ lcid = lcid()
18
+
19
+
20
+ class dispid(object):
21
+ def __init__(self, memid):
22
+ self.memid = memid
23
+
24
+ def __repr__(self):
25
+ return "dispid(%s)" % self.memid
26
+
27
+
28
+ class helpstring(object):
29
+ def __init__(self, text):
30
+ self.text = text
31
+
32
+ def __repr__(self):
33
+ return "helpstring(%r)" % self.text
34
+
35
+
36
+ # XXX Should this be in ctypes itself?
37
+ ctypes_names = {
38
+ "unsigned char": "c_ubyte",
39
+ "signed char": "c_byte",
40
+ "char": "c_char",
41
+ "wchar_t": "c_wchar",
42
+ "short unsigned int": "c_ushort",
43
+ "short int": "c_short",
44
+ "long unsigned int": "c_ulong",
45
+ "long int": "c_long",
46
+ "long signed int": "c_long",
47
+ "unsigned int": "c_uint",
48
+ "int": "c_int",
49
+ "long long unsigned int": "c_ulonglong",
50
+ "long long int": "c_longlong",
51
+ "double": "c_double",
52
+ "float": "c_float",
53
+ # Hm...
54
+ "void": "None",
55
+ }
56
+
57
+
58
+ def get_real_type(tp):
59
+ if type(tp) is typedesc.Typedef:
60
+ return get_real_type(tp.typ)
61
+ elif isinstance(tp, typedesc.CvQualifiedType):
62
+ return get_real_type(tp.typ)
63
+ return tp
64
+
65
+
66
+ ASSUME_STRINGS = True
67
+
68
+
69
+ ################################################################
70
+
71
+
72
+ _DefValType = _UnionT["lcid", Any, None]
73
+ _IdlFlagType = _UnionT[str, dispid, helpstring]
74
+
75
+
76
+ def _to_arg_definition(
77
+ type_name: str,
78
+ arg_name: str,
79
+ idlflags: List[str],
80
+ default: _DefValType,
81
+ ) -> str:
82
+ if default is not None:
83
+ code = f" ({idlflags!r}, {type_name}, '{arg_name}', {default!r})"
84
+ if len(code) > 80:
85
+ code = (
86
+ " (\n"
87
+ f" {idlflags!r},\n"
88
+ f" {type_name},\n"
89
+ f" '{arg_name}',\n"
90
+ f" {default!r}\n"
91
+ " )"
92
+ )
93
+ else:
94
+ code = f" ({idlflags!r}, {type_name}, '{arg_name}')"
95
+ if len(code) > 80:
96
+ code = (
97
+ " (\n"
98
+ f" {idlflags!r},\n"
99
+ f" {type_name},\n"
100
+ f" '{arg_name}',\n"
101
+ " )"
102
+ )
103
+ return code
104
+
105
+
106
+ class ComMethodGenerator(object):
107
+ def __init__(self, m: typedesc.ComMethod, isdual: bool) -> None:
108
+ self._m = m
109
+ self._isdual = isdual
110
+ self.data: List[str] = []
111
+ self._to_type_name = TypeNamer()
112
+
113
+ def generate(self) -> str:
114
+ if not self._m.arguments:
115
+ self._make_noargs()
116
+ else:
117
+ self._make_withargs()
118
+ return "\n".join(self.data)
119
+
120
+ def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
121
+ idlflags: List[_IdlFlagType] = []
122
+ if self._isdual:
123
+ idlflags.append(dispid(self._m.memid))
124
+ idlflags.extend(self._m.idlflags)
125
+ else: # We don't include the dispid for non-dispatch COM interfaces
126
+ idlflags.extend(self._m.idlflags)
127
+ if __debug__ and self._m.doc:
128
+ idlflags.insert(1, helpstring(self._m.doc))
129
+ type_name = self._to_type_name(self._m.returns)
130
+ return (idlflags, type_name, self._m.name)
131
+
132
+ def _make_noargs(self) -> None:
133
+ flags, type_name, member_name = self._get_common_elms()
134
+ code = f" COMMETHOD({flags!r}, {type_name}, '{member_name}'),"
135
+ if len(code) > 80:
136
+ code = (
137
+ " COMMETHOD(\n"
138
+ f" {flags!r},\n"
139
+ f" {type_name},\n"
140
+ f" '{member_name}',\n"
141
+ " ),"
142
+ )
143
+ self.data.append(code)
144
+
145
+ def _make_withargs(self) -> None:
146
+ flags, type_name, member_name = self._get_common_elms()
147
+ code = (
148
+ " COMMETHOD(\n"
149
+ f" {flags!r},\n"
150
+ f" {type_name},\n"
151
+ f" '{member_name}',"
152
+ )
153
+ self.data.append(code)
154
+ arglist = [_to_arg_definition(*i) for i in self._iter_args()]
155
+ self.data.append(",\n".join(arglist))
156
+ self.data.append(" ),")
157
+
158
+ def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
159
+ for typ, arg_name, _f, _defval in self._m.arguments:
160
+ ###########################################################
161
+ # IDL files that contain 'open arrays' or 'conformant
162
+ # varying arrays' method parameters are strange.
163
+ # These arrays have both a 'size_is()' and
164
+ # 'length_is()' attribute, like this example from
165
+ # dia2.idl (in the DIA SDK):
166
+ #
167
+ # interface IDiaSymbol: IUnknown {
168
+ # ...
169
+ # HRESULT get_dataBytes(
170
+ # [in] DWORD cbData,
171
+ # [out] DWORD *pcbData,
172
+ # [out, size_is(cbData),
173
+ # length_is(*pcbData)] BYTE data[]
174
+ # );
175
+ #
176
+ # The really strange thing is that the decompiled type
177
+ # library then contains this declaration, which declares
178
+ # the interface itself as [out] method parameter:
179
+ #
180
+ # interface IDiaSymbol: IUnknown {
181
+ # ...
182
+ # HRESULT _stdcall get_dataBytes(
183
+ # [in] unsigned long cbData,
184
+ # [out] unsigned long* pcbData,
185
+ # [out] IDiaSymbol data);
186
+ #
187
+ # Of course, comtypes does not accept a COM interface
188
+ # as method parameter; so replace the parameter type
189
+ # with the comtypes spelling of 'unsigned char *', and
190
+ # mark the parameter as [in, out], so the IDL
191
+ # equivalent would be like this:
192
+ #
193
+ # interface IDiaSymbol: IUnknown {
194
+ # ...
195
+ # HRESULT _stdcall get_dataBytes(
196
+ # [in] unsigned long cbData,
197
+ # [out] unsigned long* pcbData,
198
+ # [in, out] BYTE data[]);
199
+ ###########################################################
200
+ idlflags = list(_f) # shallow copy to avoid side effects
201
+ if isinstance(typ, typedesc.ComInterface):
202
+ type_name = "OPENARRAY"
203
+ if "in" not in idlflags:
204
+ idlflags.append("in")
205
+ else:
206
+ type_name = self._to_type_name(typ)
207
+ if "lcid" in idlflags: # and 'in' in idlflags:
208
+ default = lcid
209
+ else:
210
+ default = _defval
211
+ yield (type_name, arg_name, idlflags, default)
212
+
213
+
214
+ class DispMethodGenerator(object):
215
+ def __init__(self, m: typedesc.DispMethod) -> None:
216
+ self._m = m
217
+ self.data: List[str] = []
218
+ self._to_type_name = TypeNamer()
219
+
220
+ def generate(self) -> str:
221
+ if not self._m.arguments:
222
+ self._make_noargs()
223
+ else:
224
+ self._make_withargs()
225
+ return "\n".join(self.data)
226
+
227
+ def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
228
+ idlflags: List[_IdlFlagType] = []
229
+ idlflags.append(dispid(self._m.dispid))
230
+ idlflags.extend(self._m.idlflags)
231
+ if __debug__ and self._m.doc:
232
+ idlflags.insert(1, helpstring(self._m.doc))
233
+ type_name = self._to_type_name(self._m.returns)
234
+ return (idlflags, type_name, self._m.name)
235
+
236
+ def _make_noargs(self) -> None:
237
+ flags, type_name, member_name = self._get_common_elms()
238
+ code = f" DISPMETHOD({flags!r}, {type_name}, '{member_name}'),"
239
+ if len(code) > 80:
240
+ code = (
241
+ " DISPMETHOD(\n"
242
+ f" {flags!r},\n"
243
+ f" {type_name},\n"
244
+ f" '{member_name}',\n"
245
+ " ),"
246
+ )
247
+ self.data.append(code)
248
+
249
+ def _make_withargs(self) -> None:
250
+ flags, type_name, member_name = self._get_common_elms()
251
+ code = (
252
+ " DISPMETHOD(\n"
253
+ f" {flags!r},\n"
254
+ f" {type_name},\n"
255
+ f" '{member_name}',"
256
+ )
257
+ self.data.append(code)
258
+ arglist = [_to_arg_definition(*i) for i in self._iter_args()]
259
+ self.data.append(",\n".join(arglist))
260
+ self.data.append(" ),")
261
+
262
+ def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
263
+ for typ, arg_name, idlflags, default in self._m.arguments:
264
+ type_name = self._to_type_name(typ)
265
+ yield (type_name, arg_name, idlflags, default)
266
+
267
+
268
+ class DispPropertyGenerator(object):
269
+ def __init__(self, m: typedesc.DispProperty) -> None:
270
+ self._m = m
271
+ self._to_type_name = TypeNamer()
272
+
273
+ def generate(self) -> str:
274
+ flags, type_name, member_name = self._get_common_elms()
275
+ code = f" DISPPROPERTY({flags!r}, {type_name}, '{member_name}'),"
276
+ if len(code) > 80:
277
+ code = (
278
+ " DISPPROPERTY(\n"
279
+ f" {flags!r},\n"
280
+ f" {type_name},\n"
281
+ f" '{member_name}'\n"
282
+ " ),"
283
+ )
284
+ return code
285
+
286
+ def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
287
+ idlflags: List[_IdlFlagType] = []
288
+ idlflags.append(dispid(self._m.dispid))
289
+ idlflags.extend(self._m.idlflags)
290
+ if __debug__ and self._m.doc:
291
+ idlflags.insert(1, helpstring(self._m.doc))
292
+ type_name = self._to_type_name(self._m.typ)
293
+ return (idlflags, type_name, self._m.name)
294
+
295
+
296
+ class TypeNamer(object):
297
+ def __call__(self, t: Any) -> str:
298
+ # Return a string, containing an expression which can be used
299
+ # to refer to the type. Assumes the 'from ctypes import *'
300
+ # namespace is available.
301
+ if isinstance(t, typedesc.SAFEARRAYType):
302
+ return "_midlSAFEARRAY(%s)" % self(t.typ)
303
+ # if isinstance(t, typedesc.CoClass):
304
+ # return "%s._com_interfaces_[0]" % t.name
305
+ if isinstance(t, typedesc.Typedef):
306
+ return t.name
307
+ if isinstance(t, typedesc.PointerType):
308
+ _t, pcnt = self._inspect_PointerType(t)
309
+ return "%s%s%s" % ("POINTER(" * pcnt, self(_t), ")" * pcnt)
310
+ elif isinstance(t, typedesc.ArrayType):
311
+ return "%s * %s" % (self(t.typ), int(t.max) + 1)
312
+ elif isinstance(t, typedesc.FunctionType):
313
+ args = [self(x) for x in [t.returns] + list(t.iterArgTypes())]
314
+ if "__stdcall__" in t.attributes:
315
+ return "WINFUNCTYPE(%s)" % ", ".join(args)
316
+ else:
317
+ return "CFUNCTYPE(%s)" % ", ".join(args)
318
+ elif isinstance(t, typedesc.CvQualifiedType):
319
+ # const and volatile are ignored
320
+ return "%s" % self(t.typ)
321
+ elif isinstance(t, typedesc.FundamentalType):
322
+ return ctypes_names[t.name]
323
+ elif isinstance(t, typedesc.Structure):
324
+ return t.name
325
+ elif isinstance(t, typedesc.Enumeration):
326
+ if t.name:
327
+ return t.name
328
+ return "c_int" # enums are integers
329
+ elif isinstance(t, typedesc.EnumValue):
330
+ if keyword.iskeyword(t.name):
331
+ return t.name + "_"
332
+ return t.name
333
+ elif isinstance(t, typedesc.External):
334
+ # t.symbol_name - symbol to generate
335
+ # t.tlib - the ITypeLib pointer to the typelibrary containing the symbols definition
336
+ modname = name_wrapper_module(t.tlib)
337
+ return "%s.%s" % (modname, t.symbol_name)
338
+ return t.name
339
+
340
+ def _inspect_PointerType(
341
+ self, t: typedesc.PointerType, count: int = 0
342
+ ) -> Tuple[Any, int]:
343
+ if ASSUME_STRINGS:
344
+ x = get_real_type(t.typ)
345
+ if isinstance(x, typedesc.FundamentalType):
346
+ if x.name == "char":
347
+ return typedesc.Typedef("STRING", x), count
348
+ elif x.name == "wchar_t":
349
+ return typedesc.Typedef("WSTRING", x), count
350
+ if isinstance(t.typ, typedesc.FunctionType):
351
+ return t.typ, count
352
+ if isinstance(t.typ, typedesc.FundamentalType):
353
+ if t.typ.name == "void":
354
+ return typedesc.Typedef("c_void_p", t.typ), count
355
+ if isinstance(t.typ, typedesc.PointerType):
356
+ return self._inspect_PointerType(t.typ, count + 1)
357
+ return t.typ, count + 1
@@ -0,0 +1,24 @@
1
+ import comtypes
2
+
3
+
4
+ def name_wrapper_module(tlib):
5
+ """Determine the name of a typelib wrapper module"""
6
+ libattr = tlib.GetLibAttr()
7
+ modname = "_%s_%s_%s_%s" % (
8
+ str(libattr.guid)[1:-1].replace("-", "_"),
9
+ libattr.lcid,
10
+ libattr.wMajorVerNum,
11
+ libattr.wMinorVerNum,
12
+ )
13
+ return "comtypes.gen.%s" % modname
14
+
15
+
16
+ def name_friendly_module(tlib):
17
+ """Determine the friendly-name of a typelib module.
18
+ If cannot get friendly-name from typelib, returns `None`.
19
+ """
20
+ try:
21
+ modulename = tlib.GetDocumentation(-1)[0]
22
+ except comtypes.COMError:
23
+ return
24
+ return "comtypes.gen.%s" % modulename
@@ -0,0 +1,212 @@
1
+ import textwrap
2
+ from typing import Dict, List, Set, Tuple
3
+
4
+
5
+ class ImportedNamespaces(object):
6
+ def __init__(self):
7
+ self.data = {}
8
+
9
+ def add(self, name1, name2=None, symbols=None):
10
+ """Adds a namespace will be imported.
11
+
12
+ Examples:
13
+ >>> imports = ImportedNamespaces()
14
+ >>> imports.add('datetime')
15
+ >>> imports.add('ctypes', '*')
16
+ >>> imports.add('decimal', 'Decimal')
17
+ >>> imports.add('GUID', symbols={'GUID': 'comtypes'})
18
+ >>> for name in ('COMMETHOD', 'DISPMETHOD', 'IUnknown', 'dispid',
19
+ ... 'CoClass', 'BSTR', 'DISPPROPERTY'):
20
+ ... imports.add('comtypes', name)
21
+ >>> imports.add('ctypes.wintypes')
22
+ >>> print(imports.getvalue())
23
+ from ctypes import *
24
+ import datetime
25
+ from decimal import Decimal
26
+ from comtypes import (
27
+ BSTR, CoClass, COMMETHOD, dispid, DISPMETHOD, DISPPROPERTY, GUID,
28
+ IUnknown
29
+ )
30
+ import ctypes.wintypes
31
+ >>> assert imports.get_symbols() == {
32
+ ... 'Decimal', 'GUID', 'COMMETHOD', 'DISPMETHOD', 'IUnknown',
33
+ ... 'dispid', 'CoClass', 'BSTR', 'DISPPROPERTY'
34
+ ... }
35
+ """
36
+ if name2 is None:
37
+ import_ = name1
38
+ if not symbols:
39
+ self.data[import_] = None
40
+ return
41
+ from_ = symbols[import_]
42
+ else:
43
+ from_, import_ = name1, name2
44
+ self.data[import_] = from_
45
+
46
+ def __contains__(self, item):
47
+ """Returns item has already added.
48
+
49
+ Examples:
50
+ >>> imports = ImportedNamespaces()
51
+ >>> imports.add('datetime')
52
+ >>> imports.add('ctypes', '*')
53
+ >>> 'datetime' in imports
54
+ True
55
+ >>> ('ctypes', '*') in imports
56
+ True
57
+ >>> 'os' in imports
58
+ False
59
+ >>> 'ctypes' in imports
60
+ False
61
+ >>> ('ctypes', 'c_int') in imports
62
+ False
63
+ """
64
+ if isinstance(item, tuple):
65
+ from_, import_ = item
66
+ else:
67
+ from_, import_ = None, item
68
+ if import_ in self.data:
69
+ return self.data[import_] == from_
70
+ return False
71
+
72
+ def get_symbols(self) -> Set[str]:
73
+ names = set()
74
+ for key, val in self.data.items():
75
+ if val is None or key == "*":
76
+ continue
77
+ names.add(key)
78
+ return names
79
+
80
+ def _make_line(self, from_, imports):
81
+ import_ = ", ".join(imports)
82
+ code = "from %s import %s" % (from_, import_)
83
+ if len(code) <= 80:
84
+ return code
85
+ wrapper = textwrap.TextWrapper(
86
+ subsequent_indent=" ", initial_indent=" ", break_long_words=False
87
+ )
88
+ import_ = "\n".join(wrapper.wrap(import_))
89
+ code = "from %s import (\n%s\n)" % (from_, import_)
90
+ return code
91
+
92
+ def getvalue(self):
93
+ ns = {}
94
+ lines = []
95
+ for key, val in self.data.items():
96
+ if val is None:
97
+ ns[key] = val
98
+ elif key == "*":
99
+ lines.append("from %s import *" % val)
100
+ else:
101
+ ns.setdefault(val, set()).add(key)
102
+ for key, val in ns.items():
103
+ if val is None:
104
+ lines.append("import %s" % key)
105
+ else:
106
+ names = sorted(val, key=lambda s: s.lower())
107
+ lines.append(self._make_line(key, names))
108
+ return "\n".join(lines)
109
+
110
+
111
+ class DeclaredNamespaces(object):
112
+ def __init__(self):
113
+ self.data = {}
114
+
115
+ def add(self, alias, definition, comment=None):
116
+ """Adds a namespace will be declared.
117
+
118
+ Examples:
119
+ >>> declarations = DeclaredNamespaces()
120
+ >>> declarations.add('STRING', 'c_char_p')
121
+ >>> declarations.add('_lcid', '0', 'change this if required')
122
+ >>> print(declarations.getvalue())
123
+ STRING = c_char_p
124
+ _lcid = 0 # change this if required
125
+ >>> assert declarations.get_symbols() == {
126
+ ... 'STRING', '_lcid'
127
+ ... }
128
+ """
129
+ self.data[(alias, definition)] = comment
130
+
131
+ def get_symbols(self) -> Set[str]:
132
+ names = set()
133
+ for alias, _ in self.data.keys():
134
+ names.add(alias)
135
+ return names
136
+
137
+ def getvalue(self):
138
+ lines = []
139
+ for (alias, definition), comment in self.data.items():
140
+ code = "%s = %s" % (alias, definition)
141
+ if comment:
142
+ code = code + " # %s" % comment
143
+ lines.append(code)
144
+ return "\n".join(lines)
145
+
146
+
147
+ class EnumerationNamespaces(object):
148
+ def __init__(self):
149
+ self.data: Dict[str, List[Tuple[str, int]]] = {}
150
+
151
+ def add(self, enum_name: str, member_name: str, value: int) -> None:
152
+ """Adds a namespace will be enumeration and its member.
153
+
154
+ Examples:
155
+ <BLANKLINE> is necessary for doctest
156
+ >>> enums = EnumerationNamespaces()
157
+ >>> assert not enums
158
+ >>> enums.add('Foo', 'ham', 1)
159
+ >>> assert enums
160
+ >>> enums.add('Foo', 'spam', 2)
161
+ >>> enums.add('Bar', 'bacon', 3)
162
+ >>> assert 'Foo' in enums
163
+ >>> assert 'Baz' not in enums
164
+ >>> print(enums.to_intflags())
165
+ class Foo(IntFlag):
166
+ ham = 1
167
+ spam = 2
168
+ <BLANKLINE>
169
+ <BLANKLINE>
170
+ class Bar(IntFlag):
171
+ bacon = 3
172
+ >>> print(enums.to_constants())
173
+ # values for enumeration 'Foo'
174
+ ham = 1
175
+ spam = 2
176
+ Foo = c_int # enum
177
+ <BLANKLINE>
178
+ # values for enumeration 'Bar'
179
+ bacon = 3
180
+ Bar = c_int # enum
181
+ """
182
+ self.data.setdefault(enum_name, []).append((member_name, value))
183
+
184
+ def __contains__(self, item: str) -> bool:
185
+ return item in self.data
186
+
187
+ def __bool__(self) -> bool:
188
+ return bool(self.data)
189
+
190
+ def get_symbols(self) -> Set[str]:
191
+ return set(self.data)
192
+
193
+ def to_constants(self) -> str:
194
+ blocks = []
195
+ for enum_name, enum_members in self.data.items():
196
+ lines = []
197
+ lines.append(f"# values for enumeration '{enum_name}'")
198
+ for n, v in enum_members:
199
+ lines.append(f"{n} = {v}")
200
+ lines.append(f"{enum_name} = c_int # enum")
201
+ blocks.append("\n".join(lines))
202
+ return "\n\n".join(blocks)
203
+
204
+ def to_intflags(self) -> str:
205
+ blocks = []
206
+ for enum_name, enum_members in self.data.items():
207
+ lines = []
208
+ lines.append(f"class {enum_name}(IntFlag):")
209
+ for member_name, value in enum_members:
210
+ lines.append(f" {member_name} = {value}")
211
+ blocks.append("\n".join(lines))
212
+ return "\n\n\n".join(blocks)
@@ -0,0 +1,81 @@
1
+ from comtypes.tools import typedesc
2
+
3
+
4
+ def _calc_packing(struct, fields, pack, isStruct):
5
+ # Try a certain packing, raise PackingError if field offsets,
6
+ # total size ot total alignment is wrong.
7
+ if struct.size is None: # incomplete struct
8
+ return -1
9
+ if struct.name in dont_assert_size:
10
+ return None
11
+ if struct.bases:
12
+ size = struct.bases[0].size
13
+ total_align = struct.bases[0].align
14
+ else:
15
+ size = 0
16
+ total_align = 8 # in bits
17
+ for i, f in enumerate(fields):
18
+ if f.bits: # this code cannot handle bit field sizes.
19
+ # print "##XXX FIXME"
20
+ return -2 # XXX FIXME
21
+ s, a = storage(f.typ)
22
+ if pack is not None:
23
+ a = min(pack, a)
24
+ if size % a:
25
+ size += a - size % a
26
+ if isStruct:
27
+ if size != f.offset:
28
+ raise PackingError("field %s offset (%s/%s)" % (f.name, size, f.offset))
29
+ size += s
30
+ else:
31
+ size = max(size, s)
32
+ total_align = max(total_align, a)
33
+ if total_align != struct.align:
34
+ raise PackingError("total alignment (%s/%s)" % (total_align, struct.align))
35
+ a = total_align
36
+ if pack is not None:
37
+ a = min(pack, a)
38
+ if size % a:
39
+ size += a - size % a
40
+ if size != struct.size:
41
+ raise PackingError("total size (%s/%s)" % (size, struct.size))
42
+
43
+
44
+ def calc_packing(struct, fields):
45
+ # try several packings, starting with unspecified packing
46
+ isStruct = isinstance(struct, typedesc.Structure)
47
+ for pack in [None, 16 * 8, 8 * 8, 4 * 8, 2 * 8, 1 * 8]:
48
+ try:
49
+ _calc_packing(struct, fields, pack, isStruct)
50
+ except PackingError as details:
51
+ continue
52
+ else:
53
+ if pack is None:
54
+ return None
55
+
56
+ return int(pack / 8)
57
+
58
+ raise PackingError("PACKING FAILED: %s" % details)
59
+
60
+
61
+ class PackingError(Exception):
62
+ pass
63
+
64
+
65
+ # XXX These should be filtered out in gccxmlparser.
66
+ dont_assert_size = set(
67
+ [
68
+ "__si_class_type_info_pseudo",
69
+ "__class_type_info_pseudo",
70
+ ]
71
+ )
72
+
73
+
74
+ def storage(t):
75
+ # return the size and alignment of a type
76
+ if isinstance(t, typedesc.Typedef):
77
+ return storage(t.typ)
78
+ elif isinstance(t, typedesc.ArrayType):
79
+ s, a = storage(t.typ)
80
+ return s * (int(t.max) - int(t.min) + 1), a
81
+ return int(t.size), int(t.align)