Skip to content

Confusing behaviour with any(…) and a generator #310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
alexwlchan opened this issue Jul 24, 2019 · 8 comments
Closed

Confusing behaviour with any(…) and a generator #310

alexwlchan opened this issue Jul 24, 2019 · 8 comments

Comments

@alexwlchan
Copy link

Consider the following example test:

# repro.py

basket = ["apple", "banana", "cherry"]

def test_basket_contains_b():
    assert any("b" in fruit for fruit in basket)
# .coveragerc
[run]
branch = True

[report]
show_missing = True

If I run this test under pytest-cov, and print a report, it tells me that 8->exit isn’t covered:

$ pytest --cov=repro repro.py ; coverage report
[…]
Name       Stmts   Miss Branch BrPart  Cover   Missing
------------------------------------------------------
repro.py       3      0      2      1    80%   8->exit

If I wrap the generator comprehension in a list, coverage is happy:

    assert any(["b" in fruit for fruit in basket])

If I run the body of that function under plain coverage, it doesn't complain, so it looks like this is something to do with the interactions with py.test?

$ cat repro2.py
basket = ["apple", "banana", "cherry"]

assert any(["b" in fruit for fruit in basket])

$ coverage run repro2.py

$ coverage report
Name       Stmts   Miss Branch BrPart  Cover   Missing
------------------------------------------------------
repro2.py      2      0      2      0   100%

I'm not sure if this is a bug per se, and it's not blocking my work – I can wrap my any(…) calls with a list – but it was confusing, and I thought it worth flagging the discrepancy between vanilla coverage and pytest-cov.

Setup

Python 3.7.2 running on macOS. pytest-cov 2.7.1. I'm running in a fresh virtualenv with these dependencies:

$ pip freeze
atomicwrites==1.3.0
attrs==19.1.0
coverage==4.5.3
importlib-metadata==0.18
more-itertools==7.2.0
packaging==19.0
pluggy==0.12.0
py==1.8.0
pyparsing==2.4.0
pytest==5.0.1
pytest-cov==2.7.1
six==1.12.0
wcwidth==0.1.7
zipp==0.5.2

Duplicates

I tried to look for existing bug reports, but "any" is such a common keyword I couldn't find anything useful.

@blueyed
Copy link
Contributor

blueyed commented Jul 24, 2019

Thanks for the detailed report!
It looks like an issue with pytest rather than pytest-cov, when comparing it directly to coverage.py though (you do not use coverage -m pytest … there to not use pytest-cov).

@alexwlchan
Copy link
Author

alexwlchan commented Jul 24, 2019

For extra bonus funsies: the following code also gets a complaint about a missing branch from 7->exit, even though all I’ve changed is whitespace:

basket = ["apple", "banana", "cherry"]

def test_basket_contains_b():
    assert any([
        "b" in fruit for fruit in basket
    ])

@ionelmc
Copy link
Member

ionelmc commented Jul 25, 2019

Must be the assertion rewriter adding something that looks like a branch. The way I see it you're missing a test for empty basket :)

@alexwlchan
Copy link
Author

@ionelmc My fruit basket is never empty. ;)

@software-dov
Copy link

Ran into this just now on debian 4.19.37, python3.6, running in a fresh virtualenv via nox, with next:

Minimal reproducible example

from collections import namedtuple
Element = namedtuple("Element", ["key", "val"])
elements = [
    Element("squid", "teuthida"),
    Element("clam", "tridacna"),
    Element("whelk", "buccinoidea")
]
squid = next(e.val for e in elements if e.key == "squid")

@blueyed
Copy link
Contributor

blueyed commented Aug 15, 2019

This is not specific to pytest-cov.

Given t_any.py:

from collections import namedtuple


def test():
    Element = namedtuple("Element", ["key", "val"])
    elements = [
        Element("squid", "teuthida"),
        Element("clam", "tridacna"),
        Element("whelk", "buccinoidea")
    ]
    squid = next(e.val for e in elements if e.key == "squid")


if __name__ == "__main__":
    test()

coverage run --rcfile=/dev/null --branch t_any.py; coverage report t_any.py reports:

t_any.py       7      0      4      2    81.82%   11->exit, 14->exit

With pytest --cov=t_any --cov-config=/dev/null --cov-branch --cov-report=term-missing t_any.py:

t_any.py       7      1      4      2    73%   15, 11->exit, 14->15

Line 15 is the last one - the call to the test function when not using pytest.

@blueyed
Copy link
Contributor

blueyed commented Aug 15, 2019

Going through duplicates in coveragepy's issues I've landed at nedbat/coveragepy#515.

But using --assert=plain with pytest still results in 15, 11->exit, 14->15.

So it's really an issue with coverage.py.

(Coverage.py, version 4.5.2 with C extension, This is pytest version 4.3.0, Python 3.7.4 - apparently an old venv I have there for pytest-cov ;))

@blueyed
Copy link
Contributor

blueyed commented Aug 15, 2019

/cc @nedbat

@blueyed blueyed closed this as completed Aug 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants