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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions