Skip to content

Commit c1efe12

Browse files
committed
Cleanup com/win32com/test/testall.py
1 parent 84a050c commit c1efe12

File tree

1 file changed

+96
-93
lines changed

1 file changed

+96
-93
lines changed

com/win32com/test/testall.py

Lines changed: 96 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1+
from __future__ import annotations
2+
13
import getopt
24
import os
35
import re
6+
import shutil
47
import sys
58
import traceback
69
import unittest
7-
8-
try:
9-
this_file = __file__
10-
except NameError:
11-
this_file = sys.argv[0]
12-
13-
win32com_src_dir = os.path.abspath(os.path.join(this_file, "../.."))
10+
from collections.abc import Callable
11+
from textwrap import dedent
12+
from types import ModuleType
13+
from typing import NoReturn
1414

1515
import win32com
1616

17+
this_folder = os.path.dirname(__file__)
18+
win32com_src_dir = os.path.abspath(os.path.join(this_folder, ".."))
1719
# We'd prefer the win32com namespace to be the parent of __file__ - ie, our source-tree,
1820
# rather than the version installed - otherwise every .py change needs a full install to
1921
# test!
2022
# We can't patch win32comext as most of them have a .pyd in their root :(
21-
# This clearly ins't ideal or perfect :)
23+
# This clearly isn't ideal or perfect :)
2224
win32com.__path__[0] = win32com_src_dir
2325

2426
import pythoncom
25-
import win32com.client
27+
import win32com.client.gencache
2628
from pywin32_testutil import TestLoader, TestRunner
2729
from win32com.test.util import (
2830
CapturingFunctionTestCase,
@@ -35,32 +37,17 @@
3537
verbosity = 1 # default unittest verbosity.
3638

3739

38-
def GenerateAndRunOldStyle():
39-
from . import GenTestScripts
40-
41-
GenTestScripts.GenerateAll()
42-
try:
43-
pass #
44-
finally:
45-
GenTestScripts.CleanAll()
46-
47-
48-
def CleanGenerated():
49-
import shutil
50-
51-
import win32com
52-
40+
def CleanGenerated() -> None:
5341
if os.path.isdir(win32com.__gen_path__):
5442
if verbosity > 1:
55-
print("Deleting files from %s" % (win32com.__gen_path__))
43+
print(f"Deleting files from {win32com.__gen_path__}")
5644
shutil.rmtree(win32com.__gen_path__)
57-
import win32com.client.gencache
5845

5946
win32com.client.gencache.__init__() # Reset
6047

6148

62-
def RemoveRefCountOutput(data):
63-
while 1:
49+
def RemoveRefCountOutput(data: str) -> str:
50+
while True:
6451
last_line_pos = data.rfind("\n")
6552
if not re.match(r"\[\d+ refs\]", data[last_line_pos + 1 :]):
6653
break
@@ -72,47 +59,45 @@ def RemoveRefCountOutput(data):
7259
return data
7360

7461

75-
def ExecuteSilentlyIfOK(cmd, testcase):
62+
def ExecuteSilentlyIfOK(cmd: str, testcase: TestCase) -> str:
7663
f = os.popen(cmd)
7764
data = f.read().strip()
7865
rc = f.close()
7966
if rc:
8067
print(data)
81-
testcase.fail("Executing '%s' failed (%d)" % (cmd, rc))
68+
testcase.fail(f"Executing '{cmd}' failed ({rc})")
8269
# for "_d" builds, strip the '[xxx refs]' line
8370
return RemoveRefCountOutput(data)
8471

8572

8673
class PyCOMTest(TestCase):
8774
no_leak_tests = True # done by the test itself
8875

89-
def testit(self):
76+
def testit(self) -> None:
9077
# Check that the item is registered, so we get the correct
9178
# 'skipped' behaviour (and recorded as such) rather than either
9279
# error or silence due to non-registration.
9380
RegisterPythonServer(
94-
os.path.join(
95-
os.path.dirname(__file__), "..", "servers", "test_pycomtest.py"
96-
),
81+
os.path.join(win32com_src_dir, "servers", "test_pycomtest.py"),
9782
"Python.Test.PyCOMTest",
9883
)
9984

10085
# Execute testPyComTest in its own process so it can play
10186
# with the Python thread state
102-
fname = os.path.join(os.path.dirname(this_file), "testPyComTest.py")
87+
fname = os.path.join(this_folder, "testPyComTest.py")
10388
cmd = f'{sys.executable} "{fname}" -q 2>&1'
10489
data = ExecuteSilentlyIfOK(cmd, self)
10590

10691

10792
class PippoTest(TestCase):
108-
def testit(self):
93+
def testit(self) -> None:
10994
# Check we are registered before spawning the process.
11095
from win32com.test import pippo_server
11196

11297
RegisterPythonServer(pippo_server.__file__, "Python.Test.Pippo")
11398

11499
python = sys.executable
115-
fname = os.path.join(os.path.dirname(this_file), "testPippo.py")
100+
fname = os.path.join(this_folder, "testPippo.py")
116101
cmd = f'{python} "{fname}" 2>&1'
117102
ExecuteSilentlyIfOK(cmd, self)
118103

@@ -121,35 +106,44 @@ def testit(self):
121106
# function in that module if the module isn't unitest based...
122107
unittest_modules = [
123108
# Level 1 tests - fast and few dependencies - good for CI!
124-
"""testIterators testvbscript_regexp testStorage
125-
testStreams testWMI policySemantics testShell testROT
126-
testxslt testCollections
127-
errorSemantics.test testArrays
128-
testClipboard
129-
testConversionErrors
130-
""".split(),
109+
[
110+
"testIterators",
111+
"testvbscript_regexp",
112+
"testStorage",
113+
"testStreams",
114+
"testWMI",
115+
"policySemantics",
116+
"testShell",
117+
"testROT",
118+
"testxslt",
119+
"testCollections",
120+
"errorSemantics.test",
121+
"testArrays",
122+
"testClipboard",
123+
"testConversionErrors",
124+
],
131125
# Level 2 tests - wants our demo COM objects registered.
132126
# (these are strange; on github CI they get further than expected when
133127
# our objects are not installed, so fail to quietly fail with "can't
134128
# register" like they do locally. So really just a nod to CI)
135-
"""
136-
testAXScript testDictionary testServers testvb testMarshal
137-
""".split(),
129+
["testAXScript", "testDictionary", "testServers", "testvb", "testMarshal"],
138130
# Level 3 tests - Requires Office or other non-free stuff.
139-
"""testMSOffice.TestAll testMSOfficeEvents.test testAccess.test
140-
testExplorer.TestAll testExchange.test
141-
""".split(),
131+
[
132+
"testMSOffice.TestAll",
133+
"testMSOfficeEvents.test",
134+
"testAccess.test",
135+
"testExplorer.TestAll",
136+
"testExchange.test",
137+
],
142138
# Level 4 tests - we try and run `makepy` over every typelib installed!
143-
"""testmakepy.TestAll
144-
""".split(),
139+
["testmakepy.TestAll"],
145140
]
146141

147142
# A list of other unittest modules we use - these are fully qualified module
148143
# names and the module is assumed to be unittest based.
149144
unittest_other_modules = [
150145
# Level 1 tests.
151-
"""win32com.directsound.test.ds_test
152-
""".split(),
146+
["win32com.directsound.test.ds_test"],
153147
# Level 2 tests.
154148
[],
155149
# Level 3 tests.
@@ -192,7 +186,9 @@ def testit(self):
192186
]
193187

194188

195-
def get_test_mod_and_func(test_name, import_failures):
189+
def get_test_mod_and_func(
190+
test_name: str, import_failures: list[tuple[str, BaseException]]
191+
) -> tuple[None, None] | tuple[ModuleType, Callable[[], object] | None]:
196192
if test_name.find(".") > 0:
197193
mod_name, func_name = test_name.split(".")
198194
else:
@@ -202,19 +198,21 @@ def get_test_mod_and_func(test_name, import_failures):
202198
try:
203199
__import__(fq_mod_name)
204200
mod = sys.modules[fq_mod_name]
205-
except:
206-
import_failures.append((mod_name, sys.exc_info()[:2]))
201+
except Exception as error:
202+
import_failures.append((mod_name, error))
207203
return None, None
208204
func = None if func_name is None else getattr(mod, func_name)
209205
return mod, func
210206

211207

212208
# Return a test suite all loaded with the tests we want to run
213-
def make_test_suite(test_level=1):
209+
def make_test_suite(
210+
test_level: int,
211+
) -> tuple[unittest.TestSuite, list[tuple[str, BaseException]]]:
214212
suite = unittest.TestSuite()
215-
import_failures = []
213+
import_failures: list[tuple[str, BaseException]] = []
216214
loader = TestLoader()
217-
for i in range(testLevel):
215+
for i in range(test_level):
218216
for mod_name in unittest_modules[i]:
219217
mod, func = get_test_mod_and_func(mod_name, import_failures)
220218
if mod is None:
@@ -234,12 +232,12 @@ def make_test_suite(test_level=1):
234232
for test_class in custom_test_cases[i]:
235233
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(test_class))
236234
# other "normal" unittest modules.
237-
for i in range(testLevel):
235+
for i in range(test_level):
238236
for mod_name in unittest_other_modules[i]:
239237
try:
240238
__import__(mod_name)
241-
except:
242-
import_failures.append((mod_name, sys.exc_info()[:2]))
239+
except Exception as error:
240+
import_failures.append((mod_name, error))
243241
continue
244242

245243
mod = sys.modules[mod_name]
@@ -253,13 +251,15 @@ def make_test_suite(test_level=1):
253251
return suite, import_failures
254252

255253

256-
def usage(why):
257-
print(why)
258-
print()
259-
print("win32com test suite")
260-
print("usage: testall [-v] test_level")
261-
print(" where test_level is an integer 1-3. Level 1 tests are quick,")
262-
print(" level 2 tests invoke Word, IE etc, level 3 take ages!")
254+
def usage(why: str) -> NoReturn:
255+
print(f"""\
256+
{why}
257+
258+
win32com test suite
259+
usage: testall [-v] test_level
260+
where test_level is an integer 1-4. Level 1 tests are quick,
261+
level 2 tests invoke Word, IE etc, level 3 take ages!
262+
level 4 we try and run `makepy` over every typelib installed""")
263263
sys.exit(1)
264264

265265

@@ -271,44 +271,47 @@ def usage(why):
271271
for opt, val in opts:
272272
if opt == "-v":
273273
verbosity += 1
274-
testLevel = 2 # default to quick test with local objects
275-
test_names = []
276-
for arg in args:
277-
try:
278-
testLevel = int(arg)
279-
if testLevel < 0 or testLevel > 4:
280-
raise ValueError("Only levels 1-4 are supported")
281-
except ValueError:
282-
test_names.append(arg)
283-
if test_names:
274+
275+
if len(args) > 1:
276+
usage(
277+
"Only a single test level argument is supported. "
278+
+ "Test names are not supported yet"
279+
)
280+
try:
281+
test_level = int(args[0])
282+
except IndexError:
283+
test_level = 2 # default to quick test with local objects
284+
except ValueError:
284285
usage("Test names are not supported yet")
286+
if test_level < 1 or test_level > 4:
287+
usage("Only levels 1-4 are supported")
285288
CleanGenerated()
286289

287-
suite, import_failures = make_test_suite(testLevel)
290+
suite, import_failures = make_test_suite(test_level)
288291
if verbosity:
289292
if hasattr(sys, "gettotalrefcount"):
290-
print("This is a debug build - memory leak tests will also be run.")
291-
print("These tests may take *many* minutes to run - be patient!")
292-
print("(running from python.exe will avoid these leak tests)")
293+
print(
294+
dedent("""\
295+
This is a debug build - memory leak tests will also be run.
296+
These tests may take *many* minutes to run - be patient!
297+
(running from python.exe will avoid these leak tests""")
298+
)
293299
print(
294-
"Executing level %d tests - %d test cases will be run"
295-
% (testLevel, suite.countTestCases())
300+
f"Executing level {test_level} tests "
301+
+ f"- {suite.countTestCases()} test cases will be run"
296302
)
297303
if verbosity == 1 and suite.countTestCases() < 70:
298304
# A little row of markers so the dots show how close to finished
299305
print("|" * suite.countTestCases())
300-
testRunner = TestRunner(verbosity=verbosity)
301-
testResult = testRunner.run(suite)
306+
testResult = TestRunner(verbosity=verbosity).run(suite)
302307
if import_failures:
303308
testResult.stream.writeln(
304309
"*** The following test modules could not be imported ***"
305310
)
306-
for mod_name, (exc_type, exc_val) in import_failures:
307-
desc = "\n".join(traceback.format_exception_only(exc_type, exc_val))
311+
for mod_name, error in import_failures:
312+
desc = "\n".join(traceback.format_exception_only(type(error), error))
308313
testResult.stream.write(f"{mod_name}: {desc}")
309-
testResult.stream.writeln(
310-
"*** %d test(s) could not be run ***" % len(import_failures)
311-
)
314+
testResult.stream.writeln(f"*** {import_failures} test(s) could not be run ***")
312315

313316
# re-print unit-test error here so it is noticed
314317
if not testResult.wasSuccessful():

0 commit comments

Comments
 (0)