Issue #146 new

Context managers confuse branch coverage

Ned Batchelder
repo owner created an issue

In this code:

from contextlib import contextmanager

@contextmanager
def dummy():
    yield

for i in range(10):
    with dummy():
        print "hello"  # line 9
    print "bye"
print "done"   # line 11

Line 9 claims to have an untaken branch to line 11.

Comments (12)

  1. Ned Batchelder reporter

    Another report of this from lvh:

    class T(unittest.TestCase):
        def setUp(self):
            # SNIP SNIP
            for fileName in ["index.html", "style.css", "app.js"]:
                with location.child(fileName).open("w") as f:
                    f.write("base {ext}".format(ext=fileName.split(".")[-1])) # NO JUMP TO NEXT LINE
    
            f = frontend.FrontEnd(store=s, build=b, domain="frontend.test")
    
  2. stefano_palazzo

    Here's an example that probably describes the same issue:

    class Context:
    
        def __init__(self, do_raise):
            self.do_raise = do_raise
    
        def __enter__(self):
            if self.do_raise:
                raise FileNotFoundError()
            return self
    
        def __exit__(self, *exc_info):
            pass
    
    
    def load(do_raise):
        try:
            with Context(do_raise) as f:
                print(f)
        except FileNotFoundError:
            pass
    
    
    load(True)
    load(False)
    

    With "print(f)" claiming to have an untaken branch to "except FileNotFoundError:".

  3. Anthony Sottile

    Interestingly the following example seems to only plague 2.6 (not 2.7, 3.3, 3.4, pypy from my testing)

    from __future__ import print_function
    from __future__ import unicode_literals
    
    import contextlib
    
    
    @contextlib.contextmanager
    def noop():
        yield
    
    
    def test_foo():
        with noop():
            with noop():
                print('1')
            print('2')
    
  4. Log in to comment