nedbat / coveragepy

The code coverage tool for Python
https://coverage.readthedocs.io
Apache License 2.0
3.03k stars 435 forks source link

Regression on branch coverage in 7.6.2 #1876

Closed ziima closed 1 month ago

ziima commented 1 month ago

Describe the bug We discovered a regression in branch coverage of nested context processors in 7.6.2.

To Reproduce How can we reproduce the problem? Please be specific. Don't link to a failing CI job. Answer the questions below:

  1. What version of Python are you using?

Affected are 3.10 and 3.11

  1. What version of coverage.py shows the problem? The output of coverage debug sys is helpful.

7.6.2

``` -- sys ------------------------------------------------------- coverage_version: 7.6.2 coverage_module: /tmp/cover_venv/lib/python3.11/site-packages/coverage/__init__.py core: -none- CTracer: available plugins.file_tracers: -none- plugins.configurers: -none- plugins.context_switchers: -none- configs_attempted: /tmp/cover_test/.coveragerc /tmp/cover_test/setup.cfg /tmp/cover_test/tox.ini /tmp/cover_test/pyproject.toml configs_read: -none- config_file: None config_contents: -none- data_file: -none- python: 3.11.9 (main, Apr 10 2024, 13:16:36) [GCC 13.2.0] platform: Linux-6.10.6-amd64-x86_64-with-glibc2.40 implementation: CPython gil_enabled: True executable: /tmp/cover_venv/bin/python def_encoding: utf-8 fs_encoding: utf-8 pid: 1693632 cwd: /tmp/cover_test path: /tmp/cover_venv/bin /usr/lib/python311.zip /usr/lib/python3.11 /usr/lib/python3.11/lib-dynload /tmp/cover_venv/lib/python3.11/site-packages environment: HOME = /home/vzima command_line: /tmp/cover_venv/bin/coverage debug sys sqlite3_sqlite_version: 3.46.0 sqlite3_temp_store: 0 sqlite3_compile_options: ALLOW_ROWID_IN_VIEW, ATOMIC_INTRINSICS=1, COMPILER=gcc-13.2.0, 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_COLUMN_METADATA, ENABLE_DBSTAT_VTAB, ENABLE_FTS3, ENABLE_FTS3_PARENTHESIS, ENABLE_FTS3_TOKENIZER, ENABLE_FTS4, ENABLE_FTS5, ENABLE_LOAD_EXTENSION, ENABLE_MATH_FUNCTIONS, ENABLE_PREUPDATE_HOOK, ENABLE_RTREE, ENABLE_SESSION, ENABLE_STMTVTAB, ENABLE_UNLOCK_NOTIFY, ENABLE_UPDATE_DELETE_LIMIT, HAVE_ISNAN, LIKE_DOESNT_MATCH_BLOBS, MALLOC_SOFT_LIMIT=1024, MAX_ATTACHED=10, MAX_COLUMN=2000, MAX_COMPOUND_SELECT=500, MAX_DEFAULT_PAGE_SIZE=32768, MAX_EXPR_DEPTH=1000, MAX_FUNCTION_ARG=127, MAX_LENGTH=1000000000, MAX_LIKE_PATTERN_LENGTH=50000, MAX_MMAP_SIZE=0x7fff0000, MAX_PAGE_COUNT=0xfffffffe, MAX_PAGE_SIZE=65536, MAX_SCHEMA_RETRY=25, MAX_SQL_LENGTH=1000000000, MAX_TRIGGER_DEPTH=1000, MAX_VARIABLE_NUMBER=250000, MAX_VDBE_OP=250000000, MAX_WORKER_THREADS=8, MUTEX_PTHREADS, SECURE_DELETE, SOUNDEX, SYSTEM_MALLOC, TEMP_STORE=1, THREADSAFE=1, USE_URI ```
  1. What versions of what packages do you have installed? The output of pip freeze is helpful.
coverage==7.6.2
  1. What code shows the problem? Give us a specific commit of a specific repo that we can check out. If you've already worked around the problem, please provide a commit before that fix.
# /tmp/cover_test/test_pokus.py
from unittest import TestCase
from contextlib import suppress

class CoverageTest(TestCase):

    def test_coverage(self):
        with suppress(ValueError):
            # Missing branch here:
            with suppress(ValueError):
                pass
        expected = (
            tuple(b"<content_1>"),
        )
  1. What commands should we run to reproduce the problem? Be specific. Include everything, even git clone, pip install, and so on. Explain like we're five!
# Create venv
virtualenv --python 3.11 /tmp/cover_venv
/tmp/cover_venv/bin/pip install 'coverage==7.6.2'
cd /tmp/cover_test/
# Run the test
/tmp/cover_venv/bin/coverage erase && /tmp/cover_venv/bin/coverage run --branch -m unittest discover --start-directory /tmp/cover_test/ && /tmp/cover_venv/bin/coverage report --fail-under 100 --show-missing

Actual behavior

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
Name            Stmts   Miss Branch BrPart  Cover   Missing
-----------------------------------------------------------
test_pokus.py       8      0      2      1    90%   11->13
-----------------------------------------------------------
TOTAL               8      0      2      1    90%
Coverage failure: total of 90 is less than fail-under=100

Expected behavior 100% coverage

Additional context Report is fine in:

The branch coverage is highly dependent on the exact code. The missing branch also disappears if the expected is reformatted to a single line.

alex commented 1 month ago

We're seeing the same thing with this code: https://github.com/pyca/cryptography/blob/main/tests/x509/test_name.py#L17-L27

https://github.com/pyca/cryptography/actions/runs/11273274929/job/31350177576 shows the coverage output (26->18 is uncovered)

gpauloski commented 1 month ago

Experiencing this well. I additionally noticed that the branch coverage is only missing on the last of the nested context managers. Extending @ziima's example:

from unittest import TestCase
from contextlib import suppress

class CoverageTest(TestCase):

    def test_coverage(self):
        with suppress(ValueError):
            # Covered correctly
            with suppress(ValueError):
                pass
            # Covered correctly
            with suppress(ValueError):
                pass
            # Missing branch here:
            with suppress(ValueError):
                pass
        expected = (
            tuple(b"<content_1>"),
        )

I also encountered the issue when the context manager is the last line in the test function, even though removing the expected = ... statement from the above example results in 100% coverage. An example is here.

nedbat commented 1 month ago

Thanks for the clear test cases. This is fixed in commit 378c321ba035400b6091505446844e552d8808d5.

alex commented 1 month ago

Thanks Ned!

nedbat commented 1 month ago

This is now released as part of coverage 7.6.3.