--- a/eric7/DebugClients/Python/coverage/results.py Fri Nov 19 19:28:47 2021 +0100 +++ b/eric7/DebugClients/Python/coverage/results.py Sat Nov 20 16:47:38 2021 +0100 @@ -5,15 +5,15 @@ import collections -from coverage.backward import iitems from coverage.debug import SimpleReprMixin -from coverage.misc import contract, CoverageException, nice_pair +from coverage.exceptions import CoverageException +from coverage.misc import contract, nice_pair -class Analysis(object): +class Analysis: """The results of analyzing a FileReporter.""" - def __init__(self, data, file_reporter, file_mapper): + 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) @@ -32,8 +32,8 @@ self.no_branch = self.file_reporter.no_branch_lines() n_branches = self._total_branches() mba = self.missing_branch_arcs() - n_partial_branches = sum(len(v) for k,v in iitems(mba) if k not in self.missing) - n_missing_branches = sum(len(v) for k,v in iitems(mba)) + 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.exit_counts = {} @@ -41,6 +41,7 @@ n_branches = n_partial_branches = n_missing_branches = 0 self.numbers = Numbers( + precision=precision, n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), @@ -59,7 +60,7 @@ """ if branches and self.has_arcs(): - arcs = iitems(self.missing_branch_arcs()) + arcs = self.missing_branch_arcs().items() else: arcs = None @@ -83,13 +84,14 @@ @contract(returns='list(tuple(int, int))') def arcs_missing(self): - """Returns a sorted list of the arcs in the code not executed.""" + """Returns a sorted list of the unexecuted arcs in the code.""" possible = self.arc_possibilities() executed = self.arcs_executed() missing = ( p for p in possible if p not in executed and p[0] not in self.no_branch + and p[1] not in self.excluded ) return sorted(missing) @@ -113,7 +115,7 @@ def _branch_lines(self): """Returns a list of line numbers that have more than one exit.""" - return [l1 for l1,count in iitems(self.exit_counts) if count > 1] + return [l1 for l1,count in self.exit_counts.items() if count > 1] def _total_branches(self): """How many total branches are there?""" @@ -158,15 +160,16 @@ up statistics across files. """ - # A global to determine the precision on coverage percentages, the number - # of decimal places. - _precision = 0 - _near0 = 1.0 # These will change when _precision is changed. - _near100 = 99.0 - def __init__(self, n_files=0, n_statements=0, n_excluded=0, n_missing=0, - n_branches=0, n_partial_branches=0, n_missing_branches=0 - ): + def __init__(self, + precision=0, + n_files=0, n_statements=0, n_excluded=0, n_missing=0, + n_branches=0, n_partial_branches=0, n_missing_branches=0 + ): + assert 0 <= precision < 10 + self._precision = precision + self._near0 = 1.0 / 10**precision + self._near100 = 100.0 - self._near0 self.n_files = n_files self.n_statements = n_statements self.n_excluded = n_excluded @@ -178,18 +181,11 @@ def init_args(self): """Return a list for __init__(*args) to recreate this object.""" return [ + self._precision, self.n_files, self.n_statements, self.n_excluded, self.n_missing, self.n_branches, self.n_partial_branches, self.n_missing_branches, ] - @classmethod - def set_precision(cls, precision): - """Set the number of decimal places used to report percentages.""" - assert 0 <= precision < 10 - cls._precision = precision - cls._near0 = 1.0 / 10**precision - cls._near100 = 100.0 - cls._near0 - @property def n_executed(self): """Returns the number of executed statements.""" @@ -219,7 +215,16 @@ result in either "0" or "100". """ - pc = self.pc_covered + return self.display_covered(self.pc_covered) + + def display_covered(self, pc): + """Return a displayable total percentage, as a string. + + Note that "0" is only returned when the value is truly zero, and "100" + is only returned when the value is truly 100. Rounding can never + result in either "0" or "100". + + """ if 0 < pc < self._near0: pc = self._near0 elif self._near100 < pc < 100: @@ -228,12 +233,11 @@ pc = round(pc, self._precision) return "%.*f" % (self._precision, pc) - @classmethod - def pc_str_width(cls): + def pc_str_width(self): """How many characters wide can pc_covered_str be?""" width = 3 # "100" - if cls._precision > 0: - width += 1 + cls._precision + if self._precision > 0: + width += 1 + self._precision return width @property @@ -244,7 +248,7 @@ return numerator, denominator def __add__(self, other): - nums = Numbers() + nums = Numbers(precision=self._precision) nums.n_files = self.n_files + other.n_files nums.n_statements = self.n_statements + other.n_statements nums.n_excluded = self.n_excluded + other.n_excluded @@ -260,9 +264,8 @@ def __radd__(self, other): # Implementing 0+Numbers allows us to sum() a list of Numbers. - if other == 0: - return self - return NotImplemented # pragma: not covered (we never call it this way) + assert other == 0 # we only ever call it this way. + return self def _line_ranges(statements, lines): @@ -333,7 +336,7 @@ """ # We can never achieve higher than 100% coverage, or less than zero. if not (0 <= fail_under <= 100.0): - msg = "fail_under={} is invalid. Must be between 0 and 100.".format(fail_under) + msg = f"fail_under={fail_under} is invalid. Must be between 0 and 100." raise CoverageException(msg) # Special case for fail_under=100, it must really be 100.