| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame^] | 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 |