From 71050957c68a7e1eaece7134be256535173e9b85 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 8 Dec 2022 07:07:16 -0500 Subject: refactor: don't hold data so that Analysis can be pickled --- coverage/html.py | 2 +- coverage/lcovreport.py | 2 +- coverage/results.py | 44 +++++++++++++++----------------------------- tests/coveragetest.py | 8 ++++---- tests/test_plugins.py | 4 ++-- 5 files changed, 23 insertions(+), 37 deletions(-) diff --git a/coverage/html.py b/coverage/html.py index 21b5189e..d2409b38 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -63,7 +63,7 @@ class HtmlDataGeneration: """Produce the data needed for one file's report.""" if self.has_arcs: missing_branch_arcs = analysis.missing_branch_arcs() - arcs_executed = analysis.arcs_executed() + arcs_executed = analysis.arcs_executed if self.config.show_contexts: contexts_by_lineno = analysis.data.contexts_by_lineno(analysis.filename) diff --git a/coverage/lcovreport.py b/coverage/lcovreport.py index 4dc73c29..9791daed 100644 --- a/coverage/lcovreport.py +++ b/coverage/lcovreport.py @@ -96,7 +96,7 @@ class LcovReporter: outfile.write(f"BRDA:{line_number},{block_number},{branch_number},1\n") # Summary of the branch coverage. - if analysis.has_arcs(): + if analysis.has_arcs: branch_stats = analysis.branch_stats() brf = sum(t for t, k in branch_stats.values()) brh = brf - sum(t - k for t, k in branch_stats.values()) diff --git a/coverage/results.py b/coverage/results.py index 2c97a18f..8316b252 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -14,20 +14,23 @@ class Analysis: """The results of analyzing a FileReporter.""" def __init__(self, data, precision, file_reporter, file_mapper): - self.data = data self.file_reporter = file_reporter self.filename = file_mapper(self.file_reporter.filename) self.statements = self.file_reporter.lines() self.excluded = self.file_reporter.excluded_lines() # Identify missing statements. - executed = self.data.lines(self.filename) or [] + executed = data.lines(self.filename) or [] executed = self.file_reporter.translate_lines(executed) self.executed = executed self.missing = self.statements - self.executed - if self.data.has_arcs(): - self._arc_possibilities = sorted(self.file_reporter.arcs()) + self.has_arcs = data.has_arcs() + if self.has_arcs: + self.arc_possibilities = sorted(self.file_reporter.arcs()) + arcs_executed = data.arcs(self.filename) or [] + arcs_executed = self.file_reporter.translate_arcs(arcs_executed) + self.arcs_executed = sorted(arcs_executed) self.exit_counts = self.file_reporter.exit_counts() self.no_branch = self.file_reporter.no_branch_lines() n_branches = self._total_branches() @@ -35,7 +38,8 @@ class Analysis: n_partial_branches = sum(len(v) for k,v in mba.items() if k not in self.missing) n_missing_branches = sum(len(v) for k,v in mba.items()) else: - self._arc_possibilities = [] + self.arc_possibilities = [] + self.arcs_executed = set() self.exit_counts = {} self.no_branch = set() n_branches = n_partial_branches = n_missing_branches = 0 @@ -59,34 +63,18 @@ class Analysis: If `branches` is true, includes the missing branch arcs also. """ - if branches and self.has_arcs(): + if branches and self.has_arcs: arcs = self.missing_branch_arcs().items() else: arcs = None return format_lines(self.statements, self.missing, arcs=arcs) - def has_arcs(self): - """Were arcs measured in this result?""" - return self.data.has_arcs() - - @contract(returns='list(tuple(int, int))') - def arc_possibilities(self): - """Returns a sorted list of the arcs in the code.""" - return self._arc_possibilities - - @contract(returns='list(tuple(int, int))') - def arcs_executed(self): - """Returns a sorted list of the arcs actually executed in the code.""" - executed = self.data.arcs(self.filename) or [] - executed = self.file_reporter.translate_arcs(executed) - return sorted(executed) - @contract(returns='list(tuple(int, int))') def arcs_missing(self): """Returns a sorted list of the un-executed arcs in the code.""" - possible = self.arc_possibilities() - executed = self.arcs_executed() + possible = self.arc_possibilities + executed = self.arcs_executed missing = ( p for p in possible if p not in executed @@ -98,16 +86,14 @@ class Analysis: @contract(returns='list(tuple(int, int))') def arcs_unpredicted(self): """Returns a sorted list of the executed arcs missing from the code.""" - possible = self.arc_possibilities() - executed = self.arcs_executed() # Exclude arcs here which connect a line to itself. They can occur # in executed data in some cases. This is where they can cause # trouble, and here is where it's the least burden to remove them. # Also, generators can somehow cause arcs from "enter" to "exit", so # make sure we have at least one positive value. unpredicted = ( - e for e in executed - if e not in possible + e for e in self.arcs_executed + if e not in self.arc_possibilities and e[0] != e[1] and (e[0] > 0 or e[1] > 0) ) @@ -143,7 +129,7 @@ class Analysis: Returns {l1:[l2a,l2b,...], ...} """ - executed = self.arcs_executed() + executed = self.arcs_executed branch_lines = set(self._branch_lines()) eba = collections.defaultdict(list) for l1, l2 in executed: diff --git a/tests/coveragetest.py b/tests/coveragetest.py index 56e78853..cc5f26f0 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -199,12 +199,12 @@ class CoverageTest( if arcs is not None: # print("Possible arcs:") # print(" expected:", arcs) - # print(" actual:", analysis.arc_possibilities()) + # print(" actual:", analysis.arc_possibilities) # print("Executed:") - # print(" actual:", sorted(set(analysis.arcs_executed()))) + # print(" actual:", sorted(set(analysis.arcs_executed))) # TODO: this would be nicer with pytest-check, once we can run that. msg = ( - self._check_arcs(arcs, analysis.arc_possibilities(), "Possible") + + self._check_arcs(arcs, analysis.arc_possibilities, "Possible") + self._check_arcs(arcs_missing, analysis.arcs_missing(), "Missing") + self._check_arcs(arcs_unpredicted, analysis.arcs_unpredicted(), "Unpredicted") ) @@ -465,7 +465,7 @@ class CoverageTest( # ugh, unexposed methods?? filename = self.last_module_name + ".py" fr = cov._get_file_reporter(filename) - arcs_executed = cov._analyze(filename).arcs_executed() + arcs_executed = cov._analyze(filename).arcs_executed return fr.missing_arc_description(start, end, arcs_executed) diff --git a/tests/test_plugins.py b/tests/test_plugins.py index cd446441..a01904b2 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -395,8 +395,8 @@ class GoodFileTracerTest(FileTracerTest): analysis = cov._analyze("foo_7.html") assert analysis.statements == {1, 2, 3, 4, 5, 6, 7} # Plugins don't do branch coverage yet. - assert analysis.has_arcs() is True - assert analysis.arc_possibilities() == [] + assert analysis.has_arcs is True + assert analysis.arc_possibilities == [] assert analysis.missing == {1, 2, 3, 6, 7} -- cgit v1.2.1