summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2016-01-10 15:33:01 -0500
committerNed Batchelder <ned@nedbatchelder.com>2016-01-10 15:33:01 -0500
commit4772c5b15d3586e21cbb3866183ba5fd07a01b3d (patch)
tree6fd36ab513a2ffac9fb4e1c1f8dfb154e6d9d2db
parent259985f289987ecdddd02f76736669e13ec1268a (diff)
downloadpython-coveragepy-git-4772c5b15d3586e21cbb3866183ba5fd07a01b3d.tar.gz
Class docstrings are executable.
-rw-r--r--coverage/parser.py20
-rw-r--r--tests/test_coverage.py4
-rw-r--r--tests/test_parser.py6
3 files changed, 18 insertions, 12 deletions
diff --git a/coverage/parser.py b/coverage/parser.py
index 501b76c4..307b83e6 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -125,6 +125,7 @@ class PythonParser(object):
excluding = False
excluding_decorators = False
prev_toktype = token.INDENT
+ last_name = None
first_line = None
empty = True
first_on_line = True
@@ -146,6 +147,7 @@ class PythonParser(object):
# we need to exclude them. The simplest way is to note the
# lines with the 'class' keyword.
self.raw_classdefs.add(slineno)
+ last_name = ttext
elif toktype == token.OP:
if ttext == ':':
should_exclude = (elineno in self.raw_excluded) or excluding_decorators
@@ -168,7 +170,8 @@ class PythonParser(object):
# (a trick from trace.py in the stdlib.) This works for
# 99.9999% of cases. For the rest (!) see:
# http://stackoverflow.com/questions/1769332/x/1769794#1769794
- self.raw_docstrings.update(range(slineno, elineno+1))
+ if last_name == 'def':
+ self.raw_docstrings.update(range(slineno, elineno+1))
elif toktype == token.NEWLINE:
if first_line is not None and elineno != first_line:
# We're at the end of a line, and we've ended on a
@@ -334,6 +337,7 @@ 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)
ast_dump(self.root_node)
self.arcs = None
@@ -508,13 +512,13 @@ class AstArcAnalyzer(object):
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`.
- body_start = self.line_for_node(node.body[0])
- for lineno in range(last+1, body_start):
- if lineno in self.statements:
- self.arcs.add((last, lineno))
- last = lineno
+ # The definition line may have been missed, but we should have it in
+ # `self.statements`.
+ body_start = self.line_for_node(node.body[0])
+ for lineno in range(last+1, body_start):
+ if lineno in self.statements:
+ self.arcs.add((last, lineno))
+ last = lineno
# the body is handled in add_arcs_for_code_objects.
return set([last])
diff --git a/tests/test_coverage.py b/tests/test_coverage.py
index 227360e3..1173e1e6 100644
--- a/tests/test_coverage.py
+++ b/tests/test_coverage.py
@@ -1140,7 +1140,9 @@ class CompoundStatementTest(CoverageTest):
x = theClass().foo()
assert x == 1
""",
- [2,6,8,10,11,13,14], "")
+ [2, 3, 6, 8, 10, 11, 13, 14], "",
+ arcz=".2 2D DE E-2 23 36 6A A-2 .8 8-6 .B B-A",
+ )
class ExcludeTest(CoverageTest):
diff --git a/tests/test_parser.py b/tests/test_parser.py
index c32fdc4d..fe907117 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -145,8 +145,8 @@ class PythonParserTest(CoverageTest):
def func(x, y=5):
return 6
- class Foo: # the only statement...
- '''9'''
+ class Foo: # only this..
+ '''9''' # ..and this are statements.
@foo # nocover
def __init__(self):
'''12'''
@@ -169,7 +169,7 @@ class PythonParserTest(CoverageTest):
parser.raw_statements,
set([3, 4, 5, 6, 8, 9, 10, 13, 15, 16, 17, 20, 22, 23, 25, 26])
)
- self.assertEqual(parser.statements, set([8]))
+ self.assertEqual(parser.statements, set([8, 9]))
def test_class_decorator_pragmas(self):
parser = self.parse_source("""\