summaryrefslogtreecommitdiff
path: root/coverage/parser.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2016-01-18 19:24:50 -0500
committerNed Batchelder <ned@nedbatchelder.com>2016-01-18 19:24:50 -0500
commit95c9930f5c936571f32b873c6a9110204a2404ec (patch)
tree1b0e8147b483c03008ec87977ffb3ba8a3e7b342 /coverage/parser.py
parentc67e5b03f367654f3cb9c130a87dbe1df3e618af (diff)
downloadpython-coveragepy-95c9930f5c936571f32b873c6a9110204a2404ec.tar.gz
Fix #466: multi-line statements first in decorated functions
Also, leave in the SetSpy tracer we've used before to find things like this.
Diffstat (limited to 'coverage/parser.py')
-rw-r--r--coverage/parser.py32
1 files changed, 25 insertions, 7 deletions
diff --git a/coverage/parser.py b/coverage/parser.py
index 07cb75d..2d0bceb 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -321,6 +321,19 @@ class TryBlock(object):
self.raise_from = set()
+class SetSpy(object): # pragma: debugging
+ """A set proxy that shows who is adding things to it."""
+ def __init__(self, the_set):
+ self.the_set = the_set
+
+ def add(self, arc):
+ """set.add, but with a stack trace."""
+ from coverage.debug import short_stack
+ print("\nAdding arc: {}".format(arc))
+ print(short_stack(limit=6))
+ self.the_set.add(arc)
+
+
class AstArcAnalyzer(object):
"""Analyze source text with an AST to find executable code paths."""
@@ -333,11 +346,13 @@ class AstArcAnalyzer(object):
if int(os.environ.get("COVERAGE_ASTDUMP", 0)): # pragma: debugging
# Dump the AST so that failing tests have helpful output.
- print(self.statements)
- print(self.multiline)
+ print("Statements: {}".format(self.statements))
+ print("Multiline map: {}".format(self.multiline))
ast_dump(self.root_node)
- self.arcs = set()
+ self.arcs = self.arcs_to_return = set()
+ if int(os.environ.get("COVERAGE_TRACK_ARCS", 0)): # pragma: debugging
+ self.arcs = SetSpy(self.arcs)
self.block_stack = []
def collect_arcs(self):
@@ -352,7 +367,7 @@ class AstArcAnalyzer(object):
if code_object_handler is not None:
code_object_handler(node)
- return self.arcs
+ return self.arcs_to_return
def nearest_blocks(self):
"""Yield the blocks in nearest-to-farthest order."""
@@ -517,10 +532,13 @@ class AstArcAnalyzer(object):
dec_start = self.line_for_node(dec_node)
if dec_start != last:
self.arcs.add((last, dec_start))
- last = dec_start
- # The definition line may have been missed, but we should have it in
- # `self.statements`.
+ last = dec_start
+ # The definition line may have been missed, but we should have it
+ # in `self.statements`. For some constructs, `line_for_node` is
+ # not what we'd think of as the first line in the statement, so map
+ # it to the first one.
body_start = self.line_for_node(node.body[0])
+ body_start = self.multiline.get(body_start, body_start)
for lineno in range(last+1, body_start):
if lineno in self.statements:
self.arcs.add((last, lineno))