comtypes 1.4.7__zip → 1.4.9__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 (149) hide show
  1. {comtypes-1.4.7 → comtypes-1.4.9}/CHANGES.txt +39 -0
  2. {comtypes-1.4.7/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +6 -4
  3. {comtypes-1.4.7 → comtypes-1.4.9}/README.md +5 -3
  4. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
  5. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
  6. comtypes-1.4.9/comtypes/_comobject.py +507 -0
  7. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_memberspec.py +81 -9
  8. comtypes-1.4.9/comtypes/_meta.py +95 -0
  9. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_npsupport.py +2 -1
  10. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +1 -0
  11. comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
  12. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +21 -40
  13. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +88 -209
  14. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
  15. comtypes-1.4.9/comtypes/_vtbl.py +448 -0
  16. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/automation.py +36 -45
  17. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/__init__.py +21 -31
  18. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_code_cache.py +5 -4
  19. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
  20. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_events.py +1 -2
  21. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_generate.py +9 -13
  22. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -7
  23. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
  24. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/git.py +2 -2
  25. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hints.pyi +11 -19
  26. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/persist.py +7 -7
  27. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/safearray.py +12 -6
  28. comtypes-1.4.9/comtypes/server/__init__.py +86 -0
  29. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
  30. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
  31. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/register.py +62 -73
  32. comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
  33. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/shelllink.py +49 -67
  34. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.py +1 -1
  35. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +1 -1
  36. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -12
  37. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -1
  38. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
  39. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -1
  40. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
  41. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
  42. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +1 -0
  43. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
  44. comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
  45. comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
  46. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -6
  47. comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
  48. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -13
  49. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
  50. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +8 -5
  51. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
  52. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
  53. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
  54. comtypes-1.4.9/comtypes/test/test_server.py +350 -0
  55. comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
  56. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +10 -14
  57. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
  58. comtypes-1.4.9/comtypes/test/test_stream.py +131 -0
  59. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +1 -1
  60. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +1 -0
  61. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -19
  62. comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
  63. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
  64. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
  65. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
  66. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
  67. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +97 -27
  68. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
  69. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +9 -11
  70. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +33 -32
  71. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc.py +3 -8
  72. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/typeinfo.py +32 -47
  73. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/util.py +1 -0
  74. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
  75. {comtypes-1.4.7 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +6 -4
  76. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
  77. comtypes-1.4.9/pyproject.toml +55 -0
  78. comtypes-1.4.7/comtypes/_comobject.py +0 -834
  79. comtypes-1.4.7/comtypes/_idl_stuff.py +0 -67
  80. comtypes-1.4.7/comtypes/_meta.py +0 -70
  81. comtypes-1.4.7/comtypes/server/__init__.py +0 -69
  82. comtypes-1.4.7/comtypes/server/w_getopt.py +0 -75
  83. comtypes-1.4.7/comtypes/test/test_comserver.py +0 -239
  84. comtypes-1.4.7/comtypes/test/test_dispinterface.py +0 -138
  85. comtypes-1.4.7/comtypes/test/test_propputref.py +0 -40
  86. comtypes-1.4.7/comtypes/test/test_server.py +0 -348
  87. comtypes-1.4.7/comtypes/test/test_stream.py +0 -53
  88. comtypes-1.4.7/pyproject.toml +0 -3
  89. {comtypes-1.4.7 → comtypes-1.4.9}/LICENSE.txt +0 -0
  90. {comtypes-1.4.7 → comtypes-1.4.9}/MANIFEST.in +0 -0
  91. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
  92. /comtypes-1.4.7/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
  93. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
  94. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
  95. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
  96. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
  97. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
  98. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
  99. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
  100. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
  101. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
  102. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
  103. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/stream.py +0 -0
  104. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
  105. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
  106. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
  107. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
  108. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
  109. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
  110. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
  111. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
  112. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
  113. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
  114. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
  115. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
  116. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
  117. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
  118. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
  119. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
  120. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
  121. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
  122. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
  123. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
  124. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
  125. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
  126. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
  127. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
  128. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
  129. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
  130. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
  131. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
  132. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
  133. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
  134. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
  135. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
  136. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
  137. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
  138. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
  139. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
  140. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
  141. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
  142. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
  143. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  144. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
  145. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
  146. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
  147. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
  148. {comtypes-1.4.7 → comtypes-1.4.9}/setup.cfg +0 -0
  149. {comtypes-1.4.7 → comtypes-1.4.9}/setup.py +0 -0
@@ -128,9 +128,9 @@ class CodeGenerator(object):
128
128
  path = self._make_relative_path(filename, comtypes.gen.__path__[0])
129
129
  self.imports.add("os")
130
130
  definition = (
131
- "os.path.normpath(\n"
132
- " os.path.abspath(os.path.join(os.path.dirname(__file__),\n"
133
- " %r)))" % path
131
+ f"os.path.normpath(\n"
132
+ f" os.path.abspath(os.path.join(os.path.dirname(__file__),\n"
133
+ f" {path!r})))"
134
134
  )
135
135
  self.declarations.add("typelib_path", definition)
136
136
  p = os.path.normpath(
@@ -293,7 +293,7 @@ class CodeGenerator(object):
293
293
  indent = " " * depth
294
294
  # some chars are replaced to avoid causing a `SyntaxError`
295
295
  repled = orig.replace("\\", r"\\").replace('"', r"'")
296
- return '%s"""%s"""' % (indent, repled)
296
+ return f'{indent}"""{repled}"""'
297
297
 
298
298
  def ArrayType(self, tp: typedesc.ArrayType) -> None:
299
299
  self.generate(get_real_type(tp.typ))
@@ -347,7 +347,7 @@ class CodeGenerator(object):
347
347
  self.more.add(struct)
348
348
  if head.struct.location:
349
349
  self.last_item_class = False
350
- print("# %s %s" % head.struct.location, file=self.stream)
350
+ print(f"# {head.struct.location}", file=self.stream)
351
351
  basenames = [self._to_type_name(b) for b in head.struct.bases]
352
352
  if basenames:
353
353
  self.imports.add("comtypes", "GUID")
@@ -362,7 +362,7 @@ class CodeGenerator(object):
362
362
  m.name for m in head.struct.members if type(m) is typedesc.Method
363
363
  ]
364
364
  print(
365
- "class %s(%s):" % (head.struct.name, ", ".join(basenames)),
365
+ f"class {head.struct.name}({', '.join(basenames)}):",
366
366
  file=self.stream,
367
367
  )
368
368
  print(
@@ -397,7 +397,7 @@ class CodeGenerator(object):
397
397
  print("assert 0, 'cannot generate code for IUnknown'", file=self.stream)
398
398
  print(file=self.stream)
399
399
  print(file=self.stream)
400
- print("class %s(_com_interface):" % head.struct.name, file=self.stream)
400
+ print(f"class {head.struct.name}(_com_interface):", file=self.stream)
401
401
  print(" pass", file=self.stream)
402
402
  print(file=self.stream)
403
403
  print(file=self.stream)
@@ -408,10 +408,10 @@ class CodeGenerator(object):
408
408
 
409
409
  self.last_item_class = True
410
410
 
411
- print("class %s(Structure):" % head.struct.name, file=self.stream)
411
+ print(f"class {head.struct.name}(Structure):", file=self.stream)
412
412
  if hasattr(head.struct, "_recordinfo_"):
413
413
  print(
414
- " _recordinfo_ = %r" % (head.struct._recordinfo_,),
414
+ f" _recordinfo_ = {head.struct._recordinfo_!r}",
415
415
  file=self.stream,
416
416
  )
417
417
  else:
@@ -425,7 +425,7 @@ class CodeGenerator(object):
425
425
 
426
426
  self.last_item_class = True
427
427
 
428
- print("class %s(Union):" % head.struct.name, file=self.stream)
428
+ print(f"class {head.struct.name}(Union):", file=self.stream)
429
429
  print(" pass", file=self.stream)
430
430
  print(file=self.stream)
431
431
  print(file=self.stream)
@@ -462,14 +462,14 @@ class CodeGenerator(object):
462
462
  pack = packing.calc_packing(body.struct, fields)
463
463
  if pack is not None:
464
464
  self.last_item_class = False
465
- print("%s._pack_ = %s" % (body.struct.name, pack), file=self.stream)
465
+ print(f"{body.struct.name}._pack_ = {pack}", file=self.stream)
466
466
  except packing.PackingError as details:
467
467
  # if packing fails, write a warning comment to the output.
468
468
  import warnings
469
469
 
470
470
  message = "Structure %s: %s" % (body.struct.name, details)
471
471
  warnings.warn(message, UserWarning)
472
- print("# WARNING: %s" % details, file=self.stream)
472
+ print(f"# WARNING: {details}", file=self.stream)
473
473
  self.last_item_class = False
474
474
 
475
475
  if fields:
@@ -482,9 +482,9 @@ class CodeGenerator(object):
482
482
 
483
483
  self.last_item_class = False
484
484
 
485
- print("%s._fields_ = [" % body.struct.name, file=self.stream)
485
+ print(f"{body.struct.name}._fields_ = [", file=self.stream)
486
486
  if body.struct.location:
487
- print(" # %s %s" % body.struct.location, file=self.stream)
487
+ print(f" # {body.struct.location}", file=self.stream)
488
488
  # unnamed fields will get autogenerated names "_", "_1". "_2", "_3", ...
489
489
  unnamed_index = 0
490
490
  for f in fields:
@@ -495,20 +495,19 @@ class CodeGenerator(object):
495
495
  fieldname = "_"
496
496
  unnamed_index += 1
497
497
  print(
498
- " # Unnamed field renamed to '%s'" % fieldname,
498
+ f" # Unnamed field renamed to '{fieldname}'",
499
499
  file=self.stream,
500
500
  )
501
501
  else:
502
502
  fieldname = f.name
503
503
  if f.bits is None:
504
504
  print(
505
- " ('%s', %s)," % (fieldname, self._to_type_name(f.typ)),
505
+ f" ('{fieldname}', {self._to_type_name(f.typ)}),",
506
506
  file=self.stream,
507
507
  )
508
508
  else:
509
509
  print(
510
- " ('%s', %s, %s),"
511
- % (fieldname, self._to_type_name(f.typ), f.bits),
510
+ f" ('{fieldname}', {self._to_type_name(f.typ)}, {f.bits}),",
512
511
  file=self.stream,
513
512
  )
514
513
  print("]", file=self.stream)
@@ -524,14 +523,12 @@ class CodeGenerator(object):
524
523
  print(file=self.stream)
525
524
  size = body.struct.size // 8
526
525
  print(
527
- "assert sizeof(%s) == %s, sizeof(%s)"
528
- % (body.struct.name, size, body.struct.name),
526
+ f"assert sizeof({body.struct.name}) == {size}, sizeof({body.struct.name})",
529
527
  file=self.stream,
530
528
  )
531
529
  align = body.struct.align // 8
532
530
  print(
533
- "assert alignment(%s) == %s, alignment(%s)"
534
- % (body.struct.name, align, body.struct.name),
531
+ f"assert alignment({body.struct.name}) == {align}, alignment({body.struct.name})",
535
532
  file=self.stream,
536
533
  )
537
534
 
@@ -542,27 +539,24 @@ class CodeGenerator(object):
542
539
  print(file=self.stream)
543
540
 
544
541
  self.last_item_class = False
545
- print("%s._methods_ = [" % body.struct.name, file=self.stream)
542
+ print(f"{body.struct.name}._methods_ = [", file=self.stream)
546
543
  if body.struct.location:
547
- print("# %s %s" % body.struct.location, file=self.stream)
544
+ print(f"# {body.struct.location}", file=self.stream)
548
545
 
549
546
  for m in methods:
550
547
  if m.location:
551
- print(" # %s %s" % m.location, file=self.stream)
548
+ print(f" # {m.location}", file=self.stream)
552
549
  print(
553
550
  (
554
- " COMMETHOD(\n"
555
- " [], \n"
556
- " %s,\n"
557
- " '%s',\n"
558
- )
559
- % (self._to_type_name(m.returns), m.name),
551
+ f" COMMETHOD(\n"
552
+ f" [], \n"
553
+ f" {self._to_type_name(m.returns)},\n"
554
+ f" '{m.name}',\n"
555
+ ),
560
556
  file=self.stream,
561
557
  )
562
558
  for a in m.iterArgTypes():
563
- print(
564
- " ([], %s),\n" % self._to_type_name(a), file=self.stream
565
- )
559
+ print(f" ([], {self._to_type_name(a)}),\n", file=self.stream)
566
560
  print(" ),", file=self.stream)
567
561
  print("]", file=self.stream)
568
562
 
@@ -589,10 +583,10 @@ class CodeGenerator(object):
589
583
  print(self._to_docstring(lib.doc), file=self.stream)
590
584
 
591
585
  if lib.name:
592
- print(" name = %r" % lib.name, file=self.stream)
586
+ print(f" name = {lib.name!r}", file=self.stream)
593
587
 
594
588
  print(
595
- " _reg_typelib_ = (%r, %r, %r)" % (lib.guid, lib.major, lib.minor),
589
+ f" _reg_typelib_ = ({lib.guid!r}, {lib.major!r}, {lib.minor!r})",
596
590
  file=self.stream,
597
591
  )
598
592
  print(file=self.stream)
@@ -608,7 +602,7 @@ class CodeGenerator(object):
608
602
  def Constant(self, tp: typedesc.Constant) -> None:
609
603
  self.last_item_class = False
610
604
  print(
611
- "%s = %r # Constant %s" % (tp.name, tp.value, self._to_type_name(tp.typ)),
605
+ f"{tp.name} = {tp.value!r} # Constant {self._to_type_name(tp.typ)}",
612
606
  file=self.stream,
613
607
  )
614
608
  self.names.add(tp.name)
@@ -650,11 +644,11 @@ class CodeGenerator(object):
650
644
 
651
645
  self.last_item_class = True
652
646
 
653
- print("class %s(CoClass):" % coclass.name, file=self.stream)
647
+ print(f"class {coclass.name}(CoClass):", file=self.stream)
654
648
  if coclass.doc:
655
649
  print(self._to_docstring(coclass.doc), file=self.stream)
656
- print(" _reg_clsid_ = GUID(%r)" % coclass.clsid, file=self.stream)
657
- print(" _idlflags_ = %s" % coclass.idlflags, file=self.stream)
650
+ print(f" _reg_clsid_ = GUID({coclass.clsid!r})", file=self.stream)
651
+ print(f" _idlflags_ = {coclass.idlflags}", file=self.stream)
658
652
  if self.filename is not None:
659
653
  print(" _typelib_path_ = typelib_path", file=self.stream)
660
654
  # X print
@@ -663,7 +657,7 @@ class CodeGenerator(object):
663
657
  libid = coclass.tlibattr.guid
664
658
  wMajor, wMinor = coclass.tlibattr.wMajorVerNum, coclass.tlibattr.wMinorVerNum
665
659
  print(
666
- " _reg_typelib_ = (%r, %s, %s)" % (str(libid), wMajor, wMinor),
660
+ f" _reg_typelib_ = ({str(libid)!r}, {wMajor}, {wMinor})",
667
661
  file=self.stream,
668
662
  )
669
663
  print(file=self.stream)
@@ -678,13 +672,13 @@ class CodeGenerator(object):
678
672
  if implemented:
679
673
  self.last_item_class = False
680
674
  print(
681
- "%s._com_interfaces_ = [%s]" % (coclass.name, ", ".join(implemented)),
675
+ f"{coclass.name}._com_interfaces_ = [{', '.join(implemented)}]",
682
676
  file=self.stream,
683
677
  )
684
678
  if sources:
685
679
  self.last_item_class = False
686
680
  print(
687
- "%s._outgoing_interfaces_ = [%s]" % (coclass.name, ", ".join(sources)),
681
+ f"{coclass.name}._outgoing_interfaces_ = [{', '.join(sources)}]",
688
682
  file=self.stream,
689
683
  )
690
684
 
@@ -773,13 +767,13 @@ class CodeGenerator(object):
773
767
 
774
768
  self.last_item_class = True
775
769
 
776
- print("class %s(%s):" % (head.itf.name, basename), file=self.stream)
770
+ print(f"class {head.itf.name}({basename}):", file=self.stream)
777
771
  if head.itf.doc:
778
772
  print(self._to_docstring(head.itf.doc), file=self.stream)
779
773
 
780
774
  print(" _case_insensitive_ = True", file=self.stream)
781
- print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
782
- print(" _idlflags_ = %s" % head.itf.idlflags, file=self.stream)
775
+ print(f" _iid_ = GUID({head.itf.iid!r})", file=self.stream)
776
+ print(f" _idlflags_ = {head.itf.idlflags}", file=self.stream)
783
777
 
784
778
  if self._is_enuminterface(head.itf):
785
779
  print(file=self.stream)
@@ -826,7 +820,7 @@ class CodeGenerator(object):
826
820
  print(file=self.stream)
827
821
 
828
822
  self.last_item_class = False
829
- print("%s._methods_ = [" % body.itf.name, file=self.stream)
823
+ print(f"{body.itf.name}._methods_ = [", file=self.stream)
830
824
  for m in body.itf.members:
831
825
  if isinstance(m, typedesc.ComMethod):
832
826
  self.make_ComMethod(m, "dual" in body.itf.idlflags)
@@ -839,8 +833,8 @@ class CodeGenerator(object):
839
833
  "################################################################",
840
834
  file=self.stream,
841
835
  )
842
- print("# code template for %s implementation" % body.itf.name, file=self.stream)
843
- print("# class %s_Impl(object):" % body.itf.name, file=self.stream)
836
+ print(f"# code template for {body.itf.name} implementation", file=self.stream)
837
+ print(f"# class {body.itf.name}_Impl(object):", file=self.stream)
844
838
 
845
839
  methods = {}
846
840
  for m in body.itf.members:
@@ -862,43 +856,43 @@ class CodeGenerator(object):
862
856
  for name, (typ, inargs, outargs, doc) in methods.items():
863
857
  if typ == 0: # method
864
858
  print(
865
- "# def %s(%s):" % (name, ", ".join(["self"] + inargs)),
859
+ f"# def {name}({', '.join(['self'] + inargs)}):",
866
860
  file=self.stream,
867
861
  )
868
- print("# %r" % (doc or "-no docstring-"), file=self.stream)
869
- print("# #return %s" % (", ".join(outargs)), file=self.stream)
862
+ print(f"# {(doc or '-no docstring-')!r}", file=self.stream)
863
+ print(f"# #return {', '.join(outargs)}", file=self.stream)
870
864
  elif typ == 1: # propget
871
865
  print("# @property", file=self.stream)
872
866
  print(
873
- "# def %s(%s):" % (name, ", ".join(["self"] + inargs)),
867
+ f"# def {name}({', '.join(['self'] + inargs)}):",
874
868
  file=self.stream,
875
869
  )
876
- print("# %r" % (doc or "-no docstring-"), file=self.stream)
877
- print("# #return %s" % (", ".join(outargs)), file=self.stream)
870
+ print(f"# {(doc or '-no docstring-')!r}", file=self.stream)
871
+ print(f"# #return {', '.join(outargs)}", file=self.stream)
878
872
  elif typ == 2: # propput
879
873
  print(
880
- "# def _set(%s):" % ", ".join(["self"] + inargs + outargs),
874
+ f"# def _set({', '.join(['self'] + inargs + outargs)}):",
881
875
  file=self.stream,
882
876
  )
883
- print("# %r" % (doc or "-no docstring-"), file=self.stream)
877
+ print(f"# {(doc or '-no docstring-')!r}", file=self.stream)
884
878
  print(
885
- "# %s = property(fset = _set, doc = _set.__doc__)" % name,
879
+ f"# {name} = property(fset = _set, doc = _set.__doc__)",
886
880
  file=self.stream,
887
881
  )
888
882
  elif typ == 3: # propget + propput
889
883
  print(
890
- "# def _get(%s):" % ", ".join(["self"] + inargs),
884
+ f"# def _get({', '.join(['self'] + inargs)}):",
891
885
  file=self.stream,
892
886
  )
893
- print("# %r" % (doc or "-no docstring-"), file=self.stream)
894
- print("# #return %s" % (", ".join(outargs)), file=self.stream)
887
+ print(f"# {(doc or '-no docstring-')!r}", file=self.stream)
888
+ print(f"# #return {', '.join(outargs)}", file=self.stream)
895
889
  print(
896
- "# def _set(%s):" % ", ".join(["self"] + inargs + outargs),
890
+ f"# def _set({', '.join(['self'] + inargs + outargs)}):",
897
891
  file=self.stream,
898
892
  )
899
- print("# %r" % (doc or "-no docstring-"), file=self.stream)
893
+ print(f"# {(doc or '-no docstring-')!r}", file=self.stream)
900
894
  print(
901
- "# %s = property(_get, _set, doc = _set.__doc__)" % name,
895
+ f"# {name} = property(_get, _set, doc = _set.__doc__)",
902
896
  file=self.stream,
903
897
  )
904
898
  else:
@@ -921,12 +915,12 @@ class CodeGenerator(object):
921
915
 
922
916
  self.last_item_class = True
923
917
 
924
- print("class %s(%s):" % (head.itf.name, basename), file=self.stream)
918
+ print(f"class {head.itf.name}({basename}):", file=self.stream)
925
919
  if head.itf.doc:
926
920
  print(self._to_docstring(head.itf.doc), file=self.stream)
927
921
  print(" _case_insensitive_ = True", file=self.stream)
928
- print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
929
- print(" _idlflags_ = %s" % head.itf.idlflags, file=self.stream)
922
+ print(f" _iid_ = GUID({head.itf.iid!r})", file=self.stream)
923
+ print(f" _idlflags_ = {head.itf.idlflags}", file=self.stream)
930
924
  print(" _methods_ = []", file=self.stream)
931
925
 
932
926
  annotations = typeannotator.DispInterfaceMembersAnnotator(head.itf).generate()
@@ -955,7 +949,7 @@ class CodeGenerator(object):
955
949
 
956
950
  self.last_item_class = False
957
951
 
958
- print("%s._disp_methods_ = [" % body.itf.name, file=self.stream)
952
+ print(f"{body.itf.name}._disp_methods_ = [", file=self.stream)
959
953
  for m in body.itf.members:
960
954
  if isinstance(m, typedesc.DispMethod):
961
955
  self.make_DispMethod(m)
@@ -22,7 +22,7 @@ class dispid(object):
22
22
  self.memid = memid
23
23
 
24
24
  def __repr__(self):
25
- return "dispid(%s)" % self.memid
25
+ return f"dispid({self.memid})"
26
26
 
27
27
 
28
28
  class helpstring(object):
@@ -30,7 +30,7 @@ class helpstring(object):
30
30
  self.text = text
31
31
 
32
32
  def __repr__(self):
33
- return "helpstring(%r)" % self.text
33
+ return f"helpstring({self.text!r})"
34
34
 
35
35
 
36
36
  # XXX Should this be in ctypes itself?
@@ -299,22 +299,22 @@ class TypeNamer(object):
299
299
  # to refer to the type. Assumes the 'from ctypes import *'
300
300
  # namespace is available.
301
301
  if isinstance(t, typedesc.SAFEARRAYType):
302
- return "_midlSAFEARRAY(%s)" % self(t.typ)
302
+ return f"_midlSAFEARRAY({self(t.typ)})"
303
303
  # if isinstance(t, typedesc.CoClass):
304
304
  # return "%s._com_interfaces_[0]" % t.name
305
305
  if isinstance(t, typedesc.Typedef):
306
306
  return t.name
307
307
  if isinstance(t, typedesc.PointerType):
308
308
  _t, pcnt = self._inspect_PointerType(t)
309
- return "%s%s%s" % ("POINTER(" * pcnt, self(_t), ")" * pcnt)
309
+ return f"{'POINTER(' * pcnt}{self(_t)}{')' * pcnt}"
310
310
  elif isinstance(t, typedesc.ArrayType):
311
- return "%s * %s" % (self(t.typ), int(t.max) + 1)
311
+ return f"{self(t.typ)} * {int(t.max) + 1}"
312
312
  elif isinstance(t, typedesc.FunctionType):
313
313
  args = [self(x) for x in [t.returns] + list(t.iterArgTypes())]
314
314
  if "__stdcall__" in t.attributes:
315
- return "WINFUNCTYPE(%s)" % ", ".join(args)
315
+ return f"WINFUNCTYPE({', '.join(args)})"
316
316
  else:
317
- return "CFUNCTYPE(%s)" % ", ".join(args)
317
+ return f"CFUNCTYPE({', '.join(args)})"
318
318
  elif isinstance(t, typedesc.CvQualifiedType):
319
319
  # const and volatile are ignored
320
320
  return "%s" % self(t.typ)
@@ -334,7 +334,7 @@ class TypeNamer(object):
334
334
  # t.symbol_name - symbol to generate
335
335
  # t.tlib - the ITypeLib pointer to the typelibrary containing the symbols definition
336
336
  modname = name_wrapper_module(t.tlib)
337
- return "%s.%s" % (modname, t.symbol_name)
337
+ return f"{modname}.{t.symbol_name}"
338
338
  return t.name
339
339
 
340
340
  def _inspect_PointerType(
@@ -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)