comtypes 1.4.1__zip → 1.4.3__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 (116) hide show
  1. {comtypes-1.4.1 → comtypes-1.4.3}/CHANGES.txt +24 -1
  2. {comtypes-1.4.1/comtypes.egg-info → comtypes-1.4.3}/PKG-INFO +29 -1
  3. {comtypes-1.4.1 → comtypes-1.4.3}/README.md +28 -0
  4. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/__init__.py +6 -8
  5. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/automation.py +26 -2
  6. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_generate.py +105 -80
  7. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/hints.pyi +29 -2
  8. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_GUID.py +23 -2
  9. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_client.py +14 -4
  10. comtypes-1.4.3/comtypes/test/test_client_regenerate_modules.py +158 -0
  11. comtypes-1.4.3/comtypes/test/test_dispifc_records.py +90 -0
  12. comtypes-1.4.3/comtypes/test/test_findgendir.py +87 -0
  13. comtypes-1.4.3/comtypes/tools/codegenerator/__init__.py +5 -0
  14. {comtypes-1.4.1/comtypes/tools → comtypes-1.4.3/comtypes/tools/codegenerator}/codegenerator.py +140 -716
  15. comtypes-1.4.3/comtypes/tools/codegenerator/helpers.py +357 -0
  16. comtypes-1.4.3/comtypes/tools/codegenerator/modulenamer.py +24 -0
  17. comtypes-1.4.3/comtypes/tools/codegenerator/namespaces.py +212 -0
  18. comtypes-1.4.3/comtypes/tools/codegenerator/packing.py +81 -0
  19. {comtypes-1.4.1/comtypes/tools → comtypes-1.4.3/comtypes/tools/codegenerator}/typeannotator.py +32 -15
  20. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/tlbparser.py +19 -49
  21. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/typedesc.py +58 -10
  22. {comtypes-1.4.1 → comtypes-1.4.3/comtypes.egg-info}/PKG-INFO +29 -1
  23. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/SOURCES.txt +10 -3
  24. {comtypes-1.4.1 → comtypes-1.4.3}/setup.py +1 -0
  25. comtypes-1.4.1/comtypes/test/test_findgendir.py +0 -94
  26. {comtypes-1.4.1 → comtypes-1.4.3}/LICENSE.txt +0 -0
  27. {comtypes-1.4.1 → comtypes-1.4.3}/MANIFEST.in +0 -0
  28. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/GUID.py +0 -0
  29. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_comobject.py +0 -0
  30. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_memberspec.py +0 -0
  31. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_meta.py +0 -0
  32. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_npsupport.py +0 -0
  33. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_safearray.py +0 -0
  34. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/clear_cache.py +0 -0
  35. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/__init__.py +0 -0
  36. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_code_cache.py +0 -0
  37. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_constants.py +0 -0
  38. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_events.py +0 -0
  39. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/dynamic.py +0 -0
  40. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/lazybind.py +0 -0
  41. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/connectionpoints.py +0 -0
  42. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/errorinfo.py +0 -0
  43. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/git.py +0 -0
  44. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/hresult.py +0 -0
  45. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/logutil.py +0 -0
  46. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/messageloop.py +0 -0
  47. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/patcher.py +0 -0
  48. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/persist.py +0 -0
  49. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/safearray.py +0 -0
  50. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/__init__.py +0 -0
  51. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/automation.py +0 -0
  52. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/connectionpoints.py +0 -0
  53. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/inprocserver.py +0 -0
  54. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/localserver.py +0 -0
  55. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/register.py +0 -0
  56. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/w_getopt.py +0 -0
  57. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/shelllink.py +0 -0
  58. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.idl +0 -0
  59. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.py +0 -0
  60. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.tlb +0 -0
  61. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.idl +0 -0
  62. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.py +0 -0
  63. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.tlb +0 -0
  64. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/__init__.py +0 -0
  65. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/find_memleak.py +0 -0
  66. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/mylib.idl +0 -0
  67. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/mytypelib.idl +0 -0
  68. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/runtests.py +0 -0
  69. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/setup.py +0 -0
  70. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_BSTR.py +0 -0
  71. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_DISPPARAMS.py +0 -0
  72. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_QueryService.py +0 -0
  73. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_agilent.py +0 -0
  74. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_avmc.py +0 -0
  75. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_basic.py +0 -0
  76. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_casesensitivity.py +0 -0
  77. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_clear_cache.py +0 -0
  78. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_client_dynamic.py +0 -0
  79. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_collections.py +0 -0
  80. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_comserver.py +0 -0
  81. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_createwrappers.py +0 -0
  82. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dict.py +0 -0
  83. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dispinterface.py +0 -0
  84. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dyndispatch.py +0 -0
  85. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_excel.py +0 -0
  86. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_getactiveobj.py +0 -0
  87. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_ie.py +0 -0
  88. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_ienum.py +0 -0
  89. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_imfattributes.py +0 -0
  90. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_inout_args.py +0 -0
  91. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_jscript.js +0 -0
  92. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_msscript.py +0 -0
  93. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_npsupport.py +0 -0
  94. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_outparam.py +0 -0
  95. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_propputref.py +0 -0
  96. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_pump_events.py +0 -0
  97. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_safearray.py +0 -0
  98. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_sapi.py +0 -0
  99. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_server.py +0 -0
  100. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_showevents.py +0 -0
  101. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_subinterface.py +0 -0
  102. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_typeinfo.py +0 -0
  103. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_urlhistory.py +0 -0
  104. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_variant.py +0 -0
  105. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_win32com_interop.py +0 -0
  106. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_wmi.py +0 -0
  107. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_word.py +0 -0
  108. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/__init__.py +0 -0
  109. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/typedesc_base.py +0 -0
  110. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/typeinfo.py +0 -0
  111. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/util.py +0 -0
  112. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/viewobject.py +0 -0
  113. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/dependency_links.txt +0 -0
  114. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/entry_points.txt +0 -0
  115. {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/top_level.txt +0 -0
  116. {comtypes-1.4.1 → comtypes-1.4.3}/setup.cfg +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,417 +34,45 @@ 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
- elms = (idlflags, type_name, arg_name, default)
212
- code = " (%r, %s, '%s', %r)" % elms
213
- if len(code) > 80:
214
- code = (
215
- " (\n"
216
- " %r,\n"
217
- " %s,\n"
218
- " '%s',\n"
219
- " %r\n"
220
- " )"
221
- ) % elms
222
- else:
223
- elms = (idlflags, type_name, arg_name)
224
- code = " (%r, %s, '%s')" % elms
225
- if len(code) > 80:
226
- code = (
227
- " (\n"
228
- " %r,\n"
229
- " %s,\n"
230
- " '%s',\n"
231
- " )"
232
- ) % elms
233
- return code
234
-
235
-
236
- class ComMethodGenerator(object):
237
- def __init__(self, m: typedesc.ComMethod, isdual: bool) -> None:
238
- self._m = m
239
- self._isdual = isdual
240
- self._stream = io.StringIO()
241
- self._to_type_name = TypeNamer()
242
-
243
- def generate(self):
244
- # () -> str
245
- if not self._m.arguments:
246
- self._make_noargs()
247
- else:
248
- self._make_withargs()
249
- return self._stream.getvalue()
250
-
251
- def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
252
- idlflags: List[_IdlFlagType] = []
253
- if self._isdual:
254
- idlflags.append(dispid(self._m.memid))
255
- idlflags.extend(self._m.idlflags)
256
- else: # We don't include the dispid for non-dispatch COM interfaces
257
- idlflags.extend(self._m.idlflags)
258
- if __debug__ and self._m.doc:
259
- idlflags.insert(1, helpstring(self._m.doc))
260
- type_name = self._to_type_name(self._m.returns)
261
- return (idlflags, type_name, self._m.name)
262
-
263
- def _make_noargs(self) -> None:
264
- elms = self._get_common_elms()
265
- code = " COMMETHOD(%r, %s, '%s')," % elms
266
- if len(code) > 80:
267
- code = (
268
- " COMMETHOD(\n"
269
- " %r,\n"
270
- " %s,\n"
271
- " '%s',\n"
272
- " ),"
273
- ) % elms
274
- print(code, file=self._stream)
275
-
276
- def _make_withargs(self) -> None:
277
- code = (
278
- " COMMETHOD(\n" " %r,\n" " %s,\n" " '%s',"
279
- ) % self._get_common_elms()
280
- print(code, file=self._stream)
281
- arglist = [_to_arg_definition(*i) for i in self._iter_args()]
282
- print(",\n".join(arglist), file=self._stream)
283
- print(" ),", file=self._stream)
284
-
285
- def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
286
- for typ, arg_name, _f, _defval in self._m.arguments:
287
- ###########################################################
288
- # IDL files that contain 'open arrays' or 'conformant
289
- # varying arrays' method parameters are strange.
290
- # These arrays have both a 'size_is()' and
291
- # 'length_is()' attribute, like this example from
292
- # dia2.idl (in the DIA SDK):
293
- #
294
- # interface IDiaSymbol: IUnknown {
295
- # ...
296
- # HRESULT get_dataBytes(
297
- # [in] DWORD cbData,
298
- # [out] DWORD *pcbData,
299
- # [out, size_is(cbData),
300
- # length_is(*pcbData)] BYTE data[]
301
- # );
302
- #
303
- # The really strange thing is that the decompiled type
304
- # library then contains this declaration, which declares
305
- # the interface itself as [out] method parameter:
306
- #
307
- # interface IDiaSymbol: IUnknown {
308
- # ...
309
- # HRESULT _stdcall get_dataBytes(
310
- # [in] unsigned long cbData,
311
- # [out] unsigned long* pcbData,
312
- # [out] IDiaSymbol data);
313
- #
314
- # Of course, comtypes does not accept a COM interface
315
- # as method parameter; so replace the parameter type
316
- # with the comtypes spelling of 'unsigned char *', and
317
- # mark the parameter as [in, out], so the IDL
318
- # equivalent would be like this:
319
- #
320
- # interface IDiaSymbol: IUnknown {
321
- # ...
322
- # HRESULT _stdcall get_dataBytes(
323
- # [in] unsigned long cbData,
324
- # [out] unsigned long* pcbData,
325
- # [in, out] BYTE data[]);
326
- ###########################################################
327
- idlflags = list(_f) # shallow copy to avoid side effects
328
- if isinstance(typ, typedesc.ComInterface):
329
- type_name = "OPENARRAY"
330
- if "in" not in idlflags:
331
- idlflags.append("in")
332
- else:
333
- type_name = self._to_type_name(typ)
334
- if "lcid" in idlflags: # and 'in' in idlflags:
335
- default = lcid
336
- else:
337
- default = _defval
338
- yield (type_name, arg_name, idlflags, default)
339
-
340
-
341
- class DispMethodGenerator(object):
342
- def __init__(self, m: typedesc.DispMethod) -> None:
343
- self._m = m
344
- self._stream = io.StringIO()
345
- self._to_type_name = TypeNamer()
346
-
347
- def generate(self):
348
- # () -> str
349
- if not self._m.arguments:
350
- self._make_noargs()
351
- else:
352
- self._make_withargs()
353
- return self._stream.getvalue()
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
- elms = self._get_common_elms()
366
- code = " DISPMETHOD(%r, %s, '%s')," % elms
367
- if len(code) > 80:
368
- code = (
369
- " DISPMETHOD(\n"
370
- " %r,\n"
371
- " %s,\n"
372
- " '%s',\n"
373
- " ),"
374
- ) % elms
375
- print(code, file=self._stream)
376
-
377
- def _make_withargs(self) -> None:
378
- code = (
379
- " DISPMETHOD(\n" " %r,\n" " %s,\n" " '%s',"
380
- ) % self._get_common_elms()
381
- print(code, file=self._stream)
382
- arglist = [_to_arg_definition(*i) for i in self._iter_args()]
383
- print(",\n".join(arglist), file=self._stream)
384
- print(" ),", file=self._stream)
385
-
386
- def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
387
- for typ, arg_name, idlflags, default in self._m.arguments:
388
- type_name = self._to_type_name(typ)
389
- yield (type_name, arg_name, idlflags, default)
390
-
391
-
392
- class DispPropertyGenerator(object):
393
- def __init__(self, m: typedesc.DispProperty) -> None:
394
- self._m = m
395
- self._to_type_name = TypeNamer()
396
-
397
- def generate(self):
398
- # () -> str
399
- elms = self._get_common_elms()
400
- code = " DISPPROPERTY(%r, %s, '%s')," % elms
401
- if len(code) > 80:
402
- code = (
403
- " DISPPROPERTY(\n"
404
- " %r,\n"
405
- " %s,\n"
406
- " '%s'\n"
407
- " ),"
408
- ) % elms
409
- return code + "\n"
410
-
411
- def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
412
- idlflags: List[_IdlFlagType] = []
413
- idlflags.append(dispid(self._m.dispid))
414
- idlflags.extend(self._m.idlflags)
415
- if __debug__ and self._m.doc:
416
- idlflags.insert(1, helpstring(self._m.doc))
417
- type_name = self._to_type_name(self._m.typ)
418
- return (idlflags, type_name, self._m.name)
37
+ _InterfaceTypeDesc = _UnionT[
38
+ typedesc.ComInterface,
39
+ typedesc.ComInterfaceHead,
40
+ typedesc.ComInterfaceBody,
41
+ typedesc.DispInterface,
42
+ typedesc.DispInterfaceHead,
43
+ typedesc.DispInterfaceBody,
44
+ ]
419
45
 
420
46
 
421
47
  class CodeGenerator(object):
422
- def __init__(self, known_symbols=None):
48
+ def __init__(self, known_symbols=None, known_interfaces=None) -> None:
423
49
  self.stream = io.StringIO()
424
- self.imports = ImportedNamespaces()
425
- self.declarations = DeclaredNamespaces()
426
- self.enums = EnumerationNamespaces()
50
+ self.imports = namespaces.ImportedNamespaces()
51
+ self.declarations = namespaces.DeclaredNamespaces()
52
+ self.enums = namespaces.EnumerationNamespaces()
53
+ self.unnamed_enum_members: List[Tuple[str, int]] = []
427
54
  self._to_type_name = TypeNamer()
428
55
  self.known_symbols = known_symbols or {}
56
+ self.known_interfaces = known_interfaces or {}
429
57
 
430
58
  self.done = set() # type descriptions that have been generated
431
59
  self.names = set() # names that have been generated
432
60
  self.externals = [] # typelibs imported to generated module
433
- self.aliases: Dict[str, str] = {}
61
+ self.enum_aliases: Dict[str, str] = {}
434
62
  self.last_item_class = False
435
63
 
436
64
  def generate(self, item):
437
65
  if item in self.done:
438
66
  return
67
+ if self._is_interface_typedesc(item):
68
+ self._define_interface(item)
69
+ return
439
70
  if isinstance(item, typedesc.StructureHead):
440
71
  name = getattr(item.struct, "name", None)
441
72
  else:
442
73
  name = getattr(item, "name", None)
443
74
  if name in self.known_symbols:
444
75
  self.imports.add(name, symbols=self.known_symbols)
445
-
446
76
  self.done.add(item)
447
77
  if isinstance(item, typedesc.Structure):
448
78
  self.done.add(item.get_head())
@@ -572,6 +202,19 @@ class CodeGenerator(object):
572
202
  print(file=output)
573
203
  print(self.declarations.getvalue(), file=output)
574
204
  print(file=output)
205
+ if self.unnamed_enum_members:
206
+ print("# values for unnamed enumeration", file=output)
207
+ for n, v in self.unnamed_enum_members:
208
+ print(f"{n} = {v}", file=output)
209
+ print(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)
575
218
  print(self.stream.getvalue(), file=output)
576
219
  print(self._make_dunder_all_part(), file=output)
577
220
  print(file=output)
@@ -596,12 +239,12 @@ class CodeGenerator(object):
596
239
  print(self._make_friendly_module_import_part(modname), file=output)
597
240
  print(file=output)
598
241
  print(file=output)
599
- print(self.enums.getvalue(), file=output)
600
- print(file=output)
601
- print(file=output)
602
- enum_aliases = self.enum_aliases
603
- if enum_aliases:
604
- 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():
605
248
  print(f"{k} = {v}", file=output)
606
249
  print(file=output)
607
250
  print(file=output)
@@ -639,10 +282,6 @@ class CodeGenerator(object):
639
282
  part = f"from {modname} import (\n{joined_names}\n)"
640
283
  return part
641
284
 
642
- @property
643
- def enum_aliases(self) -> Dict[str, str]:
644
- return {k: v for k, v in self.aliases.items() if v in self.enums}
645
-
646
285
  def need_VARIANT_imports(self, value):
647
286
  text = repr(value)
648
287
  if "Decimal(" in text:
@@ -667,23 +306,19 @@ class CodeGenerator(object):
667
306
  if keyword.iskeyword(tp.name):
668
307
  # XXX use logging!
669
308
  if __warn_on_munge__:
670
- print("# Fixing keyword as EnumValue for %s" % tp.name)
309
+ print(f"# Fixing keyword as EnumValue for {tp.name}")
671
310
  tp_name = self._to_type_name(tp)
672
- print("%s = %d" % (tp_name, value), file=self.stream)
673
311
  if tp.enumeration.name:
674
312
  self.enums.add(tp.enumeration.name, tp_name, value)
313
+ else:
314
+ self.unnamed_enum_members.append((tp_name, value))
675
315
  self.names.add(tp_name)
676
316
 
677
317
  def Enumeration(self, tp: typedesc.Enumeration) -> None:
678
318
  self.last_item_class = False
679
- if tp.name:
680
- print("# values for enumeration '%s'" % tp.name, file=self.stream)
681
- else:
682
- print("# values for unnamed enumeration", file=self.stream)
683
319
  for item in tp.values:
684
320
  self.generate(item)
685
321
  if tp.name:
686
- print("%s = c_int # enum" % tp.name, file=self.stream)
687
322
  self.names.add(tp.name)
688
323
 
689
324
  def Typedef(self, tp: typedesc.Typedef) -> None:
@@ -697,9 +332,11 @@ class CodeGenerator(object):
697
332
  if definition in self.known_symbols:
698
333
  self.declarations.add(tp.name, definition)
699
334
  else:
700
- print("%s = %s" % (tp.name, definition), file=self.stream)
701
- self.aliases[tp.name] = definition
702
- 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
703
340
  self.names.add(tp.name)
704
341
 
705
342
  def FundamentalType(self, item: typedesc.FundamentalType) -> None:
@@ -823,11 +460,11 @@ class CodeGenerator(object):
823
460
  # on COM interfaces:
824
461
  if not methods:
825
462
  try:
826
- pack = calc_packing(body.struct, fields)
463
+ pack = packing.calc_packing(body.struct, fields)
827
464
  if pack is not None:
828
465
  self.last_item_class = False
829
466
  print("%s._pack_ = %s" % (body.struct.name, pack), file=self.stream)
830
- except PackingError as details:
467
+ except packing.PackingError as details:
831
468
  # if packing fails, write a warning comment to the output.
832
469
  import warnings
833
470
 
@@ -884,7 +521,7 @@ class CodeGenerator(object):
884
521
  "# The size and alignment check for %s is skipped."
885
522
  )
886
523
  print(msg % body.struct.name, file=self.stream)
887
- elif body.struct.name not in dont_assert_size:
524
+ elif body.struct.name not in packing.dont_assert_size:
888
525
  print(file=self.stream)
889
526
  size = body.struct.size // 8
890
527
  print(
@@ -1015,14 +652,14 @@ class CodeGenerator(object):
1015
652
  self.last_item_class = True
1016
653
 
1017
654
  print("class %s(CoClass):" % coclass.name, file=self.stream)
1018
- doc = getattr(coclass, "doc", None)
1019
- if doc:
1020
- print(self._to_docstring(doc), file=self.stream)
655
+ if coclass.doc:
656
+ print(self._to_docstring(coclass.doc), file=self.stream)
1021
657
  print(" _reg_clsid_ = GUID(%r)" % coclass.clsid, file=self.stream)
1022
658
  print(" _idlflags_ = %s" % coclass.idlflags, file=self.stream)
1023
659
  if self.filename is not None:
1024
660
  print(" _typelib_path_ = typelib_path", file=self.stream)
1025
- # 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
1026
663
 
1027
664
  libid = coclass.tlibattr.guid
1028
665
  wMajor, wMinor = coclass.tlibattr.wMajorVerNum, coclass.tlibattr.wMinorVerNum
@@ -1033,23 +670,11 @@ class CodeGenerator(object):
1033
670
  print(file=self.stream)
1034
671
  print(file=self.stream)
1035
672
 
1036
- for itf, idlflags in coclass.interfaces:
673
+ for itf, _ in coclass.interfaces:
1037
674
  self.generate(itf.get_head())
1038
- implemented = []
1039
- sources = []
1040
- for item in coclass.interfaces:
1041
- # item is (interface class, impltypeflags)
1042
- if item[1] & 2: # IMPLTYPEFLAG_FSOURCE
1043
- # source interface
1044
- where = sources
1045
- else:
1046
- # sink interface
1047
- where = implemented
1048
- if item[1] & 1: # IMPLTYPEFLAG_FDEAULT
1049
- # The default interface should be the first item on the list
1050
- where.insert(0, self._to_type_name(item[0]))
1051
- else:
1052
- 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]
1053
678
 
1054
679
  if implemented:
1055
680
  self.last_item_class = False
@@ -1066,11 +691,63 @@ class CodeGenerator(object):
1066
691
 
1067
692
  self.names.add(coclass.name)
1068
693
 
694
+ def _is_interface_typedesc(
695
+ self, item: Any
696
+ ) -> "comtypes.hints.TypeGuard[_InterfaceTypeDesc]":
697
+ return isinstance(
698
+ item,
699
+ (
700
+ typedesc.ComInterface,
701
+ typedesc.ComInterfaceHead,
702
+ typedesc.ComInterfaceBody,
703
+ typedesc.DispInterface,
704
+ typedesc.DispInterfaceHead,
705
+ typedesc.DispInterfaceBody,
706
+ ),
707
+ )
708
+
709
+ def _define_interface(self, item: _InterfaceTypeDesc) -> None:
710
+ if isinstance(
711
+ item,
712
+ (
713
+ typedesc.ComInterfaceHead,
714
+ typedesc.ComInterfaceBody,
715
+ typedesc.DispInterfaceHead,
716
+ typedesc.DispInterfaceBody,
717
+ ),
718
+ ):
719
+ if self._is_known_interface(item.itf):
720
+ self.imports.add(item.itf.name, symbols=self.known_symbols)
721
+ self.done.add(item)
722
+ return
723
+ elif isinstance(item, (typedesc.ComInterface, typedesc.DispInterface)):
724
+ if self._is_known_interface(item):
725
+ self.imports.add(item.name, symbols=self.known_symbols)
726
+ self.done.add(item)
727
+ self.done.add(item.get_head())
728
+ self.done.add(item.get_body())
729
+ return
730
+ else:
731
+ raise TypeError
732
+ self.done.add(item) # to avoid infinite recursion.
733
+ mth = getattr(self, type(item).__name__)
734
+ mth(item)
735
+
1069
736
  def ComInterface(self, itf: typedesc.ComInterface) -> None:
1070
737
  self.generate(itf.get_head())
1071
738
  self.generate(itf.get_body())
1072
739
  self.names.add(itf.name)
1073
740
 
741
+ def _is_known_interface(
742
+ self, item: _UnionT[typedesc.ComInterface, typedesc.DispInterface]
743
+ ) -> bool:
744
+ """Returns whether an interface is statically defined in `comtypes`,
745
+ based on its name and iid.
746
+ """
747
+ if item.name in self.known_interfaces:
748
+ return self.known_interfaces[item.name] == item.iid
749
+ return False
750
+
1074
751
  def _is_enuminterface(self, itf: typedesc.ComInterface) -> bool:
1075
752
  # Check if this is an IEnumXXX interface
1076
753
  if not itf.name.startswith("IEnum"):
@@ -1082,14 +759,11 @@ class CodeGenerator(object):
1082
759
  return True
1083
760
 
1084
761
  def ComInterfaceHead(self, head: typedesc.ComInterfaceHead) -> None:
1085
- if head.itf.name in self.known_symbols:
1086
- return
1087
- base = head.itf.base
1088
762
  if head.itf.base is None:
1089
763
  # we don't beed to generate IUnknown
1090
764
  return
1091
- self.generate(base.get_head())
1092
- self.more.add(base)
765
+ self.generate(head.itf.base.get_head())
766
+ self.more.add(head.itf.base)
1093
767
  basename = self._to_type_name(head.itf.base)
1094
768
 
1095
769
  self.imports.add("comtypes", "GUID")
@@ -1101,9 +775,8 @@ class CodeGenerator(object):
1101
775
  self.last_item_class = True
1102
776
 
1103
777
  print("class %s(%s):" % (head.itf.name, basename), file=self.stream)
1104
- doc = getattr(head.itf, "doc", None)
1105
- if doc:
1106
- print(self._to_docstring(doc), file=self.stream)
778
+ if head.itf.doc:
779
+ print(self._to_docstring(head.itf.doc), file=self.stream)
1107
780
 
1108
781
  print(" _case_insensitive_ = True", file=self.stream)
1109
782
  print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
@@ -1130,11 +803,11 @@ class CodeGenerator(object):
1130
803
  print(" return item", file=self.stream)
1131
804
  print(" raise IndexError(index)", file=self.stream)
1132
805
 
1133
- annotaions = typeannotator.ComInterfaceMembersAnnotator(head.itf).generate()
1134
- if annotaions:
806
+ annotations = typeannotator.ComInterfaceMembersAnnotator(head.itf).generate()
807
+ if annotations:
1135
808
  print(file=self.stream)
1136
809
  print(" if TYPE_CHECKING: # commembers", file=self.stream)
1137
- print(annotaions, file=self.stream, end="")
810
+ print(annotations, file=self.stream)
1138
811
 
1139
812
  print(file=self.stream)
1140
813
  print(file=self.stream)
@@ -1250,19 +923,18 @@ class CodeGenerator(object):
1250
923
  self.last_item_class = True
1251
924
 
1252
925
  print("class %s(%s):" % (head.itf.name, basename), file=self.stream)
1253
- doc = getattr(head.itf, "doc", None)
1254
- if doc:
1255
- print(self._to_docstring(doc), file=self.stream)
926
+ if head.itf.doc:
927
+ print(self._to_docstring(head.itf.doc), file=self.stream)
1256
928
  print(" _case_insensitive_ = True", file=self.stream)
1257
929
  print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
1258
930
  print(" _idlflags_ = %s" % head.itf.idlflags, file=self.stream)
1259
931
  print(" _methods_ = []", file=self.stream)
1260
932
 
1261
- annotaions = typeannotator.DispInterfaceMembersAnnotator(head.itf).generate()
1262
- if annotaions:
933
+ annotations = typeannotator.DispInterfaceMembersAnnotator(head.itf).generate()
934
+ if annotations:
1263
935
  print(file=self.stream)
1264
936
  print(" if TYPE_CHECKING: # dispmembers", file=self.stream)
1265
- print(annotaions, file=self.stream, end="")
937
+ print(annotations, file=self.stream)
1266
938
 
1267
939
  print(file=self.stream)
1268
940
  print(file=self.stream)
@@ -1304,7 +976,7 @@ class CodeGenerator(object):
1304
976
  if __debug__ and m.doc:
1305
977
  self.imports.add("comtypes", "helpstring")
1306
978
  gen = ComMethodGenerator(m, isdual)
1307
- print(gen.generate(), file=self.stream, end="")
979
+ print(gen.generate(), file=self.stream)
1308
980
  self.last_item_class = False
1309
981
  for typ, _, _, default in m.arguments:
1310
982
  if isinstance(typ, typedesc.ComInterface):
@@ -1322,7 +994,7 @@ class CodeGenerator(object):
1322
994
  if __debug__ and m.doc:
1323
995
  self.imports.add("comtypes", "helpstring")
1324
996
  gen = DispMethodGenerator(m)
1325
- print(gen.generate(), file=self.stream, end="")
997
+ print(gen.generate(), file=self.stream)
1326
998
  self.last_item_class = False
1327
999
  for _, _, _, default in m.arguments:
1328
1000
  if default is not None:
@@ -1334,253 +1006,5 @@ class CodeGenerator(object):
1334
1006
  if __debug__ and prop.doc:
1335
1007
  self.imports.add("comtypes", "helpstring")
1336
1008
  gen = DispPropertyGenerator(prop)
1337
- print(gen.generate(), file=self.stream, end="")
1009
+ print(gen.generate(), file=self.stream)
1338
1010
  self.last_item_class = False
1339
-
1340
-
1341
- class TypeNamer(object):
1342
- def __call__(self, t: Any) -> str:
1343
- # Return a string, containing an expression which can be used
1344
- # to refer to the type. Assumes the 'from ctypes import *'
1345
- # namespace is available.
1346
- if isinstance(t, typedesc.SAFEARRAYType):
1347
- return "_midlSAFEARRAY(%s)" % self(t.typ)
1348
- # if isinstance(t, typedesc.CoClass):
1349
- # return "%s._com_interfaces_[0]" % t.name
1350
- if isinstance(t, typedesc.Typedef):
1351
- return t.name
1352
- if isinstance(t, typedesc.PointerType):
1353
- _t, pcnt = self._inspect_PointerType(t)
1354
- return "%s%s%s" % ("POINTER(" * pcnt, self(_t), ")" * pcnt)
1355
- elif isinstance(t, typedesc.ArrayType):
1356
- return "%s * %s" % (self(t.typ), int(t.max) + 1)
1357
- elif isinstance(t, typedesc.FunctionType):
1358
- args = [self(x) for x in [t.returns] + list(t.iterArgTypes())]
1359
- if "__stdcall__" in t.attributes:
1360
- return "WINFUNCTYPE(%s)" % ", ".join(args)
1361
- else:
1362
- return "CFUNCTYPE(%s)" % ", ".join(args)
1363
- elif isinstance(t, typedesc.CvQualifiedType):
1364
- # const and volatile are ignored
1365
- return "%s" % self(t.typ)
1366
- elif isinstance(t, typedesc.FundamentalType):
1367
- return ctypes_names[t.name]
1368
- elif isinstance(t, typedesc.Structure):
1369
- return t.name
1370
- elif isinstance(t, typedesc.Enumeration):
1371
- if t.name:
1372
- return t.name
1373
- return "c_int" # enums are integers
1374
- elif isinstance(t, typedesc.EnumValue):
1375
- if keyword.iskeyword(t.name):
1376
- return t.name + "_"
1377
- return t.name
1378
- elif isinstance(t, typedesc.External):
1379
- # t.symbol_name - symbol to generate
1380
- # t.tlib - the ITypeLib pointer to the typelibrary containing the symbols definition
1381
- modname = name_wrapper_module(t.tlib)
1382
- return "%s.%s" % (modname, t.symbol_name)
1383
- return t.name
1384
-
1385
- def _inspect_PointerType(
1386
- self, t: typedesc.PointerType, count: int = 0
1387
- ) -> Tuple[Any, int]:
1388
- if ASSUME_STRINGS:
1389
- x = get_real_type(t.typ)
1390
- if isinstance(x, typedesc.FundamentalType):
1391
- if x.name == "char":
1392
- return typedesc.Typedef("STRING", x), count
1393
- elif x.name == "wchar_t":
1394
- return typedesc.Typedef("WSTRING", x), count
1395
- if isinstance(t.typ, typedesc.FunctionType):
1396
- return t.typ, count
1397
- if isinstance(t.typ, typedesc.FundamentalType):
1398
- if t.typ.name == "void":
1399
- return typedesc.Typedef("c_void_p", t.typ), count
1400
- if isinstance(t.typ, typedesc.PointerType):
1401
- return self._inspect_PointerType(t.typ, count + 1)
1402
- return t.typ, count + 1
1403
-
1404
-
1405
- class ImportedNamespaces(object):
1406
- def __init__(self):
1407
- self.data = {}
1408
-
1409
- def add(self, name1, name2=None, symbols=None):
1410
- """Adds a namespace will be imported.
1411
-
1412
- Examples:
1413
- >>> imports = ImportedNamespaces()
1414
- >>> imports.add('datetime')
1415
- >>> imports.add('ctypes', '*')
1416
- >>> imports.add('decimal', 'Decimal')
1417
- >>> imports.add('GUID', symbols={'GUID': 'comtypes'})
1418
- >>> for name in ('COMMETHOD', 'DISPMETHOD', 'IUnknown', 'dispid',
1419
- ... 'CoClass', 'BSTR', 'DISPPROPERTY'):
1420
- ... imports.add('comtypes', name)
1421
- >>> imports.add('ctypes.wintypes')
1422
- >>> print(imports.getvalue())
1423
- from ctypes import *
1424
- import datetime
1425
- from decimal import Decimal
1426
- from comtypes import (
1427
- BSTR, CoClass, COMMETHOD, dispid, DISPMETHOD, DISPPROPERTY, GUID,
1428
- IUnknown
1429
- )
1430
- import ctypes.wintypes
1431
- >>> assert imports.get_symbols() == {
1432
- ... 'Decimal', 'GUID', 'COMMETHOD', 'DISPMETHOD', 'IUnknown',
1433
- ... 'dispid', 'CoClass', 'BSTR', 'DISPPROPERTY'
1434
- ... }
1435
- """
1436
- if name2 is None:
1437
- import_ = name1
1438
- if not symbols:
1439
- self.data[import_] = None
1440
- return
1441
- from_ = symbols[import_]
1442
- else:
1443
- from_, import_ = name1, name2
1444
- self.data[import_] = from_
1445
-
1446
- def __contains__(self, item):
1447
- """Returns item has already added.
1448
-
1449
- Examples:
1450
- >>> imports = ImportedNamespaces()
1451
- >>> imports.add('datetime')
1452
- >>> imports.add('ctypes', '*')
1453
- >>> 'datetime' in imports
1454
- True
1455
- >>> ('ctypes', '*') in imports
1456
- True
1457
- >>> 'os' in imports
1458
- False
1459
- >>> 'ctypes' in imports
1460
- False
1461
- >>> ('ctypes', 'c_int') in imports
1462
- False
1463
- """
1464
- if isinstance(item, tuple):
1465
- from_, import_ = item
1466
- else:
1467
- from_, import_ = None, item
1468
- if import_ in self.data:
1469
- return self.data[import_] == from_
1470
- return False
1471
-
1472
- def get_symbols(self) -> Set[str]:
1473
- names = set()
1474
- for key, val in self.data.items():
1475
- if val is None or key == "*":
1476
- continue
1477
- names.add(key)
1478
- return names
1479
-
1480
- def _make_line(self, from_, imports):
1481
- import_ = ", ".join(imports)
1482
- code = "from %s import %s" % (from_, import_)
1483
- if len(code) <= 80:
1484
- return code
1485
- wrapper = textwrap.TextWrapper(
1486
- subsequent_indent=" ", initial_indent=" ", break_long_words=False
1487
- )
1488
- import_ = "\n".join(wrapper.wrap(import_))
1489
- code = "from %s import (\n%s\n)" % (from_, import_)
1490
- return code
1491
-
1492
- def getvalue(self):
1493
- ns = {}
1494
- lines = []
1495
- for key, val in self.data.items():
1496
- if val is None:
1497
- ns[key] = val
1498
- elif key == "*":
1499
- lines.append("from %s import *" % val)
1500
- else:
1501
- ns.setdefault(val, set()).add(key)
1502
- for key, val in ns.items():
1503
- if val is None:
1504
- lines.append("import %s" % key)
1505
- else:
1506
- names = sorted(val, key=lambda s: s.lower())
1507
- lines.append(self._make_line(key, names))
1508
- return "\n".join(lines)
1509
-
1510
-
1511
- class DeclaredNamespaces(object):
1512
- def __init__(self):
1513
- self.data = {}
1514
-
1515
- def add(self, alias, definition, comment=None):
1516
- """Adds a namespace will be declared.
1517
-
1518
- Examples:
1519
- >>> declarations = DeclaredNamespaces()
1520
- >>> declarations.add('STRING', 'c_char_p')
1521
- >>> declarations.add('_lcid', '0', 'change this if required')
1522
- >>> print(declarations.getvalue())
1523
- STRING = c_char_p
1524
- _lcid = 0 # change this if required
1525
- >>> assert declarations.get_symbols() == {
1526
- ... 'STRING', '_lcid'
1527
- ... }
1528
- """
1529
- self.data[(alias, definition)] = comment
1530
-
1531
- def get_symbols(self) -> Set[str]:
1532
- names = set()
1533
- for alias, _ in self.data.keys():
1534
- names.add(alias)
1535
- return names
1536
-
1537
- def getvalue(self):
1538
- lines = []
1539
- for (alias, definition), comment in self.data.items():
1540
- code = "%s = %s" % (alias, definition)
1541
- if comment:
1542
- code = code + " # %s" % comment
1543
- lines.append(code)
1544
- return "\n".join(lines)
1545
-
1546
-
1547
- class EnumerationNamespaces(object):
1548
- def __init__(self):
1549
- self.data: Dict[str, List[Tuple[str, int]]] = {}
1550
-
1551
- def add(self, enum_name: str, member_name: str, value: int) -> None:
1552
- """Adds a namespace will be enumeration and its member.
1553
-
1554
- Examples:
1555
- >>> enums = EnumerationNamespaces()
1556
- >>> enums.add('Foo', 'ham', 1)
1557
- >>> enums.add('Foo', 'spam', 2)
1558
- >>> enums.add('Bar', 'bacon', 3)
1559
- >>> assert 'Foo' in enums
1560
- >>> assert 'Baz' not in enums
1561
- >>> print(enums.getvalue()) # <BLANKLINE> is necessary for doctest
1562
- class Foo(IntFlag):
1563
- ham = 1
1564
- spam = 2
1565
- <BLANKLINE>
1566
- <BLANKLINE>
1567
- class Bar(IntFlag):
1568
- bacon = 3
1569
- """
1570
- self.data.setdefault(enum_name, []).append((member_name, value))
1571
-
1572
- def __contains__(self, item: str) -> bool:
1573
- return item in self.data
1574
-
1575
- def get_symbols(self) -> Set[str]:
1576
- return set(self.data)
1577
-
1578
- def getvalue(self) -> str:
1579
- blocks = []
1580
- for enum_name, enum_members in self.data.items():
1581
- lines = []
1582
- lines.append(f"class {enum_name}(IntFlag):")
1583
- for member_name, value in enum_members:
1584
- lines.append(f" {member_name} = {value}")
1585
- blocks.append("\n".join(lines))
1586
- return "\n\n\n".join(blocks)