Skip to content

Test regression around .pth files in 7.10.1 #2011

@mgorny

Description

@mgorny

Describe the bug
With 7.10.1, the tests seem to be failing on all Pythons. Bisect points to 2134e57.

======================================================= short test summary info =======================================================
FAILED tests/test_process.py::ProcessStartupTest::test_patch_subprocess@needs_pth - KeyError: 'sub.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execl]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execle]@needs_pth - KeyError: 'other.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execlp]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execlpe]@needs_pth - KeyError: 'other.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execv]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execve]@needs_pth - KeyError: 'other.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execvp]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[execvpe]@needs_pth - KeyError: 'other.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnl]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnle]@needs_pth - KeyError: 'other.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnlp]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnlpe]@needs_pth - KeyError: 'other.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnv]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnve]@needs_pth - KeyError: 'other.py'
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnvp]@needs_pth - assert 'In main\nError processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:\n\n  Traceback (...
FAILED tests/test_process.py::ExecvTest::test_execv_patch[spawnvpe]@needs_pth - KeyError: 'other.py'
17 failed, 1460 passed, 25 skipped in 28.06s

The errors seem to all have roughly the same reason, and xdist doesn't seem relevant, i.e.:

$ pytest -o addopts= tests/test_process.py::ProcessStartupTest::test_patch_subprocess
========================================================= test session starts =========================================================
platform linux -- Python 3.13.5, pytest-8.4.1, pluggy-1.6.0
rootdir: /tmp/coveragepy
configfile: pyproject.toml
plugins: xdist-3.8.0, hypothesis-6.135.29, flaky-3.8.1
collected 1 item                                                                                                                      

tests/test_process.py F                                                                                                         [100%]

============================================================== FAILURES ===============================================================
______________________________________________ ProcessStartupTest.test_patch_subprocess _______________________________________________

self = <tests.test_process.ProcessStartupTest object at 0x7f8f9fdddbd0>

    def test_patch_subprocess(self) -> None:
        self.make_file(".coveragerc", """\
            [run]
            patch = subprocess
            """)
        self.run_command("coverage run main.py")
        self.run_command("coverage combine")
        self.assert_exists(".coverage")
        data = coverage.CoverageData()
        data.read()
        assert line_counts(data)["main.py"] == 3
>       assert line_counts(data)["sub.py"] == 3
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'sub.py'

/tmp/coveragepy/tests/test_process.py:1355: KeyError
-------------------------------------------------------- Captured stdout call ---------------------------------------------------------
Error processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:

  Traceback (most recent call last):
    File "<frozen site>", line 207, in addpackage
    File "<string>", line 1, in <module>
    File "/tmp/coveragepy/coverage/control.py", line 1435, in process_startup
      cov.start()
      ~~~~~~~~~^^
    File "/tmp/coveragepy/coverage/control.py", line 681, in start
      apply_patches(self, self.config)
      ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
    File "/tmp/coveragepy/coverage/patch.py", line 82, in apply_patches
      assert pth_file is not None
             ^^^^^^^^^^^^^^^^^^^^
  AssertionError

Remainder of file ignored

Combined data file .coverage.pomiot.137273.XAxvKiBx

======================================================= short test summary info =======================================================
FAILED tests/test_process.py::ProcessStartupTest::test_patch_subprocess - KeyError: 'sub.py'
========================================================== 1 failed in 0.81s ==========================================================

To Reproduce

tox -e py313

I have reproduced with CPython 3.11.13, 3.13.5, and PyPy3.11 7.3.20.

$ coverage debug sys
-- sys -------------------------------------------------------
               coverage_version: 7.10.2a0.dev1
                coverage_module: /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/coverage/__init__.py
                           core: -none-
                        CTracer: unavailable
           plugins.file_tracers: -none-
            plugins.configurers: -none-
      plugins.context_switchers: -none-
              configs_attempted: /tmp/coveragepy/.coveragerc
                                 /tmp/coveragepy/setup.cfg
                                 /tmp/coveragepy/tox.ini
                                 /tmp/coveragepy/pyproject.toml
                   configs_read: /tmp/coveragepy/tox.ini
                                 /tmp/coveragepy/pyproject.toml
                    config_file: None
                config_contents: -none-
                      data_file: -none-
                         python: 3.13.5 (main, Jun 12 2025, 03:41:01) [GCC 14.3.0]
                       platform: Linux-6.15.8-gentoo-dist-x86_64-AMD_Ryzen_5_3600_6-Core_Processor-with-glibc2.41
                 implementation: CPython
                          build: main
                                 Jun 12 2025 03:41:01
                    gil_enabled: True
                     executable: /tmp/coveragepy/.tox/py313/bin/python
                   def_encoding: utf-8
                    fs_encoding: utf-8
                            pid: 114926
                            cwd: /tmp/coveragepy
                           path: /tmp/coveragepy/.tox/py313/bin
                                 /usr/lib/python313.zip
                                 /usr/lib/python3.13
                                 /usr/lib/python3.13/lib-dynload
                                 /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages
                    environment: HOME = /home/mgorny
                                 LIBXCB_ALLOW_SLOPPY_LOCK = 1
                   command_line: /tmp/coveragepy/.tox/py313/bin/coverage debug sys
         sqlite3_sqlite_version: 3.50.3
             sqlite3_temp_store: 0
        sqlite3_compile_options: ATOMIC_INTRINSICS=1, COMPILER=gcc-15.1.1 20250705, DEFAULT_AUTOVACUUM,
                                 DEFAULT_CACHE_SIZE=-2000, DEFAULT_FILE_FORMAT=4,
                                 DEFAULT_JOURNAL_SIZE_LIMIT=-1, DEFAULT_MMAP_SIZE=0, DEFAULT_PAGE_SIZE=4096,
                                 DEFAULT_PCACHE_INITSZ=20, DEFAULT_RECURSIVE_TRIGGERS,
                                 DEFAULT_SECTOR_SIZE=4096, DEFAULT_SYNCHRONOUS=2,
                                 DEFAULT_WAL_AUTOCHECKPOINT=1000, DEFAULT_WAL_SYNCHRONOUS=2,
                                 DEFAULT_WORKER_THREADS=0, DIRECT_OVERFLOW_READ, ENABLE_API_ARMOR,
                                 ENABLE_BYTECODE_VTAB, ENABLE_COLUMN_METADATA, ENABLE_DBPAGE_VTAB,
                                 ENABLE_DBSTAT_VTAB, ENABLE_EXPLAIN_COMMENTS, ENABLE_FTS3,
                                 ENABLE_FTS3_PARENTHESIS, ENABLE_FTS4, ENABLE_FTS5, ENABLE_GEOPOLY,
                                 ENABLE_HIDDEN_COLUMNS, ENABLE_ICU, ENABLE_MATH_FUNCTIONS, ENABLE_MEMSYS5,
                                 ENABLE_NORMALIZE, ENABLE_OFFSET_SQL_FUNC, ENABLE_PREUPDATE_HOOK,
                                 ENABLE_RBU, ENABLE_RTREE, ENABLE_SESSION, ENABLE_STMTVTAB,
                                 ENABLE_STMT_SCANSTATUS, ENABLE_UNKNOWN_SQL_FUNCTION, ENABLE_UNLOCK_NOTIFY,
                                 ENABLE_UPDATE_DELETE_LIMIT, HAVE_ISNAN, MALLOC_SOFT_LIMIT=1024,
                                 MAX_ATTACHED=10, MAX_COLUMN=2000, MAX_COMPOUND_SELECT=500,
                                 MAX_DEFAULT_PAGE_SIZE=8192, MAX_EXPR_DEPTH=1000, MAX_FUNCTION_ARG=1000,
                                 MAX_LENGTH=1000000000, MAX_LIKE_PATTERN_LENGTH=50000,
                                 MAX_MMAP_SIZE=0x7fff0000, MAX_PAGE_COUNT=0xfffffffe, MAX_PAGE_SIZE=65536,
                                 MAX_SQL_LENGTH=1000000000, MAX_TRIGGER_DEPTH=1000,
                                 MAX_VARIABLE_NUMBER=32766, MAX_VDBE_OP=250000000, MAX_WORKER_THREADS=8,
                                 MUTEX_PTHREADS, SOUNDEX, SYSTEM_MALLOC, TEMP_STORE=1, THREADSAFE=1, USE_URI
$ pip freeze
attrs==25.3.0
colorama==0.4.6
coverage @ file:///tmp/coveragepy/.tox/.tmp/package/10/coverage-7.10.2a0.dev1.tar.gz#sha256=372cf06067ebd2afe864846a07138c74f1d9d0238d386805c43a37da207ce15b
distlib==0.4.0
exceptiongroup==1.3.0
execnet==2.1.1
filelock==3.18.0
flaky==3.8.1
hypothesis==6.136.4
iniconfig==2.1.0
packaging==25.0
platformdirs==4.3.8
pluggy==1.6.0
Pygments==2.19.2
pytest==8.4.1
pytest-xdist==3.8.0
setuptools==80.9.0
sortedcontainers==2.4.0
tomli==2.2.1
typing_extensions==4.14.1
virtualenv==20.32.0

Expected behavior
Passing tests :-).

Additional context
If I add a some debug prints:

diff --git a/coverage/files.py b/coverage/files.py
index af609488..48b9e375 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -222,12 +222,14 @@ def create_pth_file() -> Path | None:
     """Create .pth file for measuring subprocesses."""
     for pth_dir in site.getsitepackages():  # pragma: part covered
         pth_file = Path(pth_dir) / "subcover.pth"
+        print(f"{pth_file=}")
         try:
             pth_file.write_text("import coverage; coverage.process_startup()\n", encoding="utf-8")
         except OSError:  # pragma: cant happen
             continue
         else:
             return pth_file
+    print("it happened")
     return None  # pragma: cant happen

Then the output becomes:

Error processing line 1 of /tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth:

  Traceback (most recent call last):
    File "<frozen site>", line 207, in addpackage
    File "<string>", line 1, in <module>
    File "/tmp/coveragepy/coverage/control.py", line 1435, in process_startup
      cov.start()
      ~~~~~~~~~^^
    File "/tmp/coveragepy/coverage/control.py", line 681, in start
      apply_patches(self, self.config)
      ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
    File "/tmp/coveragepy/coverage/patch.py", line 82, in apply_patches
      assert pth_file is not None
             ^^^^^^^^^^^^^^^^^^^^
  AssertionError

Remainder of file ignored
pth_file=PosixPath('/usr/lib/python3.13/site-packages/subcover.pth')
it happened
pth_file=PosixPath('/tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth')

Combined data file .coverage.pomiot.138514.XzsHbdxx

Prior to the commit in question, the output is instead:

pth_file=PosixPath('/tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth')
pth_file=PosixPath('/tmp/coveragepy/.tox/py313/lib/python3.13/site-packages/subcover.pth')

Combined data file .coverage.pomiot.142231.XWEYKEix
Combined data file .coverage.pomiot.142232.XqBXkAix

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions