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
@@ -1,28 +1,30 @@
1
1
  # Code generator to generate code for everything contained in COM type
2
2
  # libraries.
3
- from __future__ import print_function
4
- import ctypes
5
3
  import keyword
6
4
  import logging
7
5
  import os
8
- import sys
9
6
  import textwrap
10
- from typing import (
11
- Any,
12
- Dict,
13
- Iterator,
14
- List,
15
- Optional,
16
- Sequence,
17
- Set,
18
- Tuple,
19
- Union as _UnionT,
20
- )
7
+ from typing import Any
8
+ from typing import Dict, List, Tuple
9
+ from typing import Sequence
10
+ from typing import Optional, Union as _UnionT
21
11
  import io
22
12
 
23
13
  import comtypes
24
14
  from comtypes import typeinfo
25
- from comtypes.tools import tlbparser, typedesc, typeannotator
15
+ from comtypes.tools import tlbparser, typedesc
16
+ from comtypes.tools.codegenerator import namespaces
17
+ from comtypes.tools.codegenerator import packing
18
+ from comtypes.tools.codegenerator.modulenamer import name_wrapper_module
19
+ from comtypes.tools.codegenerator.helpers import (
20
+ get_real_type,
21
+ ASSUME_STRINGS,
22
+ ComMethodGenerator,
23
+ DispMethodGenerator,
24
+ DispPropertyGenerator,
25
+ TypeNamer,
26
+ )
27
+ from comtypes.tools.codegenerator import typeannotator
26
28
 
27
29
 
28
30
  version = comtypes.__version__
@@ -32,395 +34,6 @@ logger = logging.getLogger(__name__)
32
34
  __warn_on_munge__ = __debug__
33
35
 
34
36
 
35
- class lcid(object):
36
- def __repr__(self):
37
- return "_lcid"
38
-
39
-
40
- lcid = lcid()
41
-
42
-
43
- class dispid(object):
44
- def __init__(self, memid):
45
- self.memid = memid
46
-
47
- def __repr__(self):
48
- return "dispid(%s)" % self.memid
49
-
50
-
51
- class helpstring(object):
52
- def __init__(self, text):
53
- self.text = text
54
-
55
- def __repr__(self):
56
- return "helpstring(%r)" % self.text
57
-
58
-
59
- # XXX Should this be in ctypes itself?
60
- ctypes_names = {
61
- "unsigned char": "c_ubyte",
62
- "signed char": "c_byte",
63
- "char": "c_char",
64
- "wchar_t": "c_wchar",
65
- "short unsigned int": "c_ushort",
66
- "short int": "c_short",
67
- "long unsigned int": "c_ulong",
68
- "long int": "c_long",
69
- "long signed int": "c_long",
70
- "unsigned int": "c_uint",
71
- "int": "c_int",
72
- "long long unsigned int": "c_ulonglong",
73
- "long long int": "c_longlong",
74
- "double": "c_double",
75
- "float": "c_float",
76
- # Hm...
77
- "void": "None",
78
- }
79
-
80
-
81
- def get_real_type(tp):
82
- if type(tp) is typedesc.Typedef:
83
- return get_real_type(tp.typ)
84
- elif isinstance(tp, typedesc.CvQualifiedType):
85
- return get_real_type(tp.typ)
86
- return tp
87
-
88
-
89
- ASSUME_STRINGS = True
90
-
91
-
92
- def _calc_packing(struct, fields, pack, isStruct):
93
- # Try a certain packing, raise PackingError if field offsets,
94
- # total size ot total alignment is wrong.
95
- if struct.size is None: # incomplete struct
96
- return -1
97
- if struct.name in dont_assert_size:
98
- return None
99
- if struct.bases:
100
- size = struct.bases[0].size
101
- total_align = struct.bases[0].align
102
- else:
103
- size = 0
104
- total_align = 8 # in bits
105
- for i, f in enumerate(fields):
106
- if f.bits: # this code cannot handle bit field sizes.
107
- # print "##XXX FIXME"
108
- return -2 # XXX FIXME
109
- s, a = storage(f.typ)
110
- if pack is not None:
111
- a = min(pack, a)
112
- if size % a:
113
- size += a - size % a
114
- if isStruct:
115
- if size != f.offset:
116
- raise PackingError("field %s offset (%s/%s)" % (f.name, size, f.offset))
117
- size += s
118
- else:
119
- size = max(size, s)
120
- total_align = max(total_align, a)
121
- if total_align != struct.align:
122
- raise PackingError("total alignment (%s/%s)" % (total_align, struct.align))
123
- a = total_align
124
- if pack is not None:
125
- a = min(pack, a)
126
- if size % a:
127
- size += a - size % a
128
- if size != struct.size:
129
- raise PackingError("total size (%s/%s)" % (size, struct.size))
130
-
131
-
132
- def calc_packing(struct, fields):
133
- # try several packings, starting with unspecified packing
134
- isStruct = isinstance(struct, typedesc.Structure)
135
- for pack in [None, 16 * 8, 8 * 8, 4 * 8, 2 * 8, 1 * 8]:
136
- try:
137
- _calc_packing(struct, fields, pack, isStruct)
138
- except PackingError as details:
139
- continue
140
- else:
141
- if pack is None:
142
- return None
143
-
144
- return int(pack / 8)
145
-
146
- raise PackingError("PACKING FAILED: %s" % details)
147
-
148
-
149
- class PackingError(Exception):
150
- pass
151
-
152
-
153
- # XXX These should be filtered out in gccxmlparser.
154
- dont_assert_size = set(
155
- [
156
- "__si_class_type_info_pseudo",
157
- "__class_type_info_pseudo",
158
- ]
159
- )
160
-
161
-
162
- def storage(t):
163
- # return the size and alignment of a type
164
- if isinstance(t, typedesc.Typedef):
165
- return storage(t.typ)
166
- elif isinstance(t, typedesc.ArrayType):
167
- s, a = storage(t.typ)
168
- return s * (int(t.max) - int(t.min) + 1), a
169
- return int(t.size), int(t.align)
170
-
171
-
172
- ################################################################
173
-
174
-
175
- def name_wrapper_module(tlib):
176
- """Determine the name of a typelib wrapper module"""
177
- libattr = tlib.GetLibAttr()
178
- modname = "_%s_%s_%s_%s" % (
179
- str(libattr.guid)[1:-1].replace("-", "_"),
180
- libattr.lcid,
181
- libattr.wMajorVerNum,
182
- libattr.wMinorVerNum,
183
- )
184
- return "comtypes.gen.%s" % modname
185
-
186
-
187
- def name_friendly_module(tlib):
188
- """Determine the friendly-name of a typelib module.
189
- If cannot get friendly-name from typelib, returns `None`.
190
- """
191
- try:
192
- modulename = tlib.GetDocumentation(-1)[0]
193
- except comtypes.COMError:
194
- return
195
- return "comtypes.gen.%s" % modulename
196
-
197
-
198
- ################################################################
199
-
200
- _DefValType = _UnionT["lcid", Any, None]
201
- _IdlFlagType = _UnionT[str, dispid, helpstring]
202
-
203
-
204
- def _to_arg_definition(
205
- type_name: str,
206
- arg_name: str,
207
- idlflags: List[str],
208
- default: _DefValType,
209
- ) -> str:
210
- if default is not None:
211
- code = f" ({idlflags!r}, {type_name}, '{arg_name}', {default!r})"
212
- if len(code) > 80:
213
- code = (
214
- " (\n"
215
- f" {idlflags!r},\n"
216
- f" {type_name},\n"
217
- f" '{arg_name}',\n"
218
- f" {default!r}\n"
219
- " )"
220
- )
221
- else:
222
- code = f" ({idlflags!r}, {type_name}, '{arg_name}')"
223
- if len(code) > 80:
224
- code = (
225
- " (\n"
226
- f" {idlflags!r},\n"
227
- f" {type_name},\n"
228
- f" '{arg_name}',\n"
229
- " )"
230
- )
231
- return code
232
-
233
-
234
- class ComMethodGenerator(object):
235
- def __init__(self, m: typedesc.ComMethod, isdual: bool) -> None:
236
- self._m = m
237
- self._isdual = isdual
238
- self.data: List[str] = []
239
- self._to_type_name = TypeNamer()
240
-
241
- def generate(self) -> str:
242
- if not self._m.arguments:
243
- self._make_noargs()
244
- else:
245
- self._make_withargs()
246
- return "\n".join(self.data)
247
-
248
- def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
249
- idlflags: List[_IdlFlagType] = []
250
- if self._isdual:
251
- idlflags.append(dispid(self._m.memid))
252
- idlflags.extend(self._m.idlflags)
253
- else: # We don't include the dispid for non-dispatch COM interfaces
254
- idlflags.extend(self._m.idlflags)
255
- if __debug__ and self._m.doc:
256
- idlflags.insert(1, helpstring(self._m.doc))
257
- type_name = self._to_type_name(self._m.returns)
258
- return (idlflags, type_name, self._m.name)
259
-
260
- def _make_noargs(self) -> None:
261
- flags, type_name, member_name = self._get_common_elms()
262
- code = f" COMMETHOD({flags!r}, {type_name}, '{member_name}'),"
263
- if len(code) > 80:
264
- code = (
265
- " COMMETHOD(\n"
266
- f" {flags!r},\n"
267
- f" {type_name},\n"
268
- f" '{member_name}',\n"
269
- " ),"
270
- )
271
- self.data.append(code)
272
-
273
- def _make_withargs(self) -> None:
274
- flags, type_name, member_name = self._get_common_elms()
275
- code = (
276
- " COMMETHOD(\n"
277
- f" {flags!r},\n"
278
- f" {type_name},\n"
279
- f" '{member_name}',"
280
- )
281
- self.data.append(code)
282
- arglist = [_to_arg_definition(*i) for i in self._iter_args()]
283
- self.data.append(",\n".join(arglist))
284
- self.data.append(" ),")
285
-
286
- def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
287
- for typ, arg_name, _f, _defval in self._m.arguments:
288
- ###########################################################
289
- # IDL files that contain 'open arrays' or 'conformant
290
- # varying arrays' method parameters are strange.
291
- # These arrays have both a 'size_is()' and
292
- # 'length_is()' attribute, like this example from
293
- # dia2.idl (in the DIA SDK):
294
- #
295
- # interface IDiaSymbol: IUnknown {
296
- # ...
297
- # HRESULT get_dataBytes(
298
- # [in] DWORD cbData,
299
- # [out] DWORD *pcbData,
300
- # [out, size_is(cbData),
301
- # length_is(*pcbData)] BYTE data[]
302
- # );
303
- #
304
- # The really strange thing is that the decompiled type
305
- # library then contains this declaration, which declares
306
- # the interface itself as [out] method parameter:
307
- #
308
- # interface IDiaSymbol: IUnknown {
309
- # ...
310
- # HRESULT _stdcall get_dataBytes(
311
- # [in] unsigned long cbData,
312
- # [out] unsigned long* pcbData,
313
- # [out] IDiaSymbol data);
314
- #
315
- # Of course, comtypes does not accept a COM interface
316
- # as method parameter; so replace the parameter type
317
- # with the comtypes spelling of 'unsigned char *', and
318
- # mark the parameter as [in, out], so the IDL
319
- # equivalent would be like this:
320
- #
321
- # interface IDiaSymbol: IUnknown {
322
- # ...
323
- # HRESULT _stdcall get_dataBytes(
324
- # [in] unsigned long cbData,
325
- # [out] unsigned long* pcbData,
326
- # [in, out] BYTE data[]);
327
- ###########################################################
328
- idlflags = list(_f) # shallow copy to avoid side effects
329
- if isinstance(typ, typedesc.ComInterface):
330
- type_name = "OPENARRAY"
331
- if "in" not in idlflags:
332
- idlflags.append("in")
333
- else:
334
- type_name = self._to_type_name(typ)
335
- if "lcid" in idlflags: # and 'in' in idlflags:
336
- default = lcid
337
- else:
338
- default = _defval
339
- yield (type_name, arg_name, idlflags, default)
340
-
341
-
342
- class DispMethodGenerator(object):
343
- def __init__(self, m: typedesc.DispMethod) -> None:
344
- self._m = m
345
- self.data: List[str] = []
346
- self._to_type_name = TypeNamer()
347
-
348
- def generate(self) -> str:
349
- if not self._m.arguments:
350
- self._make_noargs()
351
- else:
352
- self._make_withargs()
353
- return "\n".join(self.data)
354
-
355
- def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
356
- idlflags: List[_IdlFlagType] = []
357
- idlflags.append(dispid(self._m.dispid))
358
- idlflags.extend(self._m.idlflags)
359
- if __debug__ and self._m.doc:
360
- idlflags.insert(1, helpstring(self._m.doc))
361
- type_name = self._to_type_name(self._m.returns)
362
- return (idlflags, type_name, self._m.name)
363
-
364
- def _make_noargs(self) -> None:
365
- flags, type_name, member_name = self._get_common_elms()
366
- code = f" DISPMETHOD({flags!r}, {type_name}, '{member_name}'),"
367
- if len(code) > 80:
368
- code = (
369
- " DISPMETHOD(\n"
370
- f" {flags!r},\n"
371
- f" {type_name},\n"
372
- f" '{member_name}',\n"
373
- " ),"
374
- )
375
- self.data.append(code)
376
-
377
- def _make_withargs(self) -> None:
378
- flags, type_name, member_name = self._get_common_elms()
379
- code = (
380
- " DISPMETHOD(\n"
381
- f" {flags!r},\n"
382
- f" {type_name},\n"
383
- f" '{member_name}',"
384
- )
385
- self.data.append(code)
386
- arglist = [_to_arg_definition(*i) for i in self._iter_args()]
387
- self.data.append(",\n".join(arglist))
388
- self.data.append(" ),")
389
-
390
- def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
391
- for typ, arg_name, idlflags, default in self._m.arguments:
392
- type_name = self._to_type_name(typ)
393
- yield (type_name, arg_name, idlflags, default)
394
-
395
-
396
- class DispPropertyGenerator(object):
397
- def __init__(self, m: typedesc.DispProperty) -> None:
398
- self._m = m
399
- self._to_type_name = TypeNamer()
400
-
401
- def generate(self) -> str:
402
- flags, type_name, member_name = self._get_common_elms()
403
- code = f" DISPPROPERTY({flags!r}, {type_name}, '{member_name}'),"
404
- if len(code) > 80:
405
- code = (
406
- " DISPPROPERTY(\n"
407
- f" {flags!r},\n"
408
- f" {type_name},\n"
409
- f" '{member_name}'\n"
410
- " ),"
411
- )
412
- return code
413
-
414
- def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
415
- idlflags: List[_IdlFlagType] = []
416
- idlflags.append(dispid(self._m.dispid))
417
- idlflags.extend(self._m.idlflags)
418
- if __debug__ and self._m.doc:
419
- idlflags.insert(1, helpstring(self._m.doc))
420
- type_name = self._to_type_name(self._m.typ)
421
- return (idlflags, type_name, self._m.name)
422
-
423
-
424
37
  _InterfaceTypeDesc = _UnionT[
425
38
  typedesc.ComInterface,
426
39
  typedesc.ComInterfaceHead,
@@ -434,9 +47,9 @@ _InterfaceTypeDesc = _UnionT[
434
47
  class CodeGenerator(object):
435
48
  def __init__(self, known_symbols=None, known_interfaces=None) -> None:
436
49
  self.stream = io.StringIO()
437
- self.imports = ImportedNamespaces()
438
- self.declarations = DeclaredNamespaces()
439
- self.enums = EnumerationNamespaces()
50
+ self.imports = namespaces.ImportedNamespaces()
51
+ self.declarations = namespaces.DeclaredNamespaces()
52
+ self.enums = namespaces.EnumerationNamespaces()
440
53
  self.unnamed_enum_members: List[Tuple[str, int]] = []
441
54
  self._to_type_name = TypeNamer()
442
55
  self.known_symbols = known_symbols or {}
@@ -445,7 +58,7 @@ class CodeGenerator(object):
445
58
  self.done = set() # type descriptions that have been generated
446
59
  self.names = set() # names that have been generated
447
60
  self.externals = [] # typelibs imported to generated module
448
- self.aliases: Dict[str, str] = {}
61
+ self.enum_aliases: Dict[str, str] = {}
449
62
  self.last_item_class = False
450
63
 
451
64
  def generate(self, item):
@@ -594,7 +207,14 @@ class CodeGenerator(object):
594
207
  for n, v in self.unnamed_enum_members:
595
208
  print(f"{n} = {v}", file=output)
596
209
  print(file=output)
597
- print(self.enums.to_constants(), file=output)
210
+ if self.enums:
211
+ print(self.enums.to_constants(), file=output)
212
+ print(file=output)
213
+ if self.enum_aliases:
214
+ print("# aliases for enums", file=output)
215
+ for k, v in self.enum_aliases.items():
216
+ print(f"{k} = {v}", file=output)
217
+ print(file=output)
598
218
  print(self.stream.getvalue(), file=output)
599
219
  print(self._make_dunder_all_part(), file=output)
600
220
  print(file=output)
@@ -619,12 +239,12 @@ class CodeGenerator(object):
619
239
  print(self._make_friendly_module_import_part(modname), file=output)
620
240
  print(file=output)
621
241
  print(file=output)
622
- print(self.enums.to_intflags(), file=output)
623
- print(file=output)
624
- print(file=output)
625
- enum_aliases = self.enum_aliases
626
- if enum_aliases:
627
- for k, v in enum_aliases.items():
242
+ if self.enums:
243
+ print(self.enums.to_intflags(), file=output)
244
+ print(file=output)
245
+ print(file=output)
246
+ if self.enum_aliases:
247
+ for k, v in self.enum_aliases.items():
628
248
  print(f"{k} = {v}", file=output)
629
249
  print(file=output)
630
250
  print(file=output)
@@ -662,10 +282,6 @@ class CodeGenerator(object):
662
282
  part = f"from {modname} import (\n{joined_names}\n)"
663
283
  return part
664
284
 
665
- @property
666
- def enum_aliases(self) -> Dict[str, str]:
667
- return {k: v for k, v in self.aliases.items() if v in self.enums}
668
-
669
285
  def need_VARIANT_imports(self, value):
670
286
  text = repr(value)
671
287
  if "Decimal(" in text:
@@ -690,7 +306,7 @@ class CodeGenerator(object):
690
306
  if keyword.iskeyword(tp.name):
691
307
  # XXX use logging!
692
308
  if __warn_on_munge__:
693
- print("# Fixing keyword as EnumValue for %s" % tp.name)
309
+ print(f"# Fixing keyword as EnumValue for {tp.name}")
694
310
  tp_name = self._to_type_name(tp)
695
311
  if tp.enumeration.name:
696
312
  self.enums.add(tp.enumeration.name, tp_name, value)
@@ -716,9 +332,11 @@ class CodeGenerator(object):
716
332
  if definition in self.known_symbols:
717
333
  self.declarations.add(tp.name, definition)
718
334
  else:
719
- print("%s = %s" % (tp.name, definition), file=self.stream)
720
- self.aliases[tp.name] = definition
721
- self.last_item_class = False
335
+ if isinstance(tp.typ, typedesc.Enumeration):
336
+ self.enum_aliases[tp.name] = definition
337
+ else:
338
+ print(f"{tp.name} = {definition}", file=self.stream)
339
+ self.last_item_class = False
722
340
  self.names.add(tp.name)
723
341
 
724
342
  def FundamentalType(self, item: typedesc.FundamentalType) -> None:
@@ -842,11 +460,11 @@ class CodeGenerator(object):
842
460
  # on COM interfaces:
843
461
  if not methods:
844
462
  try:
845
- pack = calc_packing(body.struct, fields)
463
+ pack = packing.calc_packing(body.struct, fields)
846
464
  if pack is not None:
847
465
  self.last_item_class = False
848
466
  print("%s._pack_ = %s" % (body.struct.name, pack), file=self.stream)
849
- except PackingError as details:
467
+ except packing.PackingError as details:
850
468
  # if packing fails, write a warning comment to the output.
851
469
  import warnings
852
470
 
@@ -903,7 +521,7 @@ class CodeGenerator(object):
903
521
  "# The size and alignment check for %s is skipped."
904
522
  )
905
523
  print(msg % body.struct.name, file=self.stream)
906
- elif body.struct.name not in dont_assert_size:
524
+ elif body.struct.name not in packing.dont_assert_size:
907
525
  print(file=self.stream)
908
526
  size = body.struct.size // 8
909
527
  print(
@@ -1034,14 +652,14 @@ class CodeGenerator(object):
1034
652
  self.last_item_class = True
1035
653
 
1036
654
  print("class %s(CoClass):" % coclass.name, file=self.stream)
1037
- doc = getattr(coclass, "doc", None)
1038
- if doc:
1039
- print(self._to_docstring(doc), file=self.stream)
655
+ if coclass.doc:
656
+ print(self._to_docstring(coclass.doc), file=self.stream)
1040
657
  print(" _reg_clsid_ = GUID(%r)" % coclass.clsid, file=self.stream)
1041
658
  print(" _idlflags_ = %s" % coclass.idlflags, file=self.stream)
1042
659
  if self.filename is not None:
1043
660
  print(" _typelib_path_ = typelib_path", file=self.stream)
1044
- # X print >> self.stream, "POINTER(%s).__ctypes_from_outparam__ = wrap" % coclass.name
661
+ # X print
662
+ # >> self.stream, "POINTER(%s).__ctypes_from_outparam__ = wrap" % coclass.name
1045
663
 
1046
664
  libid = coclass.tlibattr.guid
1047
665
  wMajor, wMinor = coclass.tlibattr.wMajorVerNum, coclass.tlibattr.wMinorVerNum
@@ -1052,23 +670,11 @@ class CodeGenerator(object):
1052
670
  print(file=self.stream)
1053
671
  print(file=self.stream)
1054
672
 
1055
- for itf, idlflags in coclass.interfaces:
673
+ for itf, _ in coclass.interfaces:
1056
674
  self.generate(itf.get_head())
1057
- implemented = []
1058
- sources = []
1059
- for item in coclass.interfaces:
1060
- # item is (interface class, impltypeflags)
1061
- if item[1] & 2: # IMPLTYPEFLAG_FSOURCE
1062
- # source interface
1063
- where = sources
1064
- else:
1065
- # sink interface
1066
- where = implemented
1067
- if item[1] & 1: # IMPLTYPEFLAG_FDEAULT
1068
- # The default interface should be the first item on the list
1069
- where.insert(0, self._to_type_name(item[0]))
1070
- else:
1071
- where.append(self._to_type_name(item[0]))
675
+ impl, src = typedesc.groupby_impltypeflags(coclass.interfaces)
676
+ implemented = [self._to_type_name(itf) for itf in impl]
677
+ sources = [self._to_type_name(itf) for itf in src]
1072
678
 
1073
679
  if implemented:
1074
680
  self.last_item_class = False
@@ -1169,9 +775,8 @@ class CodeGenerator(object):
1169
775
  self.last_item_class = True
1170
776
 
1171
777
  print("class %s(%s):" % (head.itf.name, basename), file=self.stream)
1172
- doc = getattr(head.itf, "doc", None)
1173
- if doc:
1174
- print(self._to_docstring(doc), file=self.stream)
778
+ if head.itf.doc:
779
+ print(self._to_docstring(head.itf.doc), file=self.stream)
1175
780
 
1176
781
  print(" _case_insensitive_ = True", file=self.stream)
1177
782
  print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
@@ -1318,9 +923,8 @@ class CodeGenerator(object):
1318
923
  self.last_item_class = True
1319
924
 
1320
925
  print("class %s(%s):" % (head.itf.name, basename), file=self.stream)
1321
- doc = getattr(head.itf, "doc", None)
1322
- if doc:
1323
- print(self._to_docstring(doc), file=self.stream)
926
+ if head.itf.doc:
927
+ print(self._to_docstring(head.itf.doc), file=self.stream)
1324
928
  print(" _case_insensitive_ = True", file=self.stream)
1325
929
  print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
1326
930
  print(" _idlflags_ = %s" % head.itf.idlflags, file=self.stream)
@@ -1404,272 +1008,3 @@ class CodeGenerator(object):
1404
1008
  gen = DispPropertyGenerator(prop)
1405
1009
  print(gen.generate(), file=self.stream)
1406
1010
  self.last_item_class = False
1407
-
1408
-
1409
- class TypeNamer(object):
1410
- def __call__(self, t: Any) -> str:
1411
- # Return a string, containing an expression which can be used
1412
- # to refer to the type. Assumes the 'from ctypes import *'
1413
- # namespace is available.
1414
- if isinstance(t, typedesc.SAFEARRAYType):
1415
- return "_midlSAFEARRAY(%s)" % self(t.typ)
1416
- # if isinstance(t, typedesc.CoClass):
1417
- # return "%s._com_interfaces_[0]" % t.name
1418
- if isinstance(t, typedesc.Typedef):
1419
- return t.name
1420
- if isinstance(t, typedesc.PointerType):
1421
- _t, pcnt = self._inspect_PointerType(t)
1422
- return "%s%s%s" % ("POINTER(" * pcnt, self(_t), ")" * pcnt)
1423
- elif isinstance(t, typedesc.ArrayType):
1424
- return "%s * %s" % (self(t.typ), int(t.max) + 1)
1425
- elif isinstance(t, typedesc.FunctionType):
1426
- args = [self(x) for x in [t.returns] + list(t.iterArgTypes())]
1427
- if "__stdcall__" in t.attributes:
1428
- return "WINFUNCTYPE(%s)" % ", ".join(args)
1429
- else:
1430
- return "CFUNCTYPE(%s)" % ", ".join(args)
1431
- elif isinstance(t, typedesc.CvQualifiedType):
1432
- # const and volatile are ignored
1433
- return "%s" % self(t.typ)
1434
- elif isinstance(t, typedesc.FundamentalType):
1435
- return ctypes_names[t.name]
1436
- elif isinstance(t, typedesc.Structure):
1437
- return t.name
1438
- elif isinstance(t, typedesc.Enumeration):
1439
- if t.name:
1440
- return t.name
1441
- return "c_int" # enums are integers
1442
- elif isinstance(t, typedesc.EnumValue):
1443
- if keyword.iskeyword(t.name):
1444
- return t.name + "_"
1445
- return t.name
1446
- elif isinstance(t, typedesc.External):
1447
- # t.symbol_name - symbol to generate
1448
- # t.tlib - the ITypeLib pointer to the typelibrary containing the symbols definition
1449
- modname = name_wrapper_module(t.tlib)
1450
- return "%s.%s" % (modname, t.symbol_name)
1451
- return t.name
1452
-
1453
- def _inspect_PointerType(
1454
- self, t: typedesc.PointerType, count: int = 0
1455
- ) -> Tuple[Any, int]:
1456
- if ASSUME_STRINGS:
1457
- x = get_real_type(t.typ)
1458
- if isinstance(x, typedesc.FundamentalType):
1459
- if x.name == "char":
1460
- return typedesc.Typedef("STRING", x), count
1461
- elif x.name == "wchar_t":
1462
- return typedesc.Typedef("WSTRING", x), count
1463
- if isinstance(t.typ, typedesc.FunctionType):
1464
- return t.typ, count
1465
- if isinstance(t.typ, typedesc.FundamentalType):
1466
- if t.typ.name == "void":
1467
- return typedesc.Typedef("c_void_p", t.typ), count
1468
- if isinstance(t.typ, typedesc.PointerType):
1469
- return self._inspect_PointerType(t.typ, count + 1)
1470
- return t.typ, count + 1
1471
-
1472
-
1473
- class ImportedNamespaces(object):
1474
- def __init__(self):
1475
- self.data = {}
1476
-
1477
- def add(self, name1, name2=None, symbols=None):
1478
- """Adds a namespace will be imported.
1479
-
1480
- Examples:
1481
- >>> imports = ImportedNamespaces()
1482
- >>> imports.add('datetime')
1483
- >>> imports.add('ctypes', '*')
1484
- >>> imports.add('decimal', 'Decimal')
1485
- >>> imports.add('GUID', symbols={'GUID': 'comtypes'})
1486
- >>> for name in ('COMMETHOD', 'DISPMETHOD', 'IUnknown', 'dispid',
1487
- ... 'CoClass', 'BSTR', 'DISPPROPERTY'):
1488
- ... imports.add('comtypes', name)
1489
- >>> imports.add('ctypes.wintypes')
1490
- >>> print(imports.getvalue())
1491
- from ctypes import *
1492
- import datetime
1493
- from decimal import Decimal
1494
- from comtypes import (
1495
- BSTR, CoClass, COMMETHOD, dispid, DISPMETHOD, DISPPROPERTY, GUID,
1496
- IUnknown
1497
- )
1498
- import ctypes.wintypes
1499
- >>> assert imports.get_symbols() == {
1500
- ... 'Decimal', 'GUID', 'COMMETHOD', 'DISPMETHOD', 'IUnknown',
1501
- ... 'dispid', 'CoClass', 'BSTR', 'DISPPROPERTY'
1502
- ... }
1503
- """
1504
- if name2 is None:
1505
- import_ = name1
1506
- if not symbols:
1507
- self.data[import_] = None
1508
- return
1509
- from_ = symbols[import_]
1510
- else:
1511
- from_, import_ = name1, name2
1512
- self.data[import_] = from_
1513
-
1514
- def __contains__(self, item):
1515
- """Returns item has already added.
1516
-
1517
- Examples:
1518
- >>> imports = ImportedNamespaces()
1519
- >>> imports.add('datetime')
1520
- >>> imports.add('ctypes', '*')
1521
- >>> 'datetime' in imports
1522
- True
1523
- >>> ('ctypes', '*') in imports
1524
- True
1525
- >>> 'os' in imports
1526
- False
1527
- >>> 'ctypes' in imports
1528
- False
1529
- >>> ('ctypes', 'c_int') in imports
1530
- False
1531
- """
1532
- if isinstance(item, tuple):
1533
- from_, import_ = item
1534
- else:
1535
- from_, import_ = None, item
1536
- if import_ in self.data:
1537
- return self.data[import_] == from_
1538
- return False
1539
-
1540
- def get_symbols(self) -> Set[str]:
1541
- names = set()
1542
- for key, val in self.data.items():
1543
- if val is None or key == "*":
1544
- continue
1545
- names.add(key)
1546
- return names
1547
-
1548
- def _make_line(self, from_, imports):
1549
- import_ = ", ".join(imports)
1550
- code = "from %s import %s" % (from_, import_)
1551
- if len(code) <= 80:
1552
- return code
1553
- wrapper = textwrap.TextWrapper(
1554
- subsequent_indent=" ", initial_indent=" ", break_long_words=False
1555
- )
1556
- import_ = "\n".join(wrapper.wrap(import_))
1557
- code = "from %s import (\n%s\n)" % (from_, import_)
1558
- return code
1559
-
1560
- def getvalue(self):
1561
- ns = {}
1562
- lines = []
1563
- for key, val in self.data.items():
1564
- if val is None:
1565
- ns[key] = val
1566
- elif key == "*":
1567
- lines.append("from %s import *" % val)
1568
- else:
1569
- ns.setdefault(val, set()).add(key)
1570
- for key, val in ns.items():
1571
- if val is None:
1572
- lines.append("import %s" % key)
1573
- else:
1574
- names = sorted(val, key=lambda s: s.lower())
1575
- lines.append(self._make_line(key, names))
1576
- return "\n".join(lines)
1577
-
1578
-
1579
- class DeclaredNamespaces(object):
1580
- def __init__(self):
1581
- self.data = {}
1582
-
1583
- def add(self, alias, definition, comment=None):
1584
- """Adds a namespace will be declared.
1585
-
1586
- Examples:
1587
- >>> declarations = DeclaredNamespaces()
1588
- >>> declarations.add('STRING', 'c_char_p')
1589
- >>> declarations.add('_lcid', '0', 'change this if required')
1590
- >>> print(declarations.getvalue())
1591
- STRING = c_char_p
1592
- _lcid = 0 # change this if required
1593
- >>> assert declarations.get_symbols() == {
1594
- ... 'STRING', '_lcid'
1595
- ... }
1596
- """
1597
- self.data[(alias, definition)] = comment
1598
-
1599
- def get_symbols(self) -> Set[str]:
1600
- names = set()
1601
- for alias, _ in self.data.keys():
1602
- names.add(alias)
1603
- return names
1604
-
1605
- def getvalue(self):
1606
- lines = []
1607
- for (alias, definition), comment in self.data.items():
1608
- code = "%s = %s" % (alias, definition)
1609
- if comment:
1610
- code = code + " # %s" % comment
1611
- lines.append(code)
1612
- return "\n".join(lines)
1613
-
1614
-
1615
- class EnumerationNamespaces(object):
1616
- def __init__(self):
1617
- self.data: Dict[str, List[Tuple[str, int]]] = {}
1618
-
1619
- def add(self, enum_name: str, member_name: str, value: int) -> None:
1620
- """Adds a namespace will be enumeration and its member.
1621
-
1622
- Examples:
1623
- <BLANKLINE> is necessary for doctest
1624
- >>> enums = EnumerationNamespaces()
1625
- >>> enums.add('Foo', 'ham', 1)
1626
- >>> enums.add('Foo', 'spam', 2)
1627
- >>> enums.add('Bar', 'bacon', 3)
1628
- >>> assert 'Foo' in enums
1629
- >>> assert 'Baz' not in enums
1630
- >>> print(enums.to_intflags())
1631
- class Foo(IntFlag):
1632
- ham = 1
1633
- spam = 2
1634
- <BLANKLINE>
1635
- <BLANKLINE>
1636
- class Bar(IntFlag):
1637
- bacon = 3
1638
- >>> print(enums.to_constants())
1639
- # values for enumeration 'Foo'
1640
- ham = 1
1641
- spam = 2
1642
- Foo = c_int # enum
1643
- <BLANKLINE>
1644
- # values for enumeration 'Bar'
1645
- bacon = 3
1646
- Bar = c_int # enum
1647
- """
1648
- self.data.setdefault(enum_name, []).append((member_name, value))
1649
-
1650
- def __contains__(self, item: str) -> bool:
1651
- return item in self.data
1652
-
1653
- def get_symbols(self) -> Set[str]:
1654
- return set(self.data)
1655
-
1656
- def to_constants(self) -> str:
1657
- blocks = []
1658
- for enum_name, enum_members in self.data.items():
1659
- lines = []
1660
- lines.append(f"# values for enumeration '{enum_name}'")
1661
- for n, v in enum_members:
1662
- lines.append(f"{n} = {v}")
1663
- lines.append(f"{enum_name} = c_int # enum")
1664
- blocks.append("\n".join(lines))
1665
- return "\n\n".join(blocks)
1666
-
1667
- def to_intflags(self) -> str:
1668
- blocks = []
1669
- for enum_name, enum_members in self.data.items():
1670
- lines = []
1671
- lines.append(f"class {enum_name}(IntFlag):")
1672
- for member_name, value in enum_members:
1673
- lines.append(f" {member_name} = {value}")
1674
- blocks.append("\n".join(lines))
1675
- return "\n\n\n".join(blocks)