Skip to content
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

Generator expression is marked as not executed when it clearly is #475

Closed
nedbat opened this issue Feb 10, 2016 · 5 comments
Closed

Generator expression is marked as not executed when it clearly is #475

nedbat opened this issue Feb 10, 2016 · 5 comments
Labels
branch bug Something isn't working

Comments

@nedbat
Copy link
Owner

nedbat commented Feb 10, 2016

In this code with branch coverage, "Line of interest" is marked as partial (3->-3)

#!python
def f(a, b):
    c = (i for i in a)
    d = (j for j in b)  # Line of interest
    return dict(zip(c, d))

print(f(['a', 'b'], [1, 2]))

Happens with 4.0.3 and 4.1b2+


@nedbat
Copy link
Owner Author

nedbat commented Feb 11, 2016

This is from http://stackoverflow.com/questions/35317757/python-unittest-branch-coverage-seems-to-miss-executed-generator-in-zip

There, the problem was correctly identified: zip never exhausts the second iterator, because it stops as soon as the first iterator is done. So the second generator never got a chance to finish, so 3->-3 is missing.

I would like to do a better job here, especially because work is underway to make 3->-3 be expressed as, "The generator expression on line 3 never ran," which is not true.

@nedbat
Copy link
Owner Author

nedbat commented Mar 27, 2016

Fixed in 7a3950c9c967 (bb). Now a line might be marked as "The generator on line 3 never ran" or "The generator on line 3 never finished."

@nedbat nedbat closed this as completed Mar 27, 2016
@nedbat nedbat added major bug Something isn't working branch labels Jun 23, 2018
@ipmcc
Copy link

ipmcc commented Sep 23, 2020

I recently ran into this, and had some additional questions:

How can we denote a case where not finishing the iterator is the intended outcome? For instance, Coverage.py flags this:

card = next(iter(x for x in hand if x.id == card_id), None)

Then, if not exhausting an iterator is a "failure" of coverage, why is there no complaint about this substitute? Coverage.py does not flag this:

card = next(iter(filter(lambda x: x.id == card_id, hand)), None)

The Python docs say explicitly that filter "Construct[s] an iterator", and next(iter(...)) is going to leave that iterator just as unfinished as it leaves an iterator comprehension expression, so if such a thing is an "un-covered branch", I would expect it to complain equally about both. Is there a reason it doesn't?

In terms of getting around it, # pragma: no branch works, but I'm curious: Do you have a recommendation for this? I suppose I could configure partial_branches to add something like # pragma unfinished iter but I figured I'd ask your opinion. This feels like something that would happen 'all the time', but maybe it's just my Python coding style. :)

@nedbat
Copy link
Owner Author

nedbat commented Jan 2, 2022

@ipmcc The filter isn't getting flagged because the loop is hidden inside the filter implementation. This is the same issue as s.replace("foo", "bar") not knowing whether the implicit if "foo" in s: branch was taken inside replace().

@niccolomineo
Copy link

This just happened to me using any() with a generator instead of a list (which I cannot use, as pre-commit complains about it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
branch bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants