2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
3 |
3 |
4 """Reporter foundation for coverage.py.""" |
4 """Reporter foundation for coverage.py.""" |
5 |
5 |
6 import os |
6 import os |
|
7 import warnings |
7 |
8 |
8 from coverage.files import prep_patterns, FnmatchMatcher |
9 from coverage.files import prep_patterns, FnmatchMatcher |
9 from coverage.misc import CoverageException, NoSource, NotPython |
10 from coverage.misc import CoverageException, NoSource, NotPython, isolate_module |
|
11 |
|
12 os = isolate_module(os) |
10 |
13 |
11 |
14 |
12 class Reporter(object): |
15 class Reporter(object): |
13 """A base class for all reporters.""" |
16 """A base class for all reporters.""" |
14 |
17 |
20 |
23 |
21 """ |
24 """ |
22 self.coverage = coverage |
25 self.coverage = coverage |
23 self.config = config |
26 self.config = config |
24 |
27 |
25 # The FileReporters to report on. Set by find_file_reporters. |
|
26 self.file_reporters = [] |
|
27 |
|
28 # The directory into which to place the report, used by some derived |
28 # The directory into which to place the report, used by some derived |
29 # classes. |
29 # classes. |
30 self.directory = None |
30 self.directory = None |
|
31 |
|
32 # Our method find_file_reporters used to set an attribute that other |
|
33 # code could read. That's been refactored away, but some third parties |
|
34 # were using that attribute. We'll continue to support it in a noisy |
|
35 # way for now. |
|
36 self._file_reporters = [] |
|
37 |
|
38 @property |
|
39 def file_reporters(self): |
|
40 """Keep .file_reporters working for private-grabbing tools.""" |
|
41 warnings.warn( |
|
42 "Report.file_reporters will no longer be available in Coverage.py 4.2", |
|
43 DeprecationWarning, |
|
44 ) |
|
45 return self._file_reporters |
31 |
46 |
32 def find_file_reporters(self, morfs): |
47 def find_file_reporters(self, morfs): |
33 """Find the FileReporters we'll report on. |
48 """Find the FileReporters we'll report on. |
34 |
49 |
35 `morfs` is a list of modules or file names. |
50 `morfs` is a list of modules or file names. |
36 |
51 |
|
52 Returns a list of FileReporters. |
|
53 |
37 """ |
54 """ |
38 self.file_reporters = self.coverage._get_file_reporters(morfs) |
55 reporters = self.coverage._get_file_reporters(morfs) |
39 |
56 |
40 if self.config.include: |
57 if self.config.include: |
41 patterns = prep_patterns(self.config.include) |
58 matcher = FnmatchMatcher(prep_patterns(self.config.include)) |
42 matcher = FnmatchMatcher(patterns) |
59 reporters = [fr for fr in reporters if matcher.match(fr.filename)] |
43 filtered = [] |
|
44 for fr in self.file_reporters: |
|
45 if matcher.match(fr.filename): |
|
46 filtered.append(fr) |
|
47 self.file_reporters = filtered |
|
48 |
60 |
49 if self.config.omit: |
61 if self.config.omit: |
50 patterns = prep_patterns(self.config.omit) |
62 matcher = FnmatchMatcher(prep_patterns(self.config.omit)) |
51 matcher = FnmatchMatcher(patterns) |
63 reporters = [fr for fr in reporters if not matcher.match(fr.filename)] |
52 filtered = [] |
|
53 for fr in self.file_reporters: |
|
54 if not matcher.match(fr.filename): |
|
55 filtered.append(fr) |
|
56 self.file_reporters = filtered |
|
57 |
64 |
58 self.file_reporters.sort() |
65 self._file_reporters = sorted(reporters) |
|
66 return self._file_reporters |
59 |
67 |
60 def report_files(self, report_fn, morfs, directory=None): |
68 def report_files(self, report_fn, morfs, directory=None): |
61 """Run a reporting function on a number of morfs. |
69 """Run a reporting function on a number of morfs. |
62 |
70 |
63 `report_fn` is called for each relative morf in `morfs`. It is called |
71 `report_fn` is called for each relative morf in `morfs`. It is called |
67 |
75 |
68 where `file_reporter` is the `FileReporter` for the morf, and |
76 where `file_reporter` is the `FileReporter` for the morf, and |
69 `analysis` is the `Analysis` for the morf. |
77 `analysis` is the `Analysis` for the morf. |
70 |
78 |
71 """ |
79 """ |
72 self.find_file_reporters(morfs) |
80 file_reporters = self.find_file_reporters(morfs) |
73 |
81 |
74 if not self.file_reporters: |
82 if not file_reporters: |
75 raise CoverageException("No data to report.") |
83 raise CoverageException("No data to report.") |
76 |
84 |
77 self.directory = directory |
85 self.directory = directory |
78 if self.directory and not os.path.exists(self.directory): |
86 if self.directory and not os.path.exists(self.directory): |
79 os.makedirs(self.directory) |
87 os.makedirs(self.directory) |
80 |
88 |
81 for fr in self.file_reporters: |
89 for fr in file_reporters: |
82 try: |
90 try: |
83 report_fn(fr, self.coverage._analyze(fr)) |
91 report_fn(fr, self.coverage._analyze(fr)) |
84 except NoSource: |
92 except NoSource: |
85 if not self.config.ignore_errors: |
93 if not self.config.ignore_errors: |
86 raise |
94 raise |