From 0d6449874cd4d3003ce908d66fa654b64bfea0c0 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 12 Jul 2022 08:05:49 -0400 Subject: [PATCH] fix: 3.11.0b4 has 0-numbered lines. Fixes #1419 CPython added these lines in https://github.com/python/cpython/commit/1bfe83a114da3939c00746fc44dc5da7f56f525f --- CHANGES.rst | 7 +++++++ coverage/env.py | 3 +++ coverage/parser.py | 2 +- tests/test_arcs.py | 2 ++ tests/test_lcov.py | 36 +++++++++++++++++++++++++----------- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index a167b30eb..22f4935c6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -20,11 +20,18 @@ development at the same time, such as 4.5.x and 5.0. Unreleased ---------- +- Updated for a small change in Python 3.11.0 beta 4: modules now start with a + line with line number 0, which is ignored. This line cannnot be executed, so + coverage totals were thrown off. This line is now ignored by coverage.py, + but this also means that truly empty modules (like ``__init__.py``) have no + lines in them, rather than one phantom line. Fixes `issue 1419`_. + - Internal debugging data added to sys.modules is now an actual module, to avoid confusing code that examines everything in sys.modules. Thanks, Yilei Yang (`pull 1399`_). .. _pull 1399: https://github.com/nedbat/coveragepy/pull/1399 +.. _issue 1419: https://github.com/nedbat/coveragepy/issues/1419 .. _changes_6-4-1: diff --git a/coverage/env.py b/coverage/env.py index 444cb8923..2e21b9a7d 100644 --- a/coverage/env.py +++ b/coverage/env.py @@ -110,6 +110,9 @@ class PYBEHAVIOR: # Some words are keywords in some places, identifiers in other places. soft_keywords = (PYVERSION >= (3, 10)) + # Modules start with a line numbered zero. This means empty modules have + # only a 0-number line, which is ignored, giving a truly empty module. + empty_is_empty = (PYVERSION >= (3, 11, 0, 'beta', 4)) # Coverage.py specifics. diff --git a/coverage/parser.py b/coverage/parser.py index dce4f937b..7ef67d2cc 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -377,7 +377,7 @@ def _line_numbers(self): """ if hasattr(self.code, "co_lines"): for _, _, line in self.code.co_lines(): - if line is not None: + if line: yield line else: # Adapted from dis.py in the standard library. diff --git a/tests/test_arcs.py b/tests/test_arcs.py index d0e840af4..d907e8c7b 100644 --- a/tests/test_arcs.py +++ b/tests/test_arcs.py @@ -158,6 +158,8 @@ def test_what_is_the_sound_of_no_lines_clapping(self): if env.JYTHON: # Jython reports no lines for an empty file. arcz_missing=".1 1." # pragma: only jython + elif env.PYBEHAVIOR.empty_is_empty: + arcz_missing=".1 1." else: # Other Pythons report one line. arcz_missing="" diff --git a/tests/test_lcov.py b/tests/test_lcov.py index f31d8c178..09bb99aad 100644 --- a/tests/test_lcov.py +++ b/tests/test_lcov.py @@ -8,6 +8,7 @@ from tests.coveragetest import CoverageTest import coverage +from coverage import env class LcovTest(CoverageTest): @@ -252,7 +253,8 @@ def test_empty_init_files(self): line. It will also note the lack of branches, and the checksum for the line. - Although there are no lines found, it will note one line as hit. + Although there are no lines found, it will note one line as hit in + old Pythons, and no lines hit in newer Pythons. """ self.make_file("__init__.py", "") @@ -261,15 +263,27 @@ def test_empty_init_files(self): self.start_import_stop(cov, "__init__") cov.lcov_report() self.assert_exists("coverage.lcov") - expected_result = textwrap.dedent("""\ - TN: - SF:__init__.py - DA:1,1,1B2M2Y8AsgTpgAmY7PhCfg - LF:0 - LH:1 - BRF:0 - BRH:0 - end_of_record - """) + # Newer Pythons have truly empty empty files. + if env.PYBEHAVIOR.empty_is_empty: + expected_result = textwrap.dedent("""\ + TN: + SF:__init__.py + LF:0 + LH:0 + BRF:0 + BRH:0 + end_of_record + """) + else: + expected_result = textwrap.dedent("""\ + TN: + SF:__init__.py + DA:1,1,1B2M2Y8AsgTpgAmY7PhCfg + LF:0 + LH:1 + BRF:0 + BRH:0 + end_of_record + """) actual_result = self.get_lcov_report_content() assert actual_result == expected_result