Skip to content

finally-if produces wrong reasons in branch coverage #867

Open
@nedbat

Description

@nedbat

foo.py:

def doit(o, r):
    try:
        _doit(o, r)
    except:
        pass

def _doit(o, r):
    try:
        if r:
            raise ValueError("hey")
    except ValueError:
        raise Exception("hi")
    finally:
        if o:
            print("close")

    return "boo"

doit(False, True)
doit(True, False)

When run with branch coverage (Python 3.8, if it matters), produces this output:
image
The two yellow lines are both right: those are branches that are not fully exercised, but the explanations in the annotations are wrong.

The annotation on line 14 says:

line 14 didn't jump to line 17, because the condition on line 14 was never false

This isn't true: the condition on line 14 was false at one point. Line 14 can go three places:

  • line 15 (if the condition is true)
  • exit the function (if the condition is false and an exception is being raised)
  • line 17 (if the condition is false and an exception isn't being raised)

What's missing from the coverage is the third possibility, but the annotation doesn't make that clear.

The annotation on line 15 says:

line 15 didn't except from function '_doit', because the raise on line 12 wasn't executed

This isn't true: the raise on line 12 was executed. Line 15 will except from the function only if two conditions are met: the raise on line 12 is executed and the condition on line 14 is true. It's this combination that is missing, but the annotation doesn't make this clear.

Metadata

Metadata

Assignees

No one assigned

    Labels

    branchbugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions