summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt4
-rw-r--r--coverage/parser.py20
-rw-r--r--test/test_arcs.py4
-rw-r--r--test/test_parser.py17
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