1 """Reporter foundation for Coverage.""" 2 3 import fnmatch, os 4 from coverage.codeunit import code_unit_factory 5 from coverage.misc import CoverageException, NoSource, NotPython 6 7 class Reporter(object): 8 """A base class for all reporters.""" 9 10 def __init__(self, coverage, ignore_errors=False): 11 """Create a reporter. 12 13 `coverage` is the coverage instance. `ignore_errors` controls how 14 skittish the reporter will be during file processing. 15 16 """ 17 self.coverage = coverage 18 self.ignore_errors = ignore_errors 19 20 # The code units to report on. Set by find_code_units. 21 self.code_units = [] 22 23 # The directory into which to place the report, used by some derived 24 # classes. 25 self.directory = None 26 27 def find_code_units(self, morfs, config): 28 """Find the code units we'll report on. 29 30 `morfs` is a list of modules or filenames. `config` is a 31 CoverageConfig instance. 32 33 """ 34 morfs = morfs or self.coverage.data.measured_files() 35 file_locator = self.coverage.file_locator 36 self.code_units = code_unit_factory(morfs, file_locator) 37 38 if config.include: 39 patterns = [file_locator.abs_file(p) for p in config.include] 40 filtered = [] 41 for cu in self.code_units: 42 for pattern in patterns: 43 if fnmatch.fnmatch(cu.filename, pattern): 44 filtered.append(cu) 45 break 46 self.code_units = filtered 47 48 if config.omit: 49 patterns = [file_locator.abs_file(p) for p in config.omit] 50 filtered = [] 51 for cu in self.code_units: 52 for pattern in patterns: 53 if fnmatch.fnmatch(cu.filename, pattern): 54 break 55 else: 56 filtered.append(cu) 57 self.code_units = filtered 58 59 self.code_units.sort() 60 61 def report_files(self, report_fn, morfs, config, directory=None): 62 """Run a reporting function on a number of morfs. 63 64 `report_fn` is called for each relative morf in `morfs`. It is called 65 as:: 66 67 report_fn(code_unit, analysis) 68 69 where `code_unit` is the `CodeUnit` for the morf, and `analysis` is 70 the `Analysis` for the morf. 71 72 `config` is a CoverageConfig instance. 73 74 """ 75 self.find_code_units(morfs, config) 76 77 if not self.code_units: 78 raise CoverageException("No data to report.") 79 80 self.directory = directory 81 if self.directory and not os.path.exists(self.directory): 82 os.makedirs(self.directory) 83 84 for cu in self.code_units: 85 try: 86 report_fn(cu, self.coverage._analyze(cu)) 87 except (NoSource, NotPython): 88 if not self.ignore_errors: 89 raise 90