diff options
-rw-r--r-- | coverage/control.py | 25 | ||||
-rw-r--r-- | coverage/parser.py | 17 | ||||
-rw-r--r-- | test/coveragetest.py | 12 |
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: |