diff options
-rw-r--r-- | CHANGES.txt | 4 | ||||
-rw-r--r-- | coverage/parser.py | 20 | ||||
-rw-r--r-- | test/test_arcs.py | 4 | ||||
-rw-r--r-- | test/test_parser.py | 17 |
4 files changed, 40 insertions, 5 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 8f934252..1ef464e0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -10,9 +10,13 @@ Version 3.2b2 - Classes are no longer incorrectly marked as branches: `issue 32`_.
+- "except" clauses with types are no longer incorrectly marked as branches:
+ `issue 35`_.
+
.. _issue 30: http://bitbucket.org/ned/coveragepy/issue/30
.. _issue 31: http://bitbucket.org/ned/coveragepy/issue/31
.. _issue 32: http://bitbucket.org/ned/coveragepy/issue/32
+.. _issue 35: http://bitbucket.org/ned/coveragepy/issue/35
Version 3.2b1, 10 November 2009
diff --git a/coverage/parser.py b/coverage/parser.py index 1e8b7792..de0e0c7f 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -262,6 +262,8 @@ OPS_NO_JUMP = _opcode_set('SETUP_EXCEPT', 'SETUP_FINALLY') # Individual opcodes we need below. OP_BREAK_LOOP = _opcode('BREAK_LOOP') OP_END_FINALLY = _opcode('END_FINALLY') +OP_COMPARE_OP = _opcode('COMPARE_OP') +COMPARE_EXCEPTION = 10 # just have to get this const from the code. class ByteParser(object): @@ -378,6 +380,10 @@ class ByteParser(object): # Each entry is a tuple: (block type, destination) block_stack = [] + # Some op codes are followed by branches that should be ignored. This + # is a count of how many ignores are left. + ignore_branch = 0 + for bc in ByteCodes(self.code.co_code): # Maybe have to start a new block if bc.offset in bytes_lines_map: @@ -392,8 +398,12 @@ class ByteParser(object): # Look at the opcode if bc.jump_to >= 0 and bc.op not in OPS_NO_JUMP: - # The opcode has a jump, it's an exit for this chunk. - chunk.exits.add(bc.jump_to) + if ignore_branch: + # Someone earlier wanted us to ignore this branch. + ignore_branch -= 1 + else: + # The opcode has a jump, it's an exit for this chunk. + chunk.exits.add(bc.jump_to) if bc.op in OPS_CODE_END: # The opcode can exit the code object. @@ -422,7 +432,11 @@ class ByteParser(object): if block_stack[iblock][0] in OPS_EXCEPT_BLOCKS: chunk.exits.add(block_stack[iblock][1]) break - + if bc.op == OP_COMPARE_OP and bc.arg == COMPARE_EXCEPTION: + # This is an except clause. We want to overlook the next + # branch, so that except's don't count as branches. + ignore_branch += 1 + if chunks: chunks[-1].length = bc.next_offset - chunks[-1].byte for i in range(len(chunks)-1): diff --git a/test/test_arcs.py b/test/test_arcs.py index 00567ac6..dea3700f 100644 --- a/test/test_arcs.py +++ b/test/test_arcs.py @@ -265,8 +265,8 @@ class ExceptionArcTest(CoverageTest): assert try_it(0) == 8 # C assert try_it(1) == 6 # D """, - arcz=".1 12 .3 3. 24 4C CD D. .5 56 67 78 8B 9A 9B AB B.", - arcz_missing="9B", # never got an exception other than ValueError + arcz=".1 12 .3 3. 24 4C CD D. .5 56 67 78 8B 9A AB B.", + arcz_missing="", arcz_unpredicted="79") def test_try_finally(self): diff --git a/test/test_parser.py b/test/test_parser.py index 5a66f873..61572be5 100644 --- a/test/test_parser.py +++ b/test/test_parser.py @@ -34,3 +34,20 @@ class ParserTest(CoverageTest): self.assertEqual(cp.exit_counts(), { 2:1, 3:1, 4:2, 5:1, 7:1, 9:1, 10:1 }) + + def test_try_except(self): + cp = self.parse_source("""\ + try: + a = 2 + except ValueError: + a = 4 + except ZeroDivideError: + a = 6 + except: + a = 8 + b = 9 + """) + self.assertEqual(cp.exit_counts(), { + 1: 1, 2:1, 3:1, 4:1, 5:1, 6:1, 7:1, 8:1, 9:1 + }) +
\ No newline at end of file |