1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 2# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt 3 4"""Reporter foundation for coverage.py.""" 5 6import os 7 8from coverage.files import prep_patterns, FnmatchMatcher 9from coverage.misc import CoverageException, NoSource, NotPython, isolate_module 10 11os = isolate_module(os) 12 13 14class Reporter(object): 15 """A base class for all reporters.""" 16 17 def __init__(self, coverage, config): 18 """Create a reporter. 19 20 `coverage` is the coverage instance. `config` is an instance of 21 CoverageConfig, for controlling all sorts of behavior. 22 23 """ 24 self.coverage = coverage 25 self.config = config 26 27 # The FileReporters to report on. Set by find_file_reporters. 28 self.file_reporters = [] 29 30 # The directory into which to place the report, used by some derived 31 # classes. 32 self.directory = None 33 34 def find_file_reporters(self, morfs): 35 """Find the FileReporters we'll report on. 36 37 `morfs` is a list of modules or file names. 38 39 """ 40 reporters = self.coverage._get_file_reporters(morfs) 41 42 if self.config.include: 43 matcher = FnmatchMatcher(prep_patterns(self.config.include)) 44 reporters = [fr for fr in reporters if matcher.match(fr.filename)] 45 46 if self.config.omit: 47 matcher = FnmatchMatcher(prep_patterns(self.config.omit)) 48 reporters = [fr for fr in reporters if not matcher.match(fr.filename)] 49 50 self.file_reporters = sorted(reporters) 51 52 def report_files(self, report_fn, morfs, directory=None): 53 """Run a reporting function on a number of morfs. 54 55 `report_fn` is called for each relative morf in `morfs`. It is called 56 as:: 57 58 report_fn(file_reporter, analysis) 59 60 where `file_reporter` is the `FileReporter` for the morf, and 61 `analysis` is the `Analysis` for the morf. 62 63 """ 64 self.find_file_reporters(morfs) 65 66 if not self.file_reporters: 67 raise CoverageException("No data to report.") 68 69 self.directory = directory 70 if self.directory and not os.path.exists(self.directory): 71 os.makedirs(self.directory) 72 73 for fr in self.file_reporters: 74 try: 75 report_fn(fr, self.coverage._analyze(fr)) 76 except NoSource: 77 if not self.config.ignore_errors: 78 raise 79 except NotPython: 80 # Only report errors for .py files, and only if we didn't 81 # explicitly suppress those errors. 82 # NotPython is only raised by PythonFileReporter, which has a 83 # should_be_python() method. 84 if fr.should_be_python() and not self.config.ignore_errors: 85 raise 86