Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9d2e1b0

Browse files
committedJan 3, 2023
mypy: test_concurrency.py, test_python.py
1 parent c3ee30c commit 9d2e1b0

File tree

4 files changed

+76
-59
lines changed

4 files changed

+76
-59
lines changed
 

‎tests/mixins.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import sys
1414

1515
from typing import Iterator, Tuple
16+
from typing import Iterable, Optional
1617

1718
import pytest
1819

@@ -24,26 +25,26 @@ class PytestBase:
2425
"""A base class to connect to pytest in a test class hierarchy."""
2526

2627
@pytest.fixture(autouse=True)
27-
def connect_to_pytest(self, request, monkeypatch):
28+
def connect_to_pytest(self, request, monkeypatch) -> None:
2829
"""Captures pytest facilities for use by other test helpers."""
2930
# pylint: disable=attribute-defined-outside-init
3031
self._pytest_request = request
3132
self._monkeypatch = monkeypatch
3233
self.setUp()
3334

34-
def setUp(self):
35+
def setUp(self) -> None:
3536
"""Per-test initialization. Override this as you wish."""
3637
pass
3738

38-
def addCleanup(self, fn, *args):
39+
def addCleanup(self, fn, *args) -> None:
3940
"""Like unittest's addCleanup: code to call when the test is done."""
4041
self._pytest_request.addfinalizer(lambda: fn(*args))
4142

42-
def set_environ(self, name, value):
43+
def set_environ(self, name, value) -> None:
4344
"""Set an environment variable `name` to be `value`."""
4445
self._monkeypatch.setenv(name, value)
4546

46-
def del_environ(self, name):
47+
def del_environ(self, name) -> None:
4748
"""Delete an environment variable, unless we set it."""
4849
self._monkeypatch.delenv(name, raising=False)
4950

@@ -72,7 +73,13 @@ def _temp_dir(self, tmp_path_factory: pytest.TempPathFactory) -> Iterator[None]:
7273
else:
7374
yield
7475

75-
def make_file(self, filename, text="", bytes=b"", newline=None):
76+
def make_file(
77+
self,
78+
filename: str,
79+
text: str="",
80+
bytes: bytes=b"",
81+
newline: Optional[str]=None,
82+
) -> str:
7683
"""Make a file. See `tests.helpers.make_file`"""
7784
# pylint: disable=redefined-builtin # bytes
7885
assert self.run_in_temp_dir, "Only use make_file when running in a temp dir"
@@ -83,15 +90,15 @@ class RestoreModulesMixin:
8390
"""Auto-restore the imported modules at the end of each test."""
8491

8592
@pytest.fixture(autouse=True)
86-
def _module_saving(self):
93+
def _module_saving(self) -> Iterable[None]:
8794
"""Remove modules we imported during the test."""
8895
self._sys_module_saver = SysModuleSaver()
8996
try:
9097
yield
9198
finally:
9299
self._sys_module_saver.restore()
93100

94-
def clean_local_file_imports(self):
101+
def clean_local_file_imports(self) -> None:
95102
"""Clean up the results of calls to `import_local_file`.
96103
97104
Use this if you need to `import_local_file` the same file twice in
@@ -120,7 +127,7 @@ class StdStreamCapturingMixin:
120127
121128
"""
122129
@pytest.fixture(autouse=True)
123-
def _capcapsys(self, capsys):
130+
def _capcapsys(self, capsys: pytest.CaptureFixture[str]) -> None:
124131
"""Grab the fixture so our methods can use it."""
125132
self.capsys = capsys
126133

‎tests/test_concurrency.py

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
import threading
1414
import time
1515

16+
from types import ModuleType
17+
from typing import Iterable, Optional
18+
1619
from flaky import flaky
1720
import pytest
1821

@@ -44,7 +47,7 @@
4447
greenlet = None
4548

4649

47-
def measurable_line(l):
50+
def measurable_line(l: str) -> bool:
4851
"""Is this a line of code coverage will measure?
4952
5053
Not blank, not a comment, and not "else"
@@ -59,12 +62,12 @@ def measurable_line(l):
5962
return True
6063

6164

62-
def line_count(s):
65+
def line_count(s: str) -> int:
6366
"""How many measurable lines are in `s`?"""
6467
return len(list(filter(measurable_line, s.splitlines())))
6568

6669

67-
def print_simple_annotation(code, linenos):
70+
def print_simple_annotation(code: str, linenos: Iterable[int]) -> None:
6871
"""Print the lines in `code` with X for each line number in `linenos`."""
6972
for lineno, line in enumerate(code.splitlines(), start=1):
7073
print(" {} {}".format("X" if lineno in linenos else " ", line))
@@ -75,7 +78,7 @@ class LineCountTest(CoverageTest):
7578

7679
run_in_temp_dir = False
7780

78-
def test_line_count(self):
81+
def test_line_count(self) -> None:
7982
CODE = """
8083
# Hey there!
8184
x = 1
@@ -169,7 +172,7 @@ def sum_range(limit):
169172
"""
170173

171174

172-
def cant_trace_msg(concurrency, the_module):
175+
def cant_trace_msg(concurrency: str, the_module: Optional[ModuleType]) -> Optional[str]:
173176
"""What might coverage.py say about a concurrency setting and imported module?"""
174177
# In the concurrency choices, "multiprocessing" doesn't count, so remove it.
175178
if "multiprocessing" in concurrency:
@@ -197,7 +200,13 @@ class ConcurrencyTest(CoverageTest):
197200

198201
QLIMIT = 1000
199202

200-
def try_some_code(self, code, concurrency, the_module, expected_out=None):
203+
def try_some_code(
204+
self,
205+
code: str,
206+
concurrency: str,
207+
the_module: ModuleType,
208+
expected_out: Optional[str]=None,
209+
) -> None:
201210
"""Run some concurrency testing code and see that it was all covered.
202211
203212
`code` is the Python code to execute. `concurrency` is the name of
@@ -232,39 +241,40 @@ def try_some_code(self, code, concurrency, the_module, expected_out=None):
232241
# If the test fails, it's helpful to see this info:
233242
fname = abs_file("try_it.py")
234243
linenos = data.lines(fname)
244+
assert linenos is not None
235245
print(f"{len(linenos)}: {linenos}")
236246
print_simple_annotation(code, linenos)
237247

238248
lines = line_count(code)
239249
assert line_counts(data)['try_it.py'] == lines
240250

241-
def test_threads(self):
251+
def test_threads(self) -> None:
242252
code = (THREAD + SUM_RANGE_Q + PRINT_SUM_RANGE).format(QLIMIT=self.QLIMIT)
243253
self.try_some_code(code, "thread", threading)
244254

245-
def test_threads_simple_code(self):
255+
def test_threads_simple_code(self) -> None:
246256
code = SIMPLE.format(QLIMIT=self.QLIMIT)
247257
self.try_some_code(code, "thread", threading)
248258

249-
def test_eventlet(self):
259+
def test_eventlet(self) -> None:
250260
code = (EVENTLET + SUM_RANGE_Q + PRINT_SUM_RANGE).format(QLIMIT=self.QLIMIT)
251261
self.try_some_code(code, "eventlet", eventlet)
252262

253-
def test_eventlet_simple_code(self):
263+
def test_eventlet_simple_code(self) -> None:
254264
code = SIMPLE.format(QLIMIT=self.QLIMIT)
255265
self.try_some_code(code, "eventlet", eventlet)
256266

257267
# https://github.com/nedbat/coveragepy/issues/663
258268
@pytest.mark.skipif(env.WINDOWS, reason="gevent has problems on Windows: #663")
259-
def test_gevent(self):
269+
def test_gevent(self) -> None:
260270
code = (GEVENT + SUM_RANGE_Q + PRINT_SUM_RANGE).format(QLIMIT=self.QLIMIT)
261271
self.try_some_code(code, "gevent", gevent)
262272

263-
def test_gevent_simple_code(self):
273+
def test_gevent_simple_code(self) -> None:
264274
code = SIMPLE.format(QLIMIT=self.QLIMIT)
265275
self.try_some_code(code, "gevent", gevent)
266276

267-
def test_greenlet(self):
277+
def test_greenlet(self) -> None:
268278
GREENLET = """\
269279
from greenlet import greenlet
270280
@@ -282,11 +292,11 @@ def test2(u):
282292
"""
283293
self.try_some_code(GREENLET, "greenlet", greenlet, "hello world\n42\n")
284294

285-
def test_greenlet_simple_code(self):
295+
def test_greenlet_simple_code(self) -> None:
286296
code = SIMPLE.format(QLIMIT=self.QLIMIT)
287297
self.try_some_code(code, "greenlet", greenlet)
288298

289-
def test_bug_330(self):
299+
def test_bug_330(self) -> None:
290300
BUG_330 = """\
291301
from weakref import WeakKeyDictionary
292302
import eventlet
@@ -304,7 +314,7 @@ def do():
304314
"""
305315
self.try_some_code(BUG_330, "eventlet", eventlet, "0\n")
306316

307-
def test_threads_with_gevent(self):
317+
def test_threads_with_gevent(self) -> None:
308318
self.make_file("both.py", """\
309319
import queue
310320
import threading
@@ -345,25 +355,25 @@ def gwork(q):
345355
last_line = self.squeezed_lines(out)[-1]
346356
assert re.search(r"TOTAL \d+ 0 100%", last_line)
347357

348-
def test_bad_concurrency(self):
358+
def test_bad_concurrency(self) -> None:
349359
with pytest.raises(ConfigError, match="Unknown concurrency choices: nothing"):
350360
self.command_line("run --concurrency=nothing prog.py")
351361

352-
def test_bad_concurrency_in_config(self):
362+
def test_bad_concurrency_in_config(self) -> None:
353363
self.make_file(".coveragerc", "[run]\nconcurrency = nothing\n")
354364
with pytest.raises(ConfigError, match="Unknown concurrency choices: nothing"):
355365
self.command_line("run prog.py")
356366

357-
def test_no_multiple_light_concurrency(self):
367+
def test_no_multiple_light_concurrency(self) -> None:
358368
with pytest.raises(ConfigError, match="Conflicting concurrency settings: eventlet, gevent"):
359369
self.command_line("run --concurrency=gevent,eventlet prog.py")
360370

361-
def test_no_multiple_light_concurrency_in_config(self):
371+
def test_no_multiple_light_concurrency_in_config(self) -> None:
362372
self.make_file(".coveragerc", "[run]\nconcurrency = gevent, eventlet\n")
363373
with pytest.raises(ConfigError, match="Conflicting concurrency settings: eventlet, gevent"):
364374
self.command_line("run prog.py")
365375

366-
def test_multiprocessing_needs_config_file(self):
376+
def test_multiprocessing_needs_config_file(self) -> None:
367377
with pytest.raises(ConfigError, match="multiprocessing requires a configuration file"):
368378
self.command_line("run --concurrency=multiprocessing prog.py")
369379

@@ -372,9 +382,9 @@ class WithoutConcurrencyModuleTest(CoverageTest):
372382
"""Tests of what happens if the requested concurrency isn't installed."""
373383

374384
@pytest.mark.parametrize("module", ["eventlet", "gevent", "greenlet"])
375-
def test_missing_module(self, module):
385+
def test_missing_module(self, module: str) -> None:
376386
self.make_file("prog.py", "a = 1")
377-
sys.modules[module] = None
387+
sys.modules[module] = None # type: ignore[assignment]
378388
msg = f"Couldn't trace with concurrency={module}, the module isn't installed."
379389
with pytest.raises(ConfigError, match=msg):
380390
self.command_line(f"run --concurrency={module} prog.py")
@@ -428,9 +438,9 @@ def process_worker_main(args):
428438

429439

430440
@pytest.fixture(params=["fork", "spawn"], name="start_method")
431-
def start_method_fixture(request):
441+
def start_method_fixture(request: pytest.FixtureRequest) -> str:
432442
"""Parameterized fixture to choose the start_method for multiprocessing."""
433-
start_method = request.param
443+
start_method: str = request.param
434444
if start_method not in multiprocessing.get_all_start_methods():
435445
# Windows doesn't support "fork".
436446
pytest.skip(f"start_method={start_method} not supported here")
@@ -443,14 +453,14 @@ class MultiprocessingTest(CoverageTest):
443453

444454
def try_multiprocessing_code(
445455
self,
446-
code,
447-
expected_out,
448-
the_module,
449-
nprocs,
450-
start_method,
451-
concurrency="multiprocessing",
452-
args="",
453-
):
456+
code: str,
457+
expected_out: Optional[str],
458+
the_module: ModuleType,
459+
nprocs: int,
460+
start_method: str,
461+
concurrency: str="multiprocessing",
462+
args: str="",
463+
) -> None:
454464
"""Run code using multiprocessing, it should produce `expected_out`."""
455465
self.make_file("multi.py", code)
456466
self.make_file(".coveragerc", f"""\
@@ -459,9 +469,7 @@ def try_multiprocessing_code(
459469
source = .
460470
""")
461471

462-
cmd = "coverage run {args} multi.py {start_method}".format(
463-
args=args, start_method=start_method,
464-
)
472+
cmd = f"coverage run {args} multi.py {start_method}"
465473
out = self.run_command(cmd)
466474
expected_cant_trace = cant_trace_msg(concurrency, the_module)
467475

@@ -489,7 +497,7 @@ def try_multiprocessing_code(
489497
last_line = self.squeezed_lines(out)[-1]
490498
assert re.search(r"TOTAL \d+ 0 100%", last_line)
491499

492-
def test_multiprocessing_simple(self, start_method):
500+
def test_multiprocessing_simple(self, start_method: str) -> None:
493501
nprocs = 3
494502
upto = 30
495503
code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
@@ -503,7 +511,7 @@ def test_multiprocessing_simple(self, start_method):
503511
start_method=start_method,
504512
)
505513

506-
def test_multiprocessing_append(self, start_method):
514+
def test_multiprocessing_append(self, start_method: str) -> None:
507515
nprocs = 3
508516
upto = 30
509517
code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
@@ -518,7 +526,7 @@ def test_multiprocessing_append(self, start_method):
518526
start_method=start_method,
519527
)
520528

521-
def test_multiprocessing_and_gevent(self, start_method):
529+
def test_multiprocessing_and_gevent(self, start_method: str) -> None:
522530
nprocs = 3
523531
upto = 30
524532
code = (
@@ -535,7 +543,7 @@ def test_multiprocessing_and_gevent(self, start_method):
535543
start_method=start_method,
536544
)
537545

538-
def test_multiprocessing_with_branching(self, start_method):
546+
def test_multiprocessing_with_branching(self, start_method: str) -> None:
539547
nprocs = 3
540548
upto = 30
541549
code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
@@ -559,7 +567,7 @@ def test_multiprocessing_with_branching(self, start_method):
559567
last_line = self.squeezed_lines(out)[-1]
560568
assert re.search(r"TOTAL \d+ 0 \d+ 0 100%", last_line)
561569

562-
def test_multiprocessing_bootstrap_error_handling(self):
570+
def test_multiprocessing_bootstrap_error_handling(self) -> None:
563571
# An exception during bootstrapping will be reported.
564572
self.make_file("multi.py", """\
565573
import multiprocessing
@@ -576,7 +584,7 @@ def test_multiprocessing_bootstrap_error_handling(self):
576584
assert "Exception during multiprocessing bootstrap init" in out
577585
assert "Exception: Crashing because called by _bootstrap" in out
578586

579-
def test_bug_890(self):
587+
def test_bug_890(self) -> None:
580588
# chdir in multiprocessing shouldn't keep us from finding the
581589
# .coveragerc file.
582590
self.make_file("multi.py", """\
@@ -596,11 +604,11 @@ def test_bug_890(self):
596604
assert out.splitlines()[-1] == "ok"
597605

598606

599-
def test_coverage_stop_in_threads():
607+
def test_coverage_stop_in_threads() -> None:
600608
has_started_coverage = []
601609
has_stopped_coverage = []
602610

603-
def run_thread(): # pragma: nested
611+
def run_thread() -> None: # pragma: nested
604612
"""Check that coverage is stopping properly in threads."""
605613
deadline = time.time() + 5
606614
ident = threading.current_thread().ident
@@ -648,7 +656,7 @@ def test_thread_safe_save_data(tmp_path: pathlib.Path) -> None:
648656
for module_name in module_names:
649657
import_local_file(module_name)
650658

651-
def random_load(): # pragma: nested
659+
def random_load() -> None: # pragma: nested
652660
"""Import modules randomly to stress coverage."""
653661
while should_run[0]:
654662
module_name = random.choice(module_names)
@@ -695,7 +703,7 @@ class SigtermTest(CoverageTest):
695703
"""Tests of our handling of SIGTERM."""
696704

697705
@pytest.mark.parametrize("sigterm", [False, True])
698-
def test_sigterm_saves_data(self, sigterm):
706+
def test_sigterm_saves_data(self, sigterm: bool) -> None:
699707
# A terminated process should save its coverage data.
700708
self.make_file("clobbered.py", """\
701709
import multiprocessing
@@ -741,7 +749,7 @@ def subproc(x):
741749
expected = "clobbered.py 17 5 71% 5-10"
742750
assert self.squeezed_lines(out)[2] == expected
743751

744-
def test_sigterm_still_runs(self):
752+
def test_sigterm_still_runs(self) -> None:
745753
# A terminated process still runs its own SIGTERM handler.
746754
self.make_file("handler.py", """\
747755
import multiprocessing

‎tests/test_python.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ class GetZipBytesTest(CoverageTest):
2424
"encoding",
2525
["utf-8", "gb2312", "hebrew", "shift_jis", "cp1252"],
2626
)
27-
def test_get_encoded_zip_files(self, encoding):
27+
def test_get_encoded_zip_files(self, encoding: str) -> None:
2828
# See igor.py, do_zipmods, for the text of these files.
2929
zip_file = "tests/zipmods.zip"
3030
sys.path.append(zip_file) # So we can import the files.
3131
filename = zip_file + "/encoded_" + encoding + ".py"
3232
filename = os_sep(filename)
3333
zip_data = get_zip_bytes(filename)
34+
assert zip_data is not None
3435
zip_text = zip_data.decode(encoding)
3536
assert 'All OK' in zip_text
3637
# Run the code to see that we really got it encoded properly.

‎tox.ini

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,9 @@ setenv =
101101
C_FN=coverage/files.py coverage/inorout.py coverage/jsonreport.py coverage/lcovreport.py coverage/multiproc.py coverage/numbits.py
102102
C_OP=coverage/parser.py coverage/phystokens.py coverage/plugin.py coverage/plugin_support.py coverage/python.py
103103
C_QZ=coverage/report.py coverage/results.py coverage/sqldata.py coverage/tomlconfig.py coverage/types.py coverage/version.py coverage/xmlreport.py
104-
T_AN=tests/test_annotate.py tests/test_api.py tests/test_arcs.py tests/test_cmdline.py tests/test_collector.py tests/goldtest.py tests/helpers.py tests/test_html.py tests/test_xml.py
105-
TYPEABLE={env:C__B} {env:C_CC} {env:C_DE} {env:C_FN} {env:C_OP} {env:C_QZ} {env:T_AN}
104+
T_AC=tests/test_annotate.py tests/test_api.py tests/test_arcs.py tests/test_cmdline.py tests/test_collector.py tests/test_concurrency.py
105+
T_DZ=tests/goldtest.py tests/helpers.py tests/test_html.py tests/test_python.py tests/test_xml.py
106+
TYPEABLE={env:C__B} {env:C_CC} {env:C_DE} {env:C_FN} {env:C_OP} {env:C_QZ} {env:T_AC} {env:T_DZ}
106107

107108
commands =
108109
# PYVERSIONS

0 commit comments

Comments
 (0)
Please sign in to comment.