comtypes 1.4.7__zip → 1.4.8__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 (138) hide show
  1. {comtypes-1.4.7 → comtypes-1.4.8}/CHANGES.txt +18 -0
  2. {comtypes-1.4.7/comtypes.egg-info → comtypes-1.4.8}/PKG-INFO +5 -3
  3. {comtypes-1.4.7 → comtypes-1.4.8}/README.md +4 -2
  4. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/__init__.py +1 -1
  5. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_comobject.py +0 -1
  6. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_memberspec.py +1 -1
  7. comtypes-1.4.8/comtypes/_meta.py +95 -0
  8. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_npsupport.py +2 -1
  9. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_post_coinit/__init__.py +1 -0
  10. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_post_coinit/misc.py +20 -39
  11. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_post_coinit/unknwn.py +94 -69
  12. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/client/__init__.py +21 -31
  13. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/client/_code_cache.py +1 -0
  14. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/client/_events.py +0 -1
  15. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/client/_generate.py +5 -5
  16. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/client/lazybind.py +0 -5
  17. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/git.py +1 -0
  18. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/hints.pyi +4 -4
  19. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/persist.py +7 -7
  20. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/safearray.py +2 -6
  21. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/server/__init__.py +1 -0
  22. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/server/register.py +1 -0
  23. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/shelllink.py +48 -43
  24. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/TestComServer.py +1 -1
  25. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/TestDispServer.py +1 -1
  26. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/__init__.py +0 -1
  27. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/find_memleak.py +0 -1
  28. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_agilent.py +0 -1
  29. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_clear_cache.py +1 -0
  30. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_createwrappers.py +0 -2
  31. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_dispinterface.py +0 -1
  32. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_excel.py +0 -1
  33. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_inout_args.py +1 -1
  34. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_server.py +6 -0
  35. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_shelllink.py +10 -14
  36. comtypes-1.4.8/comtypes/test/test_stream.py +131 -0
  37. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_typeannotator.py +1 -1
  38. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_urlhistory.py +1 -0
  39. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_variant.py +0 -2
  40. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/codegenerator/namespaces.py +97 -27
  41. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/codegenerator/typeannotator.py +2 -4
  42. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/tlbparser.py +33 -32
  43. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/typedesc.py +2 -2
  44. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/typeinfo.py +21 -25
  45. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/util.py +1 -0
  46. {comtypes-1.4.7 → comtypes-1.4.8/comtypes.egg-info}/PKG-INFO +5 -3
  47. comtypes-1.4.8/pyproject.toml +54 -0
  48. comtypes-1.4.7/comtypes/_meta.py +0 -70
  49. comtypes-1.4.7/comtypes/test/test_stream.py +0 -53
  50. comtypes-1.4.7/pyproject.toml +0 -3
  51. {comtypes-1.4.7 → comtypes-1.4.8}/LICENSE.txt +0 -0
  52. {comtypes-1.4.7 → comtypes-1.4.8}/MANIFEST.in +0 -0
  53. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/GUID.py +0 -0
  54. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_idl_stuff.py +0 -0
  55. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_post_coinit/bstr.py +0 -0
  56. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_py_instance_method.py +0 -0
  57. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_safearray.py +0 -0
  58. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/_tlib_version_checker.py +0 -0
  59. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/automation.py +0 -0
  60. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/clear_cache.py +0 -0
  61. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/client/_constants.py +0 -0
  62. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/client/dynamic.py +0 -0
  63. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/connectionpoints.py +0 -0
  64. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/errorinfo.py +0 -0
  65. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/hresult.py +0 -0
  66. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/logutil.py +0 -0
  67. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/messageloop.py +0 -0
  68. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/patcher.py +0 -0
  69. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/server/automation.py +0 -0
  70. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/server/connectionpoints.py +0 -0
  71. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/server/inprocserver.py +0 -0
  72. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/server/localserver.py +0 -0
  73. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/server/w_getopt.py +0 -0
  74. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/stream.py +0 -0
  75. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/TestComServer.idl +0 -0
  76. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/TestComServer.tlb +0 -0
  77. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/TestDispServer.idl +0 -0
  78. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/TestDispServer.tlb +0 -0
  79. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/mylib.idl +0 -0
  80. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/mylib.tlb +0 -0
  81. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/mytypelib.idl +0 -0
  82. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/runtests.py +0 -0
  83. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/setup.py +0 -0
  84. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_BSTR.py +0 -0
  85. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_DISPPARAMS.py +0 -0
  86. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_GUID.py +0 -0
  87. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_QueryService.py +0 -0
  88. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_avmc.py +0 -0
  89. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_basic.py +0 -0
  90. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_casesensitivity.py +0 -0
  91. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_client.py +0 -0
  92. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_client_dynamic.py +0 -0
  93. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_client_regenerate_modules.py +0 -0
  94. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_collections.py +0 -0
  95. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_comserver.py +0 -0
  96. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_dict.py +0 -0
  97. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_dispifc_records.py +0 -0
  98. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_dispifc_safearrays.py +0 -0
  99. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_dyndispatch.py +0 -0
  100. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_findgendir.py +0 -0
  101. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_getactiveobj.py +0 -0
  102. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_ie.py +0 -0
  103. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_ienum.py +0 -0
  104. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_imfattributes.py +0 -0
  105. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_jscript.js +0 -0
  106. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_midl_safearray_create.py +0 -0
  107. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_monikers.py +0 -0
  108. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_msscript.py +0 -0
  109. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_npsupport.py +0 -0
  110. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_outparam.py +0 -0
  111. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_persist.py +0 -0
  112. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_propputref.py +0 -0
  113. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_pump_events.py +0 -0
  114. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_recordinfo.py +0 -0
  115. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_safearray.py +0 -0
  116. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_sapi.py +0 -0
  117. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_showevents.py +0 -0
  118. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_storage.py +0 -0
  119. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_subinterface.py +0 -0
  120. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_typeinfo.py +0 -0
  121. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_win32com_interop.py +0 -0
  122. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_wmi.py +0 -0
  123. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/test_word.py +0 -0
  124. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/test/urlhist.tlb +0 -0
  125. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/__init__.py +0 -0
  126. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/codegenerator/__init__.py +0 -0
  127. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/codegenerator/codegenerator.py +0 -0
  128. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/codegenerator/helpers.py +0 -0
  129. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  130. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/codegenerator/packing.py +0 -0
  131. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/tools/typedesc_base.py +0 -0
  132. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes/viewobject.py +0 -0
  133. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes.egg-info/SOURCES.txt +0 -0
  134. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes.egg-info/dependency_links.txt +0 -0
  135. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes.egg-info/entry_points.txt +0 -0
  136. {comtypes-1.4.7 → comtypes-1.4.8}/comtypes.egg-info/top_level.txt +0 -0
  137. {comtypes-1.4.7 → comtypes-1.4.8}/setup.cfg +0 -0
  138. {comtypes-1.4.7 → comtypes-1.4.8}/setup.py +0 -0
@@ -1,12 +1,28 @@
1
+ from collections import Counter
1
2
  import textwrap
3
+ from typing import overload
4
+ from typing import Optional, Union as _UnionT
2
5
  from typing import Dict, List, Set, Tuple
6
+ from typing import Iterator, Mapping, Sequence
7
+ import warnings
3
8
 
4
9
 
5
10
  class ImportedNamespaces(object):
6
- def __init__(self):
7
- self.data = {}
11
+ def __init__(self) -> None:
12
+ self.data: Dict[str, Optional[str]] = {}
8
13
 
9
- def add(self, name1, name2=None, symbols=None):
14
+ @overload
15
+ def add(self, modulename: str, /) -> None: ...
16
+ @overload
17
+ def add(self, modulename: str, symbolname: str, /) -> None: ...
18
+ @overload
19
+ def add(self, symbolname: str, /, *, symbols: Mapping[str, str]) -> None: ...
20
+ def add(
21
+ self,
22
+ name1: str,
23
+ name2: Optional[str] = None,
24
+ symbols: Optional[Mapping[str, str]] = None,
25
+ ) -> None:
10
26
  """Adds a namespace will be imported.
11
27
 
12
28
  Examples:
@@ -43,7 +59,7 @@ class ImportedNamespaces(object):
43
59
  from_, import_ = name1, name2
44
60
  self.data[import_] = from_
45
61
 
46
- def __contains__(self, item):
62
+ def __contains__(self, item: _UnionT[str, Tuple[str, str]]) -> bool:
47
63
  """Returns item has already added.
48
64
 
49
65
  Examples:
@@ -77,31 +93,31 @@ class ImportedNamespaces(object):
77
93
  names.add(key)
78
94
  return names
79
95
 
80
- def _make_line(self, from_, imports):
96
+ def _make_line(self, from_: str, imports: Sequence[str]) -> str:
81
97
  import_ = ", ".join(imports)
82
- code = "from %s import %s" % (from_, import_)
98
+ code = f"from {from_} import {import_}"
83
99
  if len(code) <= 80:
84
100
  return code
85
101
  wrapper = textwrap.TextWrapper(
86
102
  subsequent_indent=" ", initial_indent=" ", break_long_words=False
87
103
  )
88
104
  import_ = "\n".join(wrapper.wrap(import_))
89
- code = "from %s import (\n%s\n)" % (from_, import_)
105
+ code = f"from {from_} import (\n{import_}\n)"
90
106
  return code
91
107
 
92
- def getvalue(self):
93
- ns = {}
94
- lines = []
108
+ def getvalue(self) -> str:
109
+ ns: Dict[str, Optional[Set[str]]] = {}
110
+ lines: List[str] = []
95
111
  for key, val in self.data.items():
96
112
  if val is None:
97
113
  ns[key] = val
98
114
  elif key == "*":
99
- lines.append("from %s import *" % val)
115
+ lines.append(f"from {val} import *")
100
116
  else:
101
- ns.setdefault(val, set()).add(key)
117
+ ns.setdefault(val, set()).add(key) # type: ignore
102
118
  for key, val in ns.items():
103
119
  if val is None:
104
- lines.append("import %s" % key)
120
+ lines.append(f"import {key}")
105
121
  else:
106
122
  names = sorted(val, key=lambda s: s.lower())
107
123
  lines.append(self._make_line(key, names))
@@ -109,10 +125,10 @@ class ImportedNamespaces(object):
109
125
 
110
126
 
111
127
  class DeclaredNamespaces(object):
112
- def __init__(self):
113
- self.data = {}
128
+ def __init__(self) -> None:
129
+ self.data: Dict[Tuple[str, str], Optional[str]] = {}
114
130
 
115
- def add(self, alias, definition, comment=None):
131
+ def add(self, alias: str, definition: str, comment: Optional[str] = None) -> None:
116
132
  """Adds a namespace will be declared.
117
133
 
118
134
  Examples:
@@ -134,18 +150,18 @@ class DeclaredNamespaces(object):
134
150
  names.add(alias)
135
151
  return names
136
152
 
137
- def getvalue(self):
153
+ def getvalue(self) -> str:
138
154
  lines = []
139
155
  for (alias, definition), comment in self.data.items():
140
- code = "%s = %s" % (alias, definition)
156
+ code = f"{alias} = {definition}"
141
157
  if comment:
142
- code = code + " # %s" % comment
158
+ code = code + f" # {comment}"
143
159
  lines.append(code)
144
160
  return "\n".join(lines)
145
161
 
146
162
 
147
163
  class EnumerationNamespaces(object):
148
- def __init__(self):
164
+ def __init__(self) -> None:
149
165
  self.data: Dict[str, List[Tuple[str, int]]] = {}
150
166
 
151
167
  def add(self, enum_name: str, member_name: str, value: int) -> None:
@@ -159,6 +175,14 @@ class EnumerationNamespaces(object):
159
175
  >>> assert enums
160
176
  >>> enums.add('Foo', 'spam', 2)
161
177
  >>> enums.add('Bar', 'bacon', 3)
178
+ >>> enums.add('Bar', 'egg', 4)
179
+ >>> import warnings
180
+ >>> with warnings.catch_warnings(record=True) as w:
181
+ ... enums.add('Bar', 'egg', 5)
182
+ ... print(w[-1].message.args[0].replace(', ', ',\\n'))
183
+ The 'egg' member of the 'Bar' enumeration is already assigned 4,
184
+ but it will be overwritten with 5,
185
+ based on the type information.
162
186
  >>> assert 'Foo' in enums
163
187
  >>> assert 'Baz' not in enums
164
188
  >>> print(enums.to_intflags())
@@ -169,6 +193,8 @@ class EnumerationNamespaces(object):
169
193
  <BLANKLINE>
170
194
  class Bar(IntFlag):
171
195
  bacon = 3
196
+ # egg = 4 # duplicated. Perhaps there is a bug in the type library?
197
+ egg = 5 # duplicated. Perhaps there is a bug in the type library?
172
198
  >>> print(enums.to_constants())
173
199
  # values for enumeration 'Foo'
174
200
  ham = 1
@@ -177,9 +203,24 @@ class EnumerationNamespaces(object):
177
203
  <BLANKLINE>
178
204
  # values for enumeration 'Bar'
179
205
  bacon = 3
206
+ egg = 4 # duplicated within the 'Bar'. Perhaps there is a bug?
207
+ egg = 5 # duplicated within the 'Bar'. Perhaps there is a bug?
180
208
  Bar = c_int # enum
181
209
  """
182
- self.data.setdefault(enum_name, []).append((member_name, value))
210
+ members = self.data.setdefault(enum_name, [])
211
+ if members:
212
+ mapping = dict(members)
213
+ if member_name in mapping:
214
+ # This may be a bug in the COM type library.
215
+ # See also https://github.com/enthought/comtypes/issues/550
216
+ warnings.warn(
217
+ f"The '{member_name}' member of the '{enum_name}' enumeration "
218
+ f"is already assigned {mapping[member_name]}, "
219
+ f"but it will be overwritten with {value}, "
220
+ "based on the type information.",
221
+ UserWarning,
222
+ )
223
+ members.append((member_name, value))
183
224
 
184
225
  def __contains__(self, item: str) -> bool:
185
226
  return item in self.data
@@ -190,23 +231,52 @@ class EnumerationNamespaces(object):
190
231
  def get_symbols(self) -> Set[str]:
191
232
  return set(self.data)
192
233
 
234
+ def _iter_members(
235
+ self, members: Sequence[Tuple[str, int]]
236
+ ) -> Iterator[Tuple[str, bool, int]]:
237
+ key_counter = Counter(m for m, _ in members)
238
+ decrementee = dict(key_counter) # shallow copy
239
+ for name, value in members:
240
+ decrementee[name] -= 1
241
+ # definition, is_dupl, rest_dupl_count
242
+ yield f"{name} = {value}", key_counter[name] > 1, decrementee[name]
243
+
244
+ def _iter_items(self) -> Iterator[Tuple[str, Iterator[Tuple[str, bool, int]]]]:
245
+ for name, members in self.data.items():
246
+ yield name, self._iter_members(members)
247
+
193
248
  def to_constants(self) -> str:
194
249
  blocks = []
195
- for enum_name, enum_members in self.data.items():
250
+ for enum_name, members in self._iter_items():
196
251
  lines = []
197
252
  lines.append(f"# values for enumeration '{enum_name}'")
198
- for n, v in enum_members:
199
- lines.append(f"{n} = {v}")
253
+ for definition, is_dupl, _ in members:
254
+ if is_dupl:
255
+ msg1 = f"duplicated within the '{enum_name}'."
256
+ msg2 = "Perhaps there is a bug?"
257
+ lines.append(f"{definition} # {msg1} {msg2}")
258
+ else:
259
+ lines.append(definition)
200
260
  lines.append(f"{enum_name} = c_int # enum")
201
261
  blocks.append("\n".join(lines))
202
262
  return "\n\n".join(blocks)
203
263
 
204
264
  def to_intflags(self) -> str:
205
265
  blocks = []
206
- for enum_name, enum_members in self.data.items():
266
+ for enum_name, members in self._iter_items():
207
267
  lines = []
208
268
  lines.append(f"class {enum_name}(IntFlag):")
209
- for member_name, value in enum_members:
210
- lines.append(f" {member_name} = {value}")
269
+ for definition, is_dupl, rest_dupl_count in members:
270
+ if is_dupl:
271
+ msg = "duplicated. Perhaps there is a bug in the type library?"
272
+ base_line = f"{definition} # {msg}"
273
+ if rest_dupl_count > 0:
274
+ # Prevent raising `TypeError: Attempted to reuse key:`.
275
+ # See https://github.com/enthought/comtypes/issues/550
276
+ lines.append(f" # {base_line}")
277
+ else:
278
+ lines.append(f" {base_line}")
279
+ else:
280
+ lines.append(f" {definition}")
211
281
  blocks.append("\n".join(lines))
212
282
  return "\n\n\n".join(blocks)
@@ -33,8 +33,7 @@ class _MethodAnnotator(abc.ABC, Generic[_T_MTD]):
33
33
  return result
34
34
 
35
35
  @abc.abstractmethod
36
- def getvalue(self, name: str) -> str:
37
- ...
36
+ def getvalue(self, name: str) -> str: ...
38
37
 
39
38
 
40
39
  _CatMths = Tuple[ # categorized methods
@@ -47,8 +46,7 @@ class _MethodsAnnotator(abc.ABC, Generic[_T_MTD]):
47
46
  self.data: List[str] = []
48
47
 
49
48
  @abc.abstractmethod
50
- def to_method_annotator(self, method: _T_MTD) -> _MethodAnnotator[_T_MTD]:
51
- ...
49
+ def to_method_annotator(self, method: _T_MTD) -> _MethodAnnotator[_T_MTD]: ...
52
50
 
53
51
  def _iter_methods(self, members: Iterable[_T_MTD]) -> Iterator[_CatMths[_T_MTD]]:
54
52
  methods: Dict[str, List[Optional[_T_MTD]]] = {}
@@ -34,6 +34,7 @@ longlong_type = typedesc.FundamentalType("long long int", 64, 64)
34
34
  ulonglong_type = typedesc.FundamentalType("long long unsigned int", 64, 64)
35
35
  float_type = typedesc.FundamentalType("float", 32, 32)
36
36
  double_type = typedesc.FundamentalType("double", 64, 64)
37
+ void_type = typedesc.FundamentalType("void", 0, 0)
37
38
 
38
39
  # basic COM data types
39
40
  BSTR_type = typedesc.Typedef("BSTR", PTR(wchar_t_type))
@@ -89,7 +90,7 @@ COMTYPES = {
89
90
  automation.VT_UI8: ulonglong_type, # 21
90
91
  automation.VT_INT: int_type, # 22
91
92
  automation.VT_UINT: uint_type, # 23
92
- automation.VT_VOID: typedesc.FundamentalType("void", 0, 0), # 24
93
+ automation.VT_VOID: void_type, # 24
93
94
  automation.VT_HRESULT: HRESULT_type, # 25
94
95
  automation.VT_LPSTR: PTR(char_type), # 30
95
96
  automation.VT_LPWSTR: PTR(wchar_t_type), # 31
@@ -126,20 +127,18 @@ class Parser(object):
126
127
  )
127
128
  return typ
128
129
  elif tdesc.vt == automation.VT_PTR:
129
- ptrdesc: typeinfo.TYPEDESC = tdesc._.lptdesc[0]
130
- typ = self.make_type(ptrdesc, tinfo)
131
- return PTR(typ)
130
+ return PTR(self.make_type(tdesc._.lptdesc[0], tinfo))
132
131
  elif tdesc.vt == automation.VT_USERDEFINED:
133
132
  try:
134
133
  ti = tinfo.GetRefTypeInfo(tdesc._.hreftype)
135
134
  except COMError as details:
136
- type_name = "__error_hreftype_%d__" % tdesc._.hreftype
135
+ type_name = f"__error_hreftype_{tdesc._.hreftype:d}__"
137
136
  tlib_name = get_tlib_filename(self.tlib)
138
137
  if tlib_name is None:
139
138
  tlib_name = "unknown typelib"
140
139
  message = (
141
- "\n\tGetRefTypeInfo failed in %s: %s\n\tgenerating type '%s' instead"
142
- % (tlib_name, details, type_name)
140
+ f"\n\tGetRefTypeInfo failed in {tlib_name}: {details}"
141
+ f"\n\tgenerating type '{type_name}' instead"
143
142
  )
144
143
  import warnings
145
144
 
@@ -153,8 +152,7 @@ class Parser(object):
153
152
  return result
154
153
  elif tdesc.vt == automation.VT_SAFEARRAY:
155
154
  # SAFEARRAY(<type>), see Don Box pp.331f
156
- safearraydesc: typeinfo.TYPEDESC = tdesc._.lptdesc[0]
157
- return midlSAFEARRAY(self.make_type(safearraydesc, tinfo))
155
+ return midlSAFEARRAY(self.make_type(tdesc._.lptdesc[0], tinfo))
158
156
  raise NotImplementedError(tdesc.vt)
159
157
 
160
158
  ################################################################
@@ -271,7 +269,7 @@ class Parser(object):
271
269
  # Don't known what artefact that is - we ignore it.
272
270
  # It's an interface without methods anyway.
273
271
  if itf_name != "IOleControlTypes":
274
- message = "Ignoring interface %s which has no base interface" % itf_name
272
+ message = f"Ignoring interface {itf_name} which has no base interface"
275
273
  import warnings
276
274
 
277
275
  warnings.warn(message, UserWarning)
@@ -591,33 +589,26 @@ class Parser(object):
591
589
  self, name: Optional[str], value: Any, tlib: Optional[typeinfo.ITypeLib] = None
592
590
  ) -> None:
593
591
  modname = self._typelib_module(tlib)
594
- fullname = "%s.%s" % (modname, name)
592
+ fullname = f"{modname}.{name}"
595
593
  if fullname in self.items:
596
594
  # XXX Can we really allow this? It happens, at least.
597
595
  if isinstance(value, typedesc.External):
598
596
  return
599
597
  # BUG: We try to register an item that's already registered.
600
- raise ValueError("Bug: Multiple registered name '%s': %r" % (name, value))
598
+ raise ValueError(f"Bug: Multiple registered name '{name}': {value!r}")
601
599
  self.items[fullname] = value
602
600
 
603
601
  def parse_typeinfo(self, tinfo: typeinfo.ITypeInfo) -> Any:
604
602
  name = tinfo.GetDocumentation(-1)[0]
605
603
  modname = self._typelib_module()
606
604
  try:
607
- return self.items["%s.%s" % (modname, name)]
605
+ return self.items[f"{modname}.{name}"]
608
606
  except KeyError:
609
607
  pass
610
608
 
611
609
  tlib = tinfo.GetContainingTypeLib()[0]
612
610
  if tlib != self.tlib:
613
- ta = tinfo.GetTypeAttr()
614
- size = ta.cbSizeInstance * 8
615
- align = ta.cbAlignment * 8
616
- typ = typedesc.External(
617
- tlib, name, size, align, tlib.GetDocumentation(-1)[:2]
618
- )
619
- self._register(name, typ, tlib)
620
- return typ
611
+ return self._parse_External(name, tlib, tinfo)
621
612
 
622
613
  ta = tinfo.GetTypeAttr()
623
614
  tkind = ta.typekind
@@ -638,10 +629,7 @@ class Parser(object):
638
629
  except COMError:
639
630
  # no dual interface
640
631
  return self.ParseDispatch(tinfo, ta)
641
- tinfo = tinfo.GetRefTypeInfo(href)
642
- ta = tinfo.GetTypeAttr()
643
- assert ta.typekind == typeinfo.TKIND_INTERFACE
644
- return self.ParseInterface(tinfo, ta)
632
+ return self._parse_DualInterface(tinfo.GetRefTypeInfo(href))
645
633
  elif tkind == typeinfo.TKIND_COCLASS: # 5
646
634
  return self.ParseCoClass(tinfo, ta)
647
635
  elif tkind == typeinfo.TKIND_ALIAS: # 6
@@ -652,6 +640,24 @@ class Parser(object):
652
640
  print("NYI", tkind)
653
641
  # raise "NYI", tkind
654
642
 
643
+ def _parse_DualInterface(
644
+ self, tinfo: typeinfo.ITypeInfo
645
+ ) -> Optional[typedesc.ComInterface]:
646
+ ta = tinfo.GetTypeAttr()
647
+ assert ta.typekind == typeinfo.TKIND_INTERFACE
648
+ return self.ParseInterface(tinfo, ta)
649
+
650
+ def _parse_External(
651
+ self, name: str, tlib: typeinfo.ITypeLib, tinfo: typeinfo.ITypeInfo
652
+ ) -> typedesc.External:
653
+ ta = tinfo.GetTypeAttr()
654
+ size = ta.cbSizeInstance * 8
655
+ align = ta.cbAlignment * 8
656
+ docs = tlib.GetDocumentation(-1)[:2]
657
+ typ = typedesc.External(tlib, name, size, align, docs)
658
+ self._register(name, typ, tlib)
659
+ return typ
660
+
655
661
  def parse_LibraryDescription(self):
656
662
  la = self.tlib.GetLibAttr()
657
663
  name, doc = self.tlib.GetDocumentation(-1)[:2]
@@ -731,18 +737,13 @@ class TypeLibParser(Parser):
731
737
  # path = r"c:\vc98\include\activscp.tlb"
732
738
 
733
739
 
734
- def get_tlib_filename(tlib):
740
+ def get_tlib_filename(tlib: typeinfo.ITypeLib) -> Optional[str]:
735
741
  # seems if the typelib is not registered, there's no way to
736
742
  # determine the filename.
737
743
  la = tlib.GetLibAttr()
738
744
  name = BSTR()
739
- try:
740
- windll.oleaut32.QueryPathOfRegTypeLib
741
- except AttributeError:
742
- # Windows CE doesn't have this function
743
- return None
744
745
  if 0 == windll.oleaut32.QueryPathOfRegTypeLib(
745
- byref(la.guid), la.wMajorVerNum, la.wMinorVerNum, 0, byref(name) # lcid
746
+ byref(la.guid), la.wMajorVerNum, la.wMinorVerNum, 0, byref(name)
746
747
  ):
747
748
  full_filename = name.value.split("\0")[0]
748
749
  if not os.path.isabs(full_filename):
@@ -49,7 +49,7 @@ class External(object):
49
49
  name: str,
50
50
  size: int,
51
51
  align: int,
52
- docs: Optional[Tuple[str, str]] = None,
52
+ docs: Optional[Tuple[str, Optional[str]]] = None,
53
53
  ) -> None:
54
54
  # the type library containing the symbol
55
55
  self.tlib = tlib
@@ -238,7 +238,7 @@ _SourceInterfaces = Sequence[_Interface]
238
238
 
239
239
 
240
240
  def groupby_impltypeflags(
241
- seq: Sequence[Tuple[_Interface, _ImplTypeFlags]]
241
+ seq: Sequence[Tuple[_Interface, _ImplTypeFlags]],
242
242
  ) -> Tuple[_ImplementedInterfaces, _SourceInterfaces]:
243
243
  implemented = []
244
244
  sources = []
@@ -231,7 +231,8 @@ class ITypeLib(IUnknown):
231
231
  def GetLibAttr(self) -> "TLIBATTR":
232
232
  """Return type library attributes"""
233
233
  return _deref_with_release(
234
- self._GetLibAttr(), self.ReleaseTLibAttr # type: ignore
234
+ self._GetLibAttr(), # type: ignore
235
+ self.ReleaseTLibAttr,
235
236
  )
236
237
 
237
238
  def IsName(self, name: str, lHashVal: int = 0) -> Optional[str]:
@@ -269,15 +270,9 @@ class ITypeLib(IUnknown):
269
270
 
270
271
 
271
272
  @overload
272
- def fix_name(name: None) -> None:
273
- pass
274
-
275
-
273
+ def fix_name(name: None) -> None: ...
276
274
  @overload
277
- def fix_name(name: str) -> str:
278
- pass
279
-
280
-
275
+ def fix_name(name: str) -> str: ...
281
276
  def fix_name(name):
282
277
  # Some typelibs contain BSTR with embedded NUL characters,
283
278
  # probably the len of the BSTR is wrong.
@@ -345,7 +340,8 @@ class ITypeInfo(IUnknown):
345
340
  def GetTypeAttr(self) -> "TYPEATTR":
346
341
  """Return the TYPEATTR for this type"""
347
342
  return _deref_with_release(
348
- self._GetTypeAttr(), self.ReleaseTypeAttr # type: ignore
343
+ self._GetTypeAttr(), # type: ignore
344
+ self.ReleaseTypeAttr,
349
345
  )
350
346
 
351
347
  def GetDocumentation(
@@ -358,13 +354,15 @@ class ITypeInfo(IUnknown):
358
354
  def GetFuncDesc(self, index: int) -> "FUNCDESC":
359
355
  """Return FUNCDESC for index"""
360
356
  return _deref_with_release(
361
- self._GetFuncDesc(index), self.ReleaseFuncDesc # type: ignore
357
+ self._GetFuncDesc(index), # type: ignore
358
+ self.ReleaseFuncDesc,
362
359
  )
363
360
 
364
361
  def GetVarDesc(self, index: int) -> "VARDESC":
365
362
  """Return VARDESC for index"""
366
363
  return _deref_with_release(
367
- self._GetVarDesc(index), self.ReleaseVarDesc # type: ignore
364
+ self._GetVarDesc(index), # type: ignore
365
+ self.ReleaseVarDesc,
368
366
  )
369
367
 
370
368
  def GetNames(self, memid: int, count: int = 1) -> List[str]:
@@ -481,25 +479,23 @@ class IRecordInfo(IUnknown):
481
479
  return result
482
480
 
483
481
  if TYPE_CHECKING:
484
- # fmt: off
485
482
  # def RecordInit
486
483
  # def RecordClear
487
- def RecordCopy( # noqa
484
+ def RecordCopy(
488
485
  self, pvExisting: hints.Incomplete, pvNew: hints.Incomplete
489
486
  ) -> hints.Hresult: ...
490
- def GetGuid(self) -> GUID: ... # noqa
491
- def GetName(self) -> str: ... # noqa
492
- def GetSize(self) -> int: ... # noqa
493
- def GetTypeInfo(self) -> ITypeInfo: ... # noqa
487
+ def GetGuid(self) -> GUID: ...
488
+ def GetName(self) -> str: ...
489
+ def GetSize(self) -> int: ...
490
+ def GetTypeInfo(self) -> ITypeInfo: ...
494
491
  # def GetField
495
492
  # def GetFieldNoCopy
496
493
  # def PutField
497
494
  # def PutFieldNoCopy
498
- def IsMatchingType(self, value: "IRecordInfo") -> bool: ... # noqa
495
+ def IsMatchingType(self, value: "IRecordInfo") -> bool: ...
499
496
  # def RecordCreate
500
- def RecordCreateCopy(self, pvSource: hints.Incomplete) -> int: ... # noqa
501
- def RecordDestroy(self, pvRecord: hints.Incomplete) -> hints.Hresult: ... # noqa
502
- # fmt: on
497
+ def RecordCreateCopy(self, pvSource: hints.Incomplete) -> int: ...
498
+ def RecordDestroy(self, pvRecord: hints.Incomplete) -> hints.Hresult: ...
503
499
 
504
500
 
505
501
  IRecordInfo._methods_ = [
@@ -1125,8 +1121,8 @@ tagTLIBATTR._fields_ = [
1125
1121
  class N11tagTYPEDESC5DOLLAR_203E(ctypes.Union):
1126
1122
  # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 584
1127
1123
  if TYPE_CHECKING:
1128
- lptdesc: TYPEDESC
1129
- lpadesc: tagARRAYDESC
1124
+ lptdesc: _Pointer[tagTYPEDESC]
1125
+ lpadesc: _Pointer[tagARRAYDESC]
1130
1126
  hreftype: int
1131
1127
 
1132
1128
 
@@ -1175,7 +1171,7 @@ class N10tagVARDESC5DOLLAR_205E(ctypes.Union):
1175
1171
  # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 807
1176
1172
  if TYPE_CHECKING:
1177
1173
  oInst: int
1178
- lpvarValue: VARIANT
1174
+ lpvarValue: _Pointer[VARIANT]
1179
1175
 
1180
1176
 
1181
1177
  N10tagVARDESC5DOLLAR_205E._fields_ = [
@@ -1,6 +1,7 @@
1
1
  """This module defines the funtions byref_at(cobj, offset)
2
2
  and cast_field(struct, fieldname, fieldtype).
3
3
  """
4
+
4
5
  from ctypes import *
5
6
 
6
7
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: comtypes
3
- Version: 1.4.7
3
+ Version: 1.4.8
4
4
  Summary: Pure Python COM package
5
5
  Home-page: https://github.com/enthought/comtypes
6
6
  Download-URL: https://github.com/enthought/comtypes/releases
@@ -20,8 +20,9 @@ License-File: LICENSE.txt
20
20
  # comtypes
21
21
 
22
22
  ![Works on Windows only](https://img.shields.io/badge/-Windows-0078D6.svg?logo=windows&style=flat)
23
- [![PyPI version](https://badge.fury.io/py/comtypes.svg)](https://pypi.org/project/comtypes/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/comtypes)](https://pypi.org/project/comtypes/) [![PyPI - License](https://img.shields.io/pypi/l/comtypes)](https://pypi.org/project/comtypes/) [![PyPI - Downloads](https://img.shields.io/pypi/dm/comtypes)](https://pypi.org/project/comtypes/)
24
- [![GitHub Repo stars](https://img.shields.io/github/stars/enthought/comtypes?style=social)](https://github.com/enthought/comtypes/stargazers) [![GitHub forks](https://img.shields.io/github/forks/enthought/comtypes?style=social)](https://github.com/enthought/comtypes/network/members)
23
+ [![PyPI version](https://badge.fury.io/py/comtypes.svg)](https://pypi.org/project/comtypes/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/comtypes)](https://pypi.org/project/comtypes/) [![PyPI - Python Requires](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpypi.org%2Fpypi%2Fcomtypes%2Fjson&query=info.requires_python&label=Python&nbsp;Requires)](https://pypi.org/project/comtypes/)
24
+ [![PyPI - License](https://img.shields.io/pypi/l/comtypes)](https://pypi.org/project/comtypes/) [![PyPI - Downloads](https://img.shields.io/pypi/dm/comtypes)](https://pypi.org/project/comtypes/)
25
+ [![GitHub Repo stars](https://img.shields.io/github/stars/enthought/comtypes?style=social)](https://github.com/enthought/comtypes/stargazers) [![GitHub forks](https://img.shields.io/github/forks/enthought/comtypes?style=social)](https://github.com/enthought/comtypes/network/members) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
25
26
  [![Tidelift Subscription](https://tidelift.com/badges/package/pypi/comtypes)](https://tidelift.com/subscription/pkg/pypi-comtypes?utm_source=pypi-comtypes&utm_medium=readme)
26
27
 
27
28
 
@@ -30,6 +31,7 @@ License-File: LICENSE.txt
30
31
  `comtypes` allows you to define, call, and implement custom and dispatch-based COM interfaces in pure Python.
31
32
 
32
33
  `comtypes` requires Windows and Python 3.8 or later.
34
+ - Version <= [1.4.7](https://pypi.org/project/comtypes/1.4.7/) does not work with Python 3.13 as reported in [GH-618](https://github.com/enthought/comtypes/issues/618). Version [1.4.8](https://pypi.org/project/comtypes/1.4.8/) can work with Python 3.13.
33
35
  - Version [1.4.6](https://pypi.org/project/comtypes/1.4.6/) is the last version to support Python 3.7.
34
36
  - Version [1.2.1](https://pypi.org/project/comtypes/1.2.1/) is the last version to support Python 2.7 and 3.3–3.6.
35
37
  - `comtypes` does not work with Python 3.8.1 as reported in [GH-202](https://github.com/enthought/comtypes/issues/202). This bug has been fixed in Python >= 3.8.2.
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.2"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [tool.ruff.lint]
6
+ ignore = ["E402"]
7
+
8
+ [tool.ruff.lint.per-file-ignores]
9
+ # production
10
+ "comtypes/_comobject.py" = ["E713", "E722", "F401"]
11
+ "comtypes/_npsupport.py" = ["F401"]
12
+ "comtypes/connectionpoints.py" = ["F401", "F403", "F405"]
13
+ "comtypes/automation.py" = ["F401", "F403", "F405"]
14
+ "comtypes/errorinfo.py" = ["F403", "F405"]
15
+ "comtypes/git.py" = ["F401", "F403", "F405"]
16
+ "comtypes/logutil.py" = ["E401"]
17
+ "comtypes/shelllink.py" = ["F401"]
18
+ "comtypes/util.py" = ["F403", "F405"]
19
+ "comtypes/viewobject.py" = ["F403", "F405"]
20
+ "comtypes/_post_coinit/unknwn.py" = ["F821"]
21
+ "comtypes/client/__init__.py" = ["F401", "F403"]
22
+ "comtypes/client/_code_cache.py" = ["E401", "E711"]
23
+ "comtypes/client/_constants.py" = ["F401"]
24
+ "comtypes/client/_events.py" = ["F841"]
25
+ "comtypes/client/lazybind.py" = ["F821"]
26
+ "comtypes/server/__init__.py" = ["E401"]
27
+ "comtypes/server/automation.py" = ["F403", "F405"]
28
+ "comtypes/server/connectionpoints.py" = ["F401", "F403", "F405"]
29
+ "comtypes/server/inprocserver.py" = ["E713", "E722", "F403", "F405", "F841"]
30
+ "comtypes/server/localserver.py" = ["F401", "F403", "F405"]
31
+ "comtypes/server/register.py" = ["F403", "F405", "E713", "E731"]
32
+ "comtypes/tools/codegenerator/codegenerator.py" = ["E713", "E721"]
33
+ "comtypes/tools/codegenerator/helpers.py" = ["F401"]
34
+ "comtypes/tools/codegenerator/packing.py" = ["F821", "F841"]
35
+ "comtypes/tools/tlbparser.py" = ["F401"]
36
+ "comtypes/tools/typedesc.py" = ["F403", "F405"]
37
+ "comtypes/tools/typedesc_base.py" = ["F401"]
38
+ # tests
39
+ "comtypes/test/TestComServer.py" = ["E401", "F401", "F403", "F405"]
40
+ "comtypes/test/TestDispServer.py" = ["E401"]
41
+ "comtypes/test/find_memleak.py" = ["E401", "F401", "F403", "F405"]
42
+ "comtypes/test/setup.py" = ["F401"]
43
+ "comtypes/test/test_BSTR.py" = ["E401", "F401", "F403", "F405"]
44
+ "comtypes/test/test_agilent.py" = ["F401", "F841"]
45
+ "comtypes/test/test_client.py" = ["F401"]
46
+ "comtypes/test/test_dict.py" = ["F841"]
47
+ "comtypes/test/test_ie.py" = ["F403", "F405", "F841"]
48
+ "comtypes/test/test_outparam.py" = ["F403", "F405", "F841"]
49
+ "comtypes/test/test_sapi.py" = ["E401"]
50
+ "comtypes/test/test_server.py" = ["E401", "E722", "F401", "F841"]
51
+ "comtypes/test/test_subinterface.py" = ["E401", "F401", "F403", "F405"]
52
+ "comtypes/test/test_typeinfo.py" = ["F401"]
53
+ "comtypes/test/test_urlhistory.py" = ["E401", "F401", "F403", "F405", "F841"]
54
+ "comtypes/test/test_variant.py" = ["F401", "F821", "F841"]