diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-12-03 08:54:27 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-12-03 08:54:27 -0500 |
commit | 3b6e8394c3e50cb733caafb275d2ae85c0397565 (patch) | |
tree | dd960443f9ef3772020d74c102d785968bb44dce /coverage/control.py | |
parent | 3416380e8e46d839c3111d9f82a5f7d93a218821 (diff) | |
parent | 9e4908f37c370250ebc7836e744a59170720a9e3 (diff) | |
download | python-coveragepy-git-3b6e8394c3e50cb733caafb275d2ae85c0397565.tar.gz |
Merged default onto config.
--HG--
branch : config
Diffstat (limited to 'coverage/control.py')
-rw-r--r-- | coverage/control.py | 81 |
1 files changed, 42 insertions, 39 deletions
diff --git a/coverage/control.py b/coverage/control.py index eb134450..39e3dfbb 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -1,6 +1,6 @@ """Core control stuff for Coverage.""" -import os, socket +import atexit, os, socket from coverage.annotate import AnnotateReporter from coverage.backward import string_class @@ -18,9 +18,9 @@ class coverage(object): """Programmatic access to Coverage. To use:: - + from coverage import coverage - + cov = coverage() cov.start() #.. blah blah (run your code) blah blah .. @@ -31,24 +31,24 @@ class coverage(object): def __init__(self, data_file=None, data_suffix=False, cover_pylib=None, auto_data=False, timid=None, branch=None, config_file=True): - """ + """ `data_file` is the base name of the data file to use, defaulting to ".coverage". `data_suffix` is appended to `data_file` to create the final file name. If `data_suffix` is simply True, then a suffix is created with the machine and process identity included. - + `cover_pylib` is a boolean determining whether Python code installed with the Python interpreter is measured. This includes the Python standard library and any packages installed with the interpreter. - + If `auto_data` is true, then any existing data file will be read when coverage measurement starts, and data will be saved automatically when measurement stops. - + If `timid` is true, then a slower and simpler trace function will be used. This is important for some environments where manipulation of tracing functions breaks the faster trace function. - + If `branch` is true, then branch coverage will be measured in addition to the usual statement coverage. @@ -63,7 +63,7 @@ class coverage(object): # Build our configuration from a number of sources: # 1: defaults: self.config = CoverageConfig() - + # 2: from the coveragerc file: if config_file: if config_file is True: @@ -83,12 +83,13 @@ class coverage(object): ) self.auto_data = auto_data - + self.atexit_registered = False + self.exclude_re = "" self._compile_exclude() self.file_locator = FileLocator() - + self.collector = Collector( self._should_trace, timid=self.config.timid, branch=self.config.branch @@ -121,13 +122,13 @@ class coverage(object): def _should_trace(self, filename, frame): """Decide whether to trace execution in `filename` - + This function is called from the trace function. As each new file name is encountered, this function determines whether it is traced or not. - + Returns a canonicalized filename if it should be traced, False if it should not. - + """ if filename == '<string>': # There's no point in ever tracing string executions, we can't do @@ -173,9 +174,9 @@ class coverage(object): def use_cache(self, usecache): """Control the use of a data file (incorrectly called a cache). - + `usecache` is true or false, whether to read and write data on disk. - + """ self.data.usefile(usecache) @@ -183,16 +184,17 @@ class coverage(object): """Load previously-collected coverage data from the data file.""" self.collector.reset() self.data.read() - + def start(self): """Start measuring code coverage.""" if self.auto_data: self.load() # Save coverage data when Python exits. - import atexit - atexit.register(self.save) + if not self.atexit_registered: + atexit.register(self.save) + self.atexit_registered = True self.collector.start() - + def stop(self): """Stop measuring code coverage.""" self.collector.stop() @@ -200,10 +202,10 @@ class coverage(object): def erase(self): """Erase previously-collected coverage data. - + This removes the in-memory data collected in this session as well as discarding the data file. - + """ self.collector.reset() self.data.erase() @@ -215,12 +217,12 @@ class coverage(object): def exclude(self, regex): """Exclude source lines from execution consideration. - + `regex` is a regular expression. Lines matching this expression are not considered executable when reporting code coverage. A list of regexes is maintained; this function adds a new regex to the list. Matching any of the regexes excludes a source line. - + """ self.config.exclude_list.append(regex) self._compile_exclude() @@ -240,11 +242,11 @@ class coverage(object): def combine(self): """Combine together a number of similarly-named coverage data files. - + All coverage data files whose name starts with `data_file` (from the coverage() constructor) will be read, and combined together into the current measurements. - + """ self.data.combine_parallel_data() @@ -262,14 +264,15 @@ class coverage(object): def analysis2(self, morf): """Analyze a module. - + `morf` is a module or a filename. It will be analyzed to determine its coverage statistics. The return value is a 5-tuple: - + * The filename for the module. * A list of line numbers of executable statements. * A list of line numbers of excluded statements. - * A list of line numbers of statements not run (missing from execution). + * A list of line numbers of statements not run (missing from + execution). * A readable formatted string of the missing line numbers. The analysis uses the source file itself and the current measured @@ -284,22 +287,22 @@ class coverage(object): def _analyze(self, it): """Analyze a single morf or code unit. - + Returns an `Analysis` object. """ if not isinstance(it, CodeUnit): it = code_unit_factory(it, self.file_locator)[0] - + return Analysis(self, it) def report(self, morfs=None, show_missing=True, ignore_errors=False, file=None, omit_prefixes=None): # pylint: disable-msg=W0622 """Write a summary report to `file`. - + Each module in `morfs` is listed, with counts of statements, executed statements, missing statements, and a list of lines missed. - + """ reporter = SummaryReporter(self, show_missing, ignore_errors) reporter.report(morfs, outfile=file, omit_prefixes=omit_prefixes) @@ -307,12 +310,12 @@ class coverage(object): def annotate(self, morfs=None, directory=None, ignore_errors=False, omit_prefixes=None): """Annotate a list of modules. - + Each module in `morfs` is annotated. The source is written to a new file, named with a ",cover" suffix, with each line prefixed with a marker to indicate the coverage of the line. Covered lines have ">", excluded lines have "-", and missing lines have "!". - + """ reporter = AnnotateReporter(self, ignore_errors) reporter.report( @@ -321,7 +324,7 @@ class coverage(object): def html_report(self, morfs=None, directory=None, ignore_errors=False, omit_prefixes=None): """Generate an HTML report. - + """ reporter = HtmlReporter(self, ignore_errors) reporter.report( @@ -330,9 +333,9 @@ class coverage(object): def xml_report(self, morfs=None, outfile=None, ignore_errors=False, omit_prefixes=None): """Generate an XML report of coverage results. - + The report is compatible with Cobertura reports. - + """ if outfile: outfile = open(outfile, "w") @@ -345,7 +348,7 @@ class coverage(object): def sysinfo(self): """Return a list of key,value pairs showing internal information.""" - + import coverage as covmod import platform, re, sys |