Issue #128 resolved

branch coverage of with statement in 2.7

Christian Heimes
created an issue

With Python 2.7, branch detection doesn't get a with statement right with an inner return right. Coverage show the line "with open("test", "w") as f" as a branch, that never reaches "exit". Under Python 2.6 the with statement is shown as fully covered.

{{{

!python

def example(): with open("test", "w") as f: # exit f.write("") return 1

example() }}}

Tested with coverage 3.4 and 3.5a1.

Comments (5)

  1. Christian Heimes reporter

    The problem could be caused by a change in Python 2.7's context protocol. Since 2.7 the enter and exit methods are looked up on the type rather than on the object. The lookup is done in the new opcode SETUP_WITH.

    Python 2.7 dis

    >>> dis.dis(cov.example)
      2           0 LOAD_GLOBAL              0 (open)
                  3 LOAD_CONST               1 ('test')
                  6 LOAD_CONST               2 ('w')
                  9 CALL_FUNCTION            2
                 12 SETUP_WITH              24 (to 39)
                 15 STORE_FAST               0 (f)
    
      3          18 LOAD_FAST                0 (f)
                 21 LOAD_ATTR                1 (write)
                 24 LOAD_CONST               3 ('')
                 27 CALL_FUNCTION            1
                 30 POP_TOP             
    
      4          31 LOAD_CONST               4 (1)
                 34 RETURN_VALUE        
                 35 POP_BLOCK           
                 36 LOAD_CONST               0 (None)
            >>   39 WITH_CLEANUP        
                 40 END_FINALLY         
                 41 LOAD_CONST               0 (None)
                 44 RETURN_VALUE        
    
    

    Python 2.6 dis

    >>> dis.dis(cov.example)
      2           0 LOAD_GLOBAL              0 (open)
                  3 LOAD_CONST               1 ('test')
                  6 LOAD_CONST               2 ('w')
                  9 CALL_FUNCTION            2
                 12 DUP_TOP             
                 13 LOAD_ATTR                1 (__exit__)
                 16 ROT_TWO             
                 17 LOAD_ATTR                2 (__enter__)
                 20 CALL_FUNCTION            0
                 23 STORE_FAST               0 (_[1])
                 26 SETUP_FINALLY           30 (to 59)
                 29 LOAD_FAST                0 (_[1])
                 32 DELETE_FAST              0 (_[1])
                 35 STORE_FAST               1 (f)
    
      3          38 LOAD_FAST                1 (f)
                 41 LOAD_ATTR                3 (write)
                 44 LOAD_CONST               3 ('')
                 47 CALL_FUNCTION            1
                 50 POP_TOP             
    
      4          51 LOAD_CONST               4 (1)
                 54 RETURN_VALUE        
                 55 POP_BLOCK           
                 56 LOAD_CONST               0 (None)
            >>   59 WITH_CLEANUP        
                 60 END_FINALLY         
                 61 LOAD_CONST               0 (None)
                 64 RETURN_VALUE        
    
    
  2. Ned Batchelder repo owner

    Gre7g Luterman: This issue is marked as resolved, can you provide a sample that demonstrates it still happening? Even if you can just point to an open source project with runnable tests that show it happening?

    Notice that the original problem report mentioned a return statement inside a with statement, which is not how your code is structured.

  3. Log in to comment