comtypes 1.4.8__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 (146) hide show
  1. {comtypes-1.4.8 → comtypes-1.4.9}/CHANGES.txt +21 -0
  2. {comtypes-1.4.8/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +2 -2
  3. {comtypes-1.4.8 → comtypes-1.4.9}/README.md +1 -1
  4. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
  5. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
  6. comtypes-1.4.9/comtypes/_comobject.py +507 -0
  7. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_memberspec.py +80 -8
  8. comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
  9. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +1 -1
  10. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +25 -171
  11. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
  12. comtypes-1.4.9/comtypes/_vtbl.py +448 -0
  13. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/automation.py +36 -45
  14. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_code_cache.py +4 -4
  15. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
  16. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_events.py +1 -1
  17. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_generate.py +4 -8
  18. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -2
  19. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
  20. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/git.py +1 -2
  21. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/hints.pyi +7 -15
  22. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/safearray.py +10 -0
  23. comtypes-1.4.9/comtypes/server/__init__.py +86 -0
  24. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
  25. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
  26. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/register.py +61 -73
  27. comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
  28. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/shelllink.py +3 -26
  29. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -11
  30. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
  31. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
  32. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
  33. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
  34. comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
  35. comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
  36. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -4
  37. comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
  38. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -12
  39. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
  40. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +7 -4
  41. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
  42. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
  43. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
  44. comtypes-1.4.9/comtypes/test/test_server.py +350 -0
  45. comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
  46. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
  47. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -17
  48. comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
  49. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
  50. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
  51. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
  52. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
  53. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
  54. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +7 -7
  55. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/typedesc.py +1 -6
  56. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/typeinfo.py +11 -22
  57. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
  58. {comtypes-1.4.8 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +2 -2
  59. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
  60. {comtypes-1.4.8 → comtypes-1.4.9}/pyproject.toml +1 -0
  61. comtypes-1.4.8/comtypes/_comobject.py +0 -833
  62. comtypes-1.4.8/comtypes/_idl_stuff.py +0 -67
  63. comtypes-1.4.8/comtypes/server/__init__.py +0 -70
  64. comtypes-1.4.8/comtypes/server/w_getopt.py +0 -75
  65. comtypes-1.4.8/comtypes/test/test_comserver.py +0 -239
  66. comtypes-1.4.8/comtypes/test/test_dispinterface.py +0 -137
  67. comtypes-1.4.8/comtypes/test/test_propputref.py +0 -40
  68. comtypes-1.4.8/comtypes/test/test_server.py +0 -354
  69. {comtypes-1.4.8 → comtypes-1.4.9}/LICENSE.txt +0 -0
  70. {comtypes-1.4.8 → comtypes-1.4.9}/MANIFEST.in +0 -0
  71. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_meta.py +0 -0
  72. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_npsupport.py +0 -0
  73. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +0 -0
  74. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
  75. /comtypes-1.4.8/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
  76. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
  77. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
  78. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/__init__.py +0 -0
  79. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
  80. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
  81. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
  82. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
  83. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
  84. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
  85. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/persist.py +0 -0
  86. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
  87. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
  88. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/stream.py +0 -0
  89. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
  90. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.py +0 -0
  91. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
  92. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
  93. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +0 -0
  94. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
  95. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -0
  96. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
  97. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
  98. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
  99. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
  100. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
  101. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
  102. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
  103. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
  104. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -0
  105. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
  106. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +0 -0
  107. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
  108. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
  109. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
  110. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
  111. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
  112. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
  113. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
  114. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
  115. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
  116. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
  117. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
  118. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
  119. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
  120. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
  121. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
  122. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
  123. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
  124. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
  125. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
  126. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +0 -0
  127. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
  128. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_stream.py +0 -0
  129. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
  130. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +0 -0
  131. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
  132. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +0 -0
  133. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
  134. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
  135. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
  136. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
  137. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  138. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +0 -0
  139. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +0 -0
  140. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
  141. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/util.py +0 -0
  142. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
  143. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
  144. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
  145. {comtypes-1.4.8 → comtypes-1.4.9}/setup.cfg +0 -0
  146. {comtypes-1.4.8 → comtypes-1.4.9}/setup.py +0 -0
@@ -1,19 +1,37 @@
1
1
  import unittest
2
-
3
- from ctypes import PyDLL, py_object, c_void_p, byref, POINTER
2
+ from ctypes import POINTER, PyDLL, byref, c_void_p, py_object
4
3
  from ctypes.wintypes import BOOL
5
4
 
6
- from comtypes import IUnknown
5
+ from comtypes import COMObject, IUnknown
6
+ from comtypes.automation import VARIANT, IDispatch
7
7
  from comtypes.client import CreateObject
8
- from comtypes.automation import IDispatch
9
- from comtypes.test import requires
10
8
 
11
- requires("pythoncom")
12
9
  try:
13
10
  import pythoncom
14
11
  import win32com.client
15
12
 
16
- skip = False
13
+ IMPORT_FAILED = False
14
+ # pywin32 is available. The pythoncom dll contains two handy
15
+ # exported functions that allow to create a VARIANT from a Python
16
+ # object, also a function that unpacks a VARIANT into a Python
17
+ # object.
18
+ #
19
+ # This allows us to create und unpack SAFEARRAY instances
20
+ # contained in VARIANTs, and check for consistency with the
21
+ # comtypes code.
22
+ _dll = PyDLL(pythoncom.__file__)
23
+
24
+ # c:/sf/pywin32/com/win32com/src/oleargs.cpp 213
25
+ # PyObject *PyCom_PyObjectFromVariant(const VARIANT *var)
26
+ unpack = _dll.PyCom_PyObjectFromVariant
27
+ unpack.restype = py_object
28
+ unpack.argtypes = (POINTER(VARIANT),)
29
+
30
+ # c:/sf/pywin32/com/win32com/src/oleargs.cpp 54
31
+ # BOOL PyCom_VariantFromPyObject(PyObject *obj, VARIANT *var)
32
+ _pack = _dll.PyCom_VariantFromPyObject
33
+ _pack.argtypes = py_object, POINTER(VARIANT)
34
+ _pack.restype = BOOL
17
35
  # We use the PyCom_PyObjectFromIUnknown function in pythoncom25.dll to
18
36
  # convert a comtypes COM pointer into a pythoncom COM pointer.
19
37
  # Fortunately this function is exported by the dll...
@@ -30,17 +48,58 @@ except ImportError:
30
48
  # if it is available since pythoncom is not a project dependency and adding tests depending
31
49
  # on the vagaries of various testing environments is not deterministic.
32
50
  # TODO: Evaluate if we should just remove this test or what.
33
- skip = True
51
+ IMPORT_FAILED = True
34
52
 
35
53
 
36
54
  def setUpModule():
37
- if skip:
55
+ if IMPORT_FAILED:
38
56
  raise unittest.SkipTest(
39
57
  "This test requires the pythoncom library installed. If this is "
40
58
  "important tests then we need to add dev dependencies to the project that include pythoncom."
41
59
  )
42
60
 
43
61
 
62
+ ################################################################
63
+
64
+
65
+ def pack(obj):
66
+ var = VARIANT()
67
+ _pack(obj, byref(var))
68
+ return var
69
+
70
+
71
+ class PyWinSafeArrayTest(unittest.TestCase):
72
+ def test_1dim(self):
73
+ data = (1, 2, 3)
74
+ variant = pack(data)
75
+ self.assertEqual(variant.value, data)
76
+ self.assertEqual(unpack(variant), data)
77
+
78
+ def test_2dim(self):
79
+ data = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
80
+ variant = pack(data)
81
+ self.assertEqual(variant.value, data)
82
+ self.assertEqual(unpack(variant), data)
83
+
84
+ def test_3dim(self):
85
+ data = (((1, 2), (3, 4), (5, 6)), ((7, 8), (9, 10), (11, 12)))
86
+ variant = pack(data)
87
+ self.assertEqual(variant.value, data)
88
+ self.assertEqual(unpack(variant), data)
89
+
90
+ def test_4dim(self):
91
+ data = (
92
+ (((1, 2), (3, 4)), ((5, 6), (7, 8))),
93
+ (((9, 10), (11, 12)), ((13, 14), (15, 16))),
94
+ )
95
+ variant = pack(data)
96
+ self.assertEqual(variant.value, data)
97
+ self.assertEqual(unpack(variant), data)
98
+
99
+
100
+ ################################################################
101
+
102
+
44
103
  def comtypes2pywin(ptr, interface=None):
45
104
  """Convert a comtypes pointer 'ptr' into a pythoncom
46
105
  PyI<interface> object.
@@ -56,9 +115,6 @@ def comtypes2pywin(ptr, interface=None):
56
115
  return _PyCom_PyObjectFromIUnknown(ptr, byref(interface._iid_), True)
57
116
 
58
117
 
59
- ################################################################
60
-
61
-
62
118
  def comtypes_get_refcount(ptr):
63
119
  """Helper function for testing: return the COM reference count of
64
120
  a comtypes COM object"""
@@ -66,9 +122,6 @@ def comtypes_get_refcount(ptr):
66
122
  return ptr.Release()
67
123
 
68
124
 
69
- from comtypes import COMObject
70
-
71
-
72
125
  class MyComObject(COMObject):
73
126
  """A completely trivial COM object implementing IDispatch. Calling
74
127
  any methods will return the error code E_NOTIMPL (except the
@@ -77,42 +130,33 @@ class MyComObject(COMObject):
77
130
  _com_interfaces_ = [IDispatch]
78
131
 
79
132
 
80
- ################################################################
81
-
82
-
83
- class Test(unittest.TestCase):
84
- def tearDown(self):
85
- if hasattr(self, "ie"):
86
- self.ie.Quit()
87
- del self.ie
88
-
133
+ class ConvertComtypesPtrToPythonComObjTest(unittest.TestCase):
89
134
  def test_mycomobject(self):
90
135
  o = MyComObject()
91
136
  p = comtypes2pywin(o, IDispatch)
92
137
  disp = win32com.client.Dispatch(p)
93
138
  self.assertEqual(repr(disp), "<COMObject <unknown>>")
94
139
 
95
- def test_ie(self):
96
- # Convert a comtypes COM interface pointer into a win32com COM
97
- # pointer.
98
- ie = self.ie = CreateObject("InternetExplorer.Application")
140
+ def test_refcount(self):
141
+ # Convert a comtypes COM interface pointer into a win32com COM pointer.
142
+ dic = CreateObject("Scripting.Dictionary")
99
143
  # The COM refcount of the created object is 1:
100
- self.assertEqual(comtypes_get_refcount(ie), 1)
101
- # IE starts invisible:
102
- self.assertEqual(ie.Visible, False)
144
+ self.assertEqual(comtypes_get_refcount(dic), 1)
145
+ dic["foo"] = "bar"
146
+ self.assertEqual(dic.Item("foo"), "bar")
103
147
 
104
148
  # Create a pythoncom PyIDispatch object from it:
105
- p = comtypes2pywin(ie, interface=IDispatch)
106
- self.assertEqual(comtypes_get_refcount(ie), 2)
149
+ p = comtypes2pywin(dic, interface=IDispatch)
150
+ self.assertEqual(comtypes_get_refcount(dic), 2)
107
151
 
108
152
  # Make it usable...
109
153
  disp = win32com.client.Dispatch(p)
110
- self.assertEqual(comtypes_get_refcount(ie), 2)
111
- self.assertEqual(disp.Visible, False)
154
+ self.assertEqual(comtypes_get_refcount(dic), 2)
155
+ self.assertEqual(disp.Item("foo"), "bar")
112
156
 
113
157
  # Cleanup and make sure that the COM refcounts are correct
114
158
  del p, disp
115
- self.assertEqual(comtypes_get_refcount(ie), 1)
159
+ self.assertEqual(comtypes_get_refcount(dic), 1)
116
160
 
117
161
 
118
162
  if __name__ == "__main__":
@@ -1,9 +1,6 @@
1
1
  import unittest as ut
2
2
 
3
3
  from comtypes.client import CoGetObject
4
- from comtypes.test import requires
5
-
6
- requires("time")
7
4
 
8
5
 
9
6
  # WMI has dual interfaces.
@@ -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(
@@ -25,20 +25,20 @@ def _calc_packing(struct, fields, pack, isStruct):
25
25
  size += a - size % a
26
26
  if isStruct:
27
27
  if size != f.offset:
28
- raise PackingError("field %s offset (%s/%s)" % (f.name, size, f.offset))
28
+ raise PackingError(f"field {f.name} offset ({size}/{f.offset})")
29
29
  size += s
30
30
  else:
31
31
  size = max(size, s)
32
32
  total_align = max(total_align, a)
33
33
  if total_align != struct.align:
34
- raise PackingError("total alignment (%s/%s)" % (total_align, struct.align))
34
+ raise PackingError(f"total alignment ({total_align}/{struct.align})")
35
35
  a = total_align
36
36
  if pack is not None:
37
37
  a = min(pack, a)
38
38
  if size % a:
39
39
  size += a - size % a
40
40
  if size != struct.size:
41
- raise PackingError("total size (%s/%s)" % (size, struct.size))
41
+ raise PackingError(f"total size ({size}/{struct.size})")
42
42
 
43
43
 
44
44
  def calc_packing(struct, fields):
@@ -55,7 +55,7 @@ def calc_packing(struct, fields):
55
55
 
56
56
  return int(pack / 8)
57
57
 
58
- raise PackingError("PACKING FAILED: %s" % details)
58
+ raise PackingError(f"PACKING FAILED: {details}")
59
59
 
60
60
 
61
61
  class PackingError(Exception):
@@ -1,19 +1,19 @@
1
1
  import abc
2
2
  import keyword
3
- from typing import Any, Generic, TypeVar, TYPE_CHECKING
3
+ from typing import Any, Generic, Protocol, TypeVar
4
4
  from typing import Dict, List, Optional, Sequence, Tuple
5
5
  from typing import Iterable, Iterator
6
6
 
7
7
  from comtypes.tools import typedesc
8
8
 
9
- if TYPE_CHECKING:
10
- from comtypes import hints
11
9
 
10
+ class _MethodTypeDesc(Protocol):
11
+ arguments: List[Tuple[Any, str, List[str], Optional[Any]]]
12
+ idlflags: List[str]
13
+ name: str
12
14
 
13
- if TYPE_CHECKING:
14
- _T_MTD = TypeVar("_T_MTD", bound=hints._MethodTypeDesc)
15
- else:
16
- _T_MTD = TypeVar("_T_MTD")
15
+
16
+ _T_MTD = TypeVar("_T_MTD", bound=_MethodTypeDesc)
17
17
 
18
18
 
19
19
  class _MethodAnnotator(abc.ABC, Generic[_T_MTD]):