Commits

Ned Batchelder committed d3de376

A Numbers class to handle the interrelationships of counts and percentages, including in rolled-up presentations.

Comments (0)

Files changed (3)

coverage/control.py

         exec1 = self.parser.first_lines(self.executed)
         self.missing = sorted(set(self.statements) - set(exec1))
 
+        self.numbers = Numbers()
+        self.numbers.n_files = 1
+        self.numbers.n_statements = len(self.statements)
+        self.numbers.n_excluded = len(self.excluded)
+        self.numbers.n_missing = len(self.missing)
+
     def missing_formatted(self):
         """The missing line numbers, formatted nicely.
         
         """
         return format_lines(self.statements, self.missing)
 
-    def percent_covered(self):
-        """Returns a single percentage value for coverage."""
-        n_stm = len(self.statements)
-        n_mis = len(self.missing)
-        n_run = n_stm - n_mis
-        if n_stm > 0:
-            pc_cov = 100.0 * n_run / n_stm
-        else:
-            pc_cov = 100.0
-        return pc_cov
-
     def has_arcs(self):
         """Were arcs measured in this result?"""
         return self.coverage.data.has_arcs()
                     mba[l1] = []
                 mba[l1].append(l2)
         return mba
+
+
+class Numbers(object):
+    """The numerical results of measuring coverage.
+    
+    This holds the basic statistics from `Analysis`, and is used to roll
+    up statistics across files.
+
+    """
+    def __init__(self):
+        self.n_files = 0
+        self.n_statements = 0
+        self.n_excluded = 0
+        self.n_missing = 0
+
+    def _get_n_run(self):
+        return self.n_statements - self.n_missing
+    n_run = property(_get_n_run)
+    
+    def _get_percent_covered(self):
+        """Returns a single percentage value for coverage."""
+        if self.n_statements > 0:
+            pc_cov = 100.0 * self.n_run / self.n_statements
+        else:
+            pc_cov = 100.0
+        return pc_cov
+    percent_covered = property(_get_percent_covered)
+
+    def __iadd__(self, other):
+        self.n_files += other.n_files
+        self.n_statements += other.n_statements
+        self.n_excluded += other.n_excluded
+        self.n_missing += other.n_missing
+        return self
         n_exc = len(analysis.excluded)
         n_mis = len(analysis.missing)
         n_run = n_stm - n_mis
-        pc_cov = analysis.percent_covered()
+        pc_cov = analysis.numbers.percent_covered
 
         missing_branch_arcs = analysis.missing_branch_arcs()
         n_par = 0   # accumulated below.

coverage/summary.py

     def report(self, morfs, omit_prefixes=None, outfile=None):
         """Writes a report summarizing coverage statistics per module."""
         
+        from coverage.control import Numbers
         self.find_code_units(morfs, omit_prefixes)
 
         # Prepare the formatting strings
         outfile.write(header)
         outfile.write(rule)
 
-        total_statements = 0
-        total_executed = 0
-        total_units = 0
+        total = Numbers()
         
         for cu in self.code_units:
             try:
                 analysis = self.coverage._analyze(cu)
-                n = len(analysis.statements)
-                m = n - len(analysis.missing)
-                pc = analysis.percent_covered()
-                args = (cu.name, n, m, pc)
+                nums = analysis.numbers
+                args = (cu.name, nums.n_statements, nums.n_run, nums.percent_covered)
                 if self.show_missing:
                     args = args + (analysis.missing_formatted(),)
                 outfile.write(fmt_coverage % args)
-                total_units += 1
-                total_statements = total_statements + n
-                total_executed = total_executed + m
+                total += nums
             except KeyboardInterrupt:                       #pragma: no cover
                 raise
             except:
                     typ, msg = sys.exc_info()[:2]
                     outfile.write(fmt_err % (cu.name, typ.__name__, msg))
 
-        if total_units > 1:
+        if total.n_files > 1:
             outfile.write(rule)
-            if total_statements > 0:
-                pc = 100.0 * total_executed / total_statements
-            else:
-                pc = 100.0
-            args = ("TOTAL", total_statements, total_executed, pc)
+            args = ("TOTAL", total.n_statements, total.n_run, total.percent_covered)
             if self.show_missing:
                 args = args + ("",)
             outfile.write(fmt_coverage % args)