Skip to content

Commit 316af67

Browse files
committed
build: hide extensions, skip branch sysmon on 3.12/3.13
1 parent 2229ae7 commit 316af67

File tree

7 files changed

+66
-39
lines changed

7 files changed

+66
-39
lines changed

igor.py

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -52,52 +52,50 @@ def do_show_env():
5252
print(f" {env} = {os.environ[env]!r}")
5353

5454

55-
def do_remove_extension(*args):
55+
def remove_extension(core):
5656
"""Remove the compiled C extension, no matter what its name."""
5757

58+
if core == "ctrace":
59+
return
60+
5861
so_patterns = """
5962
tracer.so
6063
tracer.*.so
6164
tracer.pyd
6265
tracer.*.pyd
6366
""".split()
6467

65-
if "--from-install" in args:
66-
# Get the install location using a subprocess to avoid
67-
# locking the file we are about to delete
68-
root = os.path.dirname(
69-
subprocess.check_output(
70-
[
71-
sys.executable,
72-
"-Xutf8",
73-
"-c",
74-
"import coverage; print(coverage.__file__)",
75-
],
76-
encoding="utf-8",
77-
).strip(),
78-
)
79-
roots = [root]
80-
else:
81-
roots = [
82-
"coverage",
83-
"build/*/coverage",
84-
".tox/*/[Ll]ib/*/site-packages/coverage",
85-
".tox/*/[Ll]ib/site-packages/coverage",
86-
]
68+
roots = [
69+
"coverage",
70+
"build/*/coverage",
71+
".tox/*/[Ll]ib/*/site-packages/coverage",
72+
".tox/*/[Ll]ib/site-packages/coverage",
73+
]
8774

75+
# On windows at least, we can't delete a loaded .pyd file. So move them
76+
# out of the way into the tmp/ directory.
77+
os.makedirs("tmp", exist_ok=True)
8878
for root, pattern in itertools.product(roots, so_patterns):
8979
pattern = os.path.join(root, pattern)
9080
if VERBOSITY > 1:
9181
print(f"Searching for {pattern} from {os.getcwd()}")
9282
for filename in glob.glob(pattern):
9383
if os.path.exists(filename):
84+
hidden = f"tmp/{os.path.basename(filename)}"
9485
if VERBOSITY > 1:
95-
print(f"Removing {os.path.abspath(filename)}")
86+
print(f"Moving {filename} to {hidden}")
9687
try:
97-
os.remove(filename)
88+
if os.path.exists(hidden):
89+
os.remove(hidden)
9890
except OSError as exc:
9991
if VERBOSITY > 1:
100-
print(f"Couldn't remove {os.path.abspath(filename)}: {exc}")
92+
print(f"Couldn't remove {hidden}: {exc}")
93+
else:
94+
try:
95+
os.rename(filename, hidden)
96+
except OSError as exc:
97+
if VERBOSITY > 1:
98+
print(f"Couldn't rename: {exc}")
10199

102100

103101
def label_for_core(core):
@@ -112,14 +110,17 @@ def label_for_core(core):
112110
raise ValueError(f"Bad core: {core!r}")
113111

114112

115-
def should_skip(core):
113+
def should_skip(core, metacov):
116114
"""Is there a reason to skip these tests?
117115
118116
Return empty string to run tests, or a message about why we are skipping
119117
the tests.
120118
"""
121119
skipper = ""
122120

121+
if metacov and core == "sysmon" and ((3, 12) <= sys.version_info < (3, 14)):
122+
skipper = "sysmon can't measure branches in Python 3.12-3.13"
123+
123124
# $set_env.py: COVERAGE_TEST_CORES - List of cores to run: ctrace, pytrace, sysmon
124125
test_cores = os.getenv("COVERAGE_TEST_CORES")
125126
if test_cores:
@@ -140,7 +141,8 @@ def should_skip(core):
140141
skipper = f"No C core for {platform.python_implementation()}"
141142

142143
if skipper:
143-
return f"Skipping tests {label_for_core(core)}: {skipper}"
144+
what = "metacov" if metacov else "tests"
145+
return f"Skipping {what} {label_for_core(core)}: {skipper}"
144146
else:
145147
return ""
146148

@@ -157,10 +159,10 @@ def make_env_id(core):
157159

158160
def run_tests(core, *runner_args):
159161
"""The actual running of tests."""
162+
remove_extension(core)
160163
if "COVERAGE_TESTING" not in os.environ:
161164
os.environ["COVERAGE_TESTING"] = "True"
162165
print_banner(label_for_core(core))
163-
164166
return pytest.main(list(runner_args))
165167

166168

@@ -209,6 +211,8 @@ def run_tests_with_coverage(core, *runner_args):
209211
if getattr(mod, "__file__", "??").startswith(covdir):
210212
covmods[name] = mod
211213
del sys.modules[name]
214+
remove_extension(core)
215+
212216
import coverage # pylint: disable=reimported
213217

214218
sys.modules.update(covmods)
@@ -246,15 +250,17 @@ def do_combine_html():
246250

247251
def do_test_with_core(core, *runner_args):
248252
"""Run tests with a particular core."""
253+
metacov = os.getenv("COVERAGE_COVERAGE", "no") == "yes"
254+
249255
# If we should skip these tests, skip them.
250-
skip_msg = should_skip(core)
256+
skip_msg = should_skip(core, metacov)
251257
if skip_msg:
252258
if VERBOSITY > 0:
253259
print(skip_msg)
254260
return None
255261

256262
os.environ["COVERAGE_CORE"] = core
257-
if os.getenv("COVERAGE_COVERAGE", "no") == "yes":
263+
if metacov:
258264
return run_tests_with_coverage(core, *runner_args)
259265
else:
260266
return run_tests(core, *runner_args)

tests/test_cmdline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,7 @@ def test_version(self) -> None:
13721372
self.command_line("--version")
13731373
out = self.stdout()
13741374
assert "ersion " in out
1375-
if testenv.C_TRACER or testenv.SYS_MON:
1375+
if testenv.C_TRACER:
13761376
assert "with C extension" in out
13771377
else:
13781378
assert "without C extension" in out

tests/test_concurrency.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,16 @@ def try_some_code(
251251
lines = line_count(code)
252252
assert line_counts(data)["try_it.py"] == lines
253253

254+
@pytest.mark.skipif(
255+
not testenv.CAN_MEASURE_THREADS, reason="Can't measure threads with this core."
256+
)
254257
def test_threads(self) -> None:
255258
code = (THREAD + SUM_RANGE_Q + PRINT_SUM_RANGE).format(QLIMIT=self.QLIMIT)
256259
self.try_some_code(code, "thread", threading)
257260

261+
@pytest.mark.skipif(
262+
not testenv.CAN_MEASURE_THREADS, reason="Can't measure threads with this core."
263+
)
258264
def test_threads_simple_code(self) -> None:
259265
code = SIMPLE.format(QLIMIT=self.QLIMIT)
260266
self.try_some_code(code, "thread", threading)
@@ -318,6 +324,9 @@ def do():
318324
self.try_some_code(BUG_330, "eventlet", eventlet, "0\n")
319325

320326
# Sometimes a test fails due to inherent randomness. Try more times.
327+
@pytest.mark.skipif(
328+
not testenv.CAN_MEASURE_THREADS, reason="Can't measure threads with this core."
329+
)
321330
@pytest.mark.flaky(max_runs=3)
322331
def test_threads_with_gevent(self) -> None:
323332
self.make_file(
@@ -554,6 +563,9 @@ def test_multiprocessing_and_gevent(self, start_method: str) -> None:
554563
start_method=start_method,
555564
)
556565

566+
@pytest.mark.skipif(
567+
not testenv.CAN_MEASURE_BRANCHES, reason="Can't measure branches with this core"
568+
)
557569
def test_multiprocessing_with_branching(self, start_method: str) -> None:
558570
nprocs = 3
559571
upto = 30

tests/test_debug.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def test_debug_sys(self) -> None:
231231
def test_debug_sys_ctracer(self) -> None:
232232
out_text = self.f1_debug_output(["sys"])
233233
tracer_line = re_line(r"CTracer:", out_text).strip()
234-
if testenv.C_TRACER or testenv.SYS_MON:
234+
if testenv.C_TRACER:
235235
assert tracer_line.startswith("CTracer: available from ")
236236
else:
237237
assert tracer_line == "CTracer: unavailable"

tests/test_process.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,9 @@ def test_subprocess_in_directories(self) -> None:
15161516
assert line_counts(data)["main.py"] == 6
15171517
assert line_counts(data)["subproc.py"] == 2
15181518

1519+
@pytest.mark.skipif(
1520+
not testenv.CAN_MEASURE_BRANCHES, reason="Can't measure branches with this core"
1521+
)
15191522
def test_subprocess_gets_nonfile_config(self) -> None:
15201523
# https://github.com/nedbat/coveragepy/issues/2021
15211524
self.make_file(

tests/testenv.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import os
99

10+
from coverage import env
11+
1012
REQUESTED_CORE = os.getenv("COVERAGE_CORE", "ctrace")
1113

1214
REQUESTED_TRACER_CLASS = {
@@ -32,3 +34,9 @@
3234

3335
# Are dynamic contexts supported during these tests?
3436
DYN_CONTEXTS = C_TRACER or PY_TRACER
37+
38+
# Can we measure threads?
39+
CAN_MEASURE_THREADS = not SYS_MON
40+
41+
# Can we measure branches?
42+
CAN_MEASURE_BRANCHES = env.PYBEHAVIOR.branch_right_left

tox.ini

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,15 @@ commands =
4242
# Create tests/zipmods.zip
4343
python igor.py zip_mods
4444

45-
# Remove the C extension so that we can test the PyTracer
46-
python igor.py remove_extension
47-
48-
# Test with the PyTracer
49-
python igor.py test_with_core pytrace {posargs}
50-
5145
# Build the C extension and test with the CTracer
5246
python setup.py --quiet build_ext --inplace
5347
python -m pip install {env:COVERAGE_PIP_ARGS} -q -e .
5448
python igor.py test_with_core ctrace {posargs}
5549

50+
# Test with the PyTracer
51+
python igor.py test_with_core pytrace {posargs}
52+
53+
# Test with sys.monitoring
5654
py3{12-15}{,t},anypy: python igor.py test_with_core sysmon {posargs}
5755

5856
[testenv:anypy]

0 commit comments

Comments
 (0)