summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/control.py25
-rw-r--r--coverage/parser.py17
-rw-r--r--test/coveragetest.py12
3 files changed, 37 insertions, 17 deletions
diff --git a/coverage/control.py b/coverage/control.py
index ef704261..ce79cd30 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -4,7 +4,7 @@ import os, socket
from coverage.annotate import AnnotateReporter
from coverage.backward import string_class
-from coverage.codeunit import code_unit_factory
+from coverage.codeunit import code_unit_factory, CodeUnit
from coverage.collector import Collector
from coverage.data import CoverageData
from coverage.files import FileLocator
@@ -241,17 +241,19 @@ class coverage:
coverage data.
"""
- code_unit = code_unit_factory(morf, self.file_locator)[0]
- analysis = self._analyze(code_unit)
- return code_unit.filename, analysis.statements, analysis.excluded, analysis.missing, analysis.missing_formatted()
+ analysis = self._analyze(morf)
+ return analysis.filename, analysis.statements, analysis.excluded, analysis.missing, analysis.missing_formatted()
- def _analyze(self, code_unit):
- """Analyze a single code unit.
+ def _analyze(self, it):
+ """Analyze a single morf or code unit.
Returns an `Analysis` object.
"""
- return Analysis(self, code_unit)
+ if not isinstance(it, CodeUnit):
+ it = code_unit_factory(it, self.file_locator)[0]
+
+ return Analysis(self, it)
def report(self, morfs=None, show_missing=True, ignore_errors=False,
file=None, omit_prefixes=None): # pylint: disable-msg=W0622
@@ -343,10 +345,10 @@ class Analysis:
"No source for code '%s'." % code_unit.filename
)
- parser = CodeParser(
+ self.parser = CodeParser(
text=source, filename=filename, exclude=cov.exclude_re
)
- self.statements, self.excluded, line_map = parser.parse_source()
+ self.statements, self.excluded, line_map = self.parser.parse_source()
# Identify missing statements.
self.missing = []
@@ -363,5 +365,10 @@ class Analysis:
if line not in execed:
self.missing.append(line)
+ self.filename = self.code_unit.filename
+
def missing_formatted(self):
return format_lines(self.statements, self.missing)
+
+ def arc_info(self):
+ return self.parser.arc_info()
diff --git a/coverage/parser.py b/coverage/parser.py
index 4087d2f0..ba281024 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -45,6 +45,16 @@ class CodeParser:
# The line numbers that start statements.
self.statement_starts = set()
+ # Lazily-created ByteParser
+ self._byte_parser = None
+
+ def _get_byte_parser(self):
+ """Create a ByteParser on demand."""
+ if not self._byte_parser:
+ self._byte_parser = ByteParser(text=self.text, filename=self.filename)
+ return self._byte_parser
+ byte_parser = property(_get_byte_parser)
+
def _raw_parse(self):
"""Parse the source to find the interesting facts about its lines.
@@ -114,8 +124,7 @@ class CodeParser:
prev_toktype = toktype
# Find the starts of the executable statements.
- byte_parser = ByteParser(text=self.text, filename=self.filename)
- self.statement_starts.update(byte_parser._find_statements())
+ self.statement_starts.update(self.byte_parser._find_statements())
def _map_to_first_line(self, lines, ignore=None):
"""Map the line numbers in `lines` to the correct first line of the
@@ -158,6 +167,10 @@ class CodeParser:
return lines, excluded_lines, self.multiline
+ def arc_info(self):
+ """Get information about the arcs available in the code."""
+ return self.byte_parser._all_arcs()
+
class ByteParser:
diff --git a/test/coveragetest.py b/test/coveragetest.py
index 638c10d6..566819f2 100644
--- a/test/coveragetest.py
+++ b/test/coveragetest.py
@@ -134,26 +134,26 @@ class CoverageTest(unittest.TestCase):
del sys.modules[modname]
# Get the analysis results, and check that they are right.
- _, clines, _, cmissing = cov.analysis(mod)
+ analysis = cov._analyze(mod)
if lines is not None:
if type(lines[0]) == type(1):
- self.assertEqual(clines, lines)
+ self.assertEqual(analysis.statements, lines)
else:
for line_list in lines:
- if clines == line_list:
+ if analysis.statements == line_list:
break
else:
self.fail("None of the lines choices matched %r" % clines)
if missing is not None:
if type(missing) == type(""):
- self.assertEqual(cmissing, missing)
+ self.assertEqual(analysis.missing_formatted(), missing)
else:
for missing_list in missing:
- if cmissing == missing_list:
+ if analysis.missing == missing_list:
break
else:
self.fail(
- "None of the missing choices matched %r" % cmissing
+ "None of the missing choices matched %r" % analysis.missing_formatted()
)
if report: