Nested matches of exclude_lines patterns leads to unmatched lines being excluded · Issue #1779 · nedbat/coveragepy (original) (raw)

Describe the bug

When multiple patterns of exclude_lines overlap (like an abstractmethod inside a Protocol, which you see below), the exclusion for the abstractmethod unexpectedly extends to the next coverable line, leading to an incorrect coverage report.

To Reproduce

.coveragerc:

[report] exclude_lines = @(abc.)?abstractmethod class .?(.?Protocol.*?:

a.py:

import abc from typing import Protocol

class MyProtocol(Protocol): @abc.abstractmethod def my_method(self) -> int: """Discombombulate the frobnicator."""

def function() -> int: x = 1 y = 2 return x + y

tests/test_a.py:

import unittest

import a

class TestA(unittest.TestCase): ...

Screenshot 2024-05-09 at 10 57 56

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?
    3.10
  2. What version of coverage.py shows the problem? The output of coverage debug sys is helpful.
    coverage==7.5.1
  3. What versions of what packages do you have installed? The output of pip freeze is helpful.
    ...
  4. 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.
    ...
  5. 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!

$ python -m pytest tests/test_a.py --cov=a.py $ coverage html $ python -m http.server

Expected behavior
I don't expect the exclusion to extend to the next line.

If you change Protocol to abc.ABC, it works as expected. If you remove @(abc\.)?abstractmethod from exclude_lines or modify it in a way s.t. it does not match the code, it works as expected.