I don't quite understand what Python's branch coverage stats are trying to tell me. Given code of the form
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]))
which is imported during unit testing, Python's standard branch coverage tells me that the # Line of interest line is only partially covered (n->-n on the CLI output, "n ↛ exit [?]" in the pretty html report).
The returned dict is clearly printed out, and executing with empty lists still yields the uncovered line.
Am I misinterpreting the coverage output? Does this smell like a bug?
Python 3.5.1, Coverage 4.0.3
I've investigated this further, and I don't think it is a bug in coverage. When the first generator (
c) terminates,zip()efficiently doesn't bother collecting any more values from the second generator (d), so branch coverage doesn't trackdas run to completion, even though every element is actually extracted.If you instead write:
as one would expect the second generator is run to completion and coverage is happy, even though the output is identical.
I don't think there's a simple way around this, even if you write the generator expression out as a generator function containing the same for loop, you get a (slightly clearer) error that execution never jumped to function exit.
I think this is just a limitation of coverage and the exit conditions of generators, as it can't know whether a generator is supposed to exit, so it flags the uncovered case.