diff options
Diffstat (limited to 'coverage')
| -rw-r--r-- | coverage/backunittest.py | 2 | ||||
| -rw-r--r-- | coverage/cmdline.py | 16 | ||||
| -rw-r--r-- | coverage/config.py | 12 | ||||
| -rw-r--r-- | coverage/control.py | 31 | ||||
| -rw-r--r-- | coverage/env.py | 2 | ||||
| -rw-r--r-- | coverage/htmlfiles/coverage_html.js | 9 | ||||
| -rw-r--r-- | coverage/jsonreport.py | 4 | ||||
| -rw-r--r-- | coverage/multiproc.py | 2 | ||||
| -rw-r--r-- | coverage/parser.py | 1 | ||||
| -rw-r--r-- | coverage/plugin.py | 1 | ||||
| -rw-r--r-- | coverage/version.py | 2 | ||||
| -rw-r--r-- | coverage/xmlreport.py | 8 |
12 files changed, 69 insertions, 21 deletions
diff --git a/coverage/backunittest.py b/coverage/backunittest.py index 078f48cc..123bb2a1 100644 --- a/coverage/backunittest.py +++ b/coverage/backunittest.py @@ -18,7 +18,7 @@ class TestCase(unittest.TestCase): `unittest` doesn't have them. """ - # pylint: disable=arguments-differ, deprecated-method + # pylint: disable=signature-differs, deprecated-method if not unittest_has('assertCountEqual'): def assertCountEqual(self, *args, **kwargs): diff --git a/coverage/cmdline.py b/coverage/cmdline.py index 9fddb6bb..8b7fd3aa 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -146,6 +146,13 @@ class Opts(object): "to be run as 'python -m' would run it." ), ) + precision = optparse.make_option( + '', '--precision', action='store', metavar='N', type=int, + help=( + "Number of digits after the decimal point to display for " + "reported coverage percentages." + ), + ) rcfile = optparse.make_option( '', '--rcfile', action='store', help=( @@ -203,6 +210,7 @@ class CoverageOptionParser(optparse.OptionParser, object): omit=None, contexts=None, parallel_mode=None, + precision=None, pylib=None, rcfile=True, show_missing=None, @@ -358,6 +366,7 @@ CMDS = { Opts.ignore_errors, Opts.include, Opts.omit, + Opts.precision, Opts.show_contexts, Opts.skip_covered, Opts.skip_empty, @@ -395,6 +404,7 @@ CMDS = { Opts.ignore_errors, Opts.include, Opts.omit, + Opts.precision, Opts.show_missing, Opts.skip_covered, Opts.skip_empty, @@ -583,6 +593,7 @@ class CoverageScript(object): show_missing=options.show_missing, skip_covered=options.skip_covered, skip_empty=options.skip_empty, + precision=options.precision, **report_args ) elif options.action == "annotate": @@ -594,6 +605,7 @@ class CoverageScript(object): skip_covered=options.skip_covered, skip_empty=options.skip_empty, show_contexts=options.show_contexts, + precision=options.precision, **report_args ) elif options.action == "xml": @@ -806,7 +818,7 @@ HELP_TOPICS = { """, 'minimum_help': """\ - Code coverage for Python. Use '{program_name} help' for help. + Code coverage for Python, version {__version__} {extension_modifier}. Use '{program_name} help' for help. """, 'version': """\ @@ -857,8 +869,8 @@ if _profile: # pragma: debugging def main(argv=None): # pylint: disable=function-redefined """A wrapper around main that profiles.""" + profiler = SimpleLauncher.launch() try: - profiler = SimpleLauncher.launch() return original_main(argv) finally: data, _ = profiler.query(re_filter='coverage', max_records=100) diff --git a/coverage/config.py b/coverage/config.py index 78a3e86a..6d336d1f 100644 --- a/coverage/config.py +++ b/coverage/config.py @@ -72,7 +72,7 @@ class HandyConfigParser(configparser.RawConfigParser): d[opt] = self.get(section, opt) return d - def get(self, section, option, *args, **kwargs): # pylint: disable=arguments-differ + def get(self, section, option, *args, **kwargs): """Get a value, replacing environment variables also. The arguments are the same as `RawConfigParser.get`, but in the found @@ -325,7 +325,7 @@ class CoverageConfig(object): if used: self.config_file = os.path.abspath(filename) - with open(filename) as f: + with open(filename, "rb") as f: self._config_contents = f.read() return used @@ -421,6 +421,10 @@ class CoverageConfig(object): `value` is the new value for the option. """ + # Special-cased options. + if option_name == "paths": + self.paths = value + return # Check all the hard-coded options. for option_spec in self.CONFIG_FILE_OPTIONS: @@ -448,6 +452,10 @@ class CoverageConfig(object): Returns the value of the option. """ + # Special-cased options. + if option_name == "paths": + return self.paths + # Check all the hard-coded options. for option_spec in self.CONFIG_FILE_OPTIONS: attr, where = option_spec[:2] diff --git a/coverage/control.py b/coverage/control.py index f7db26e9..c2f40e70 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -367,7 +367,11 @@ class Coverage(object): option name. For example, the ``branch`` option in the ``[run]`` section of the config file would be indicated with `"run:branch"`. - Returns the value of the option. + Returns the value of the option. The type depends on the option + selected. + + As a special case, an `option_name` of ``"paths"`` will return an + OrderedDict with the entire ``[paths]`` section value. .. versionadded:: 4.0 @@ -394,6 +398,9 @@ class Coverage(object): [run] branch = True + As a special case, an `option_name` of ``"paths"`` will replace the + entire ``[paths]`` section. The value should be an OrderedDict. + .. versionadded:: 4.0 """ @@ -822,7 +829,7 @@ class Coverage(object): def report( self, morfs=None, show_missing=None, ignore_errors=None, file=None, omit=None, include=None, skip_covered=None, - contexts=None, skip_empty=None, + contexts=None, skip_empty=None, precision=None, ): """Write a textual summary report to `file`. @@ -850,6 +857,9 @@ class Coverage(object): expressions (using :func:`re.search <python:re.search>`) will be included in the report. + `precision` is the number of digits to display after the decimal + point for percentages. + All of the arguments default to the settings read from the :ref:`configuration file <config>`. @@ -861,12 +871,15 @@ class Coverage(object): .. versionadded:: 5.0 The `contexts` and `skip_empty` parameters. + .. versionadded:: 5.2 + The `precision` parameter. + """ with override_config( self, ignore_errors=ignore_errors, report_omit=omit, report_include=include, show_missing=show_missing, skip_covered=skip_covered, - report_contexts=contexts, skip_empty=skip_empty, + report_contexts=contexts, skip_empty=skip_empty, precision=precision, ): reporter = SummaryReporter(self) return reporter.report(morfs, outfile=file) @@ -892,10 +905,12 @@ class Coverage(object): reporter = AnnotateReporter(self) reporter.report(morfs, directory=directory) - def html_report(self, morfs=None, directory=None, ignore_errors=None, - omit=None, include=None, extra_css=None, title=None, - skip_covered=None, show_contexts=None, contexts=None, - skip_empty=None): + def html_report( + self, morfs=None, directory=None, ignore_errors=None, + omit=None, include=None, extra_css=None, title=None, + skip_covered=None, show_contexts=None, contexts=None, + skip_empty=None, precision=None, + ): """Generate an HTML report. The HTML is written to `directory`. The file "index.html" is the @@ -923,7 +938,7 @@ class Coverage(object): ignore_errors=ignore_errors, report_omit=omit, report_include=include, html_dir=directory, extra_css=extra_css, html_title=title, skip_covered=skip_covered, show_contexts=show_contexts, report_contexts=contexts, - skip_empty=skip_empty, + skip_empty=skip_empty, precision=precision, ): reporter = HtmlReporter(self) return reporter.report(morfs) diff --git a/coverage/env.py b/coverage/env.py index d194f34a..b5da3b47 100644 --- a/coverage/env.py +++ b/coverage/env.py @@ -57,7 +57,7 @@ class PYBEHAVIOR(object): unpackings_pep448 = (PYVERSION >= (3, 5)) # Can co_lnotab have negative deltas? - negative_lnotab = (PYVERSION >= (3, 6)) + negative_lnotab = (PYVERSION >= (3, 6)) and not (PYPY and PYPYVERSION < (7, 2)) # Do .pyc files conform to PEP 552? Hash-based pyc's. hashed_pyc_pep552 = (PYVERSION >= (3, 7, 0, 'alpha', 4)) diff --git a/coverage/htmlfiles/coverage_html.js b/coverage/htmlfiles/coverage_html.js index 22152333..3bf04bf9 100644 --- a/coverage/htmlfiles/coverage_html.js +++ b/coverage/htmlfiles/coverage_html.js @@ -172,7 +172,10 @@ coverage.index_ready = function ($) { // Look for a localStorage item containing previous sort settings: var sort_list = []; var storage_name = "COVERAGE_INDEX_SORT"; - var stored_list = localStorage.getItem(storage_name); + var stored_list = undefined; + try { + stored_list = localStorage.getItem(storage_name); + } catch(err) {} if (stored_list) { sort_list = JSON.parse('[[' + stored_list + ']]'); @@ -222,7 +225,9 @@ coverage.index_ready = function ($) { // Watch for page unload events so we can save the final sort settings: $(window).unload(function () { - localStorage.setItem(storage_name, sort_list.toString()) + try { + localStorage.setItem(storage_name, sort_list.toString()) + } catch(err) {} }); }; diff --git a/coverage/jsonreport.py b/coverage/jsonreport.py index 0c3f313d..4287bc79 100644 --- a/coverage/jsonreport.py +++ b/coverage/jsonreport.py @@ -60,6 +60,8 @@ class JsonReporter(object): self.report_data["totals"].update({ 'num_branches': self.total.n_branches, 'num_partial_branches': self.total.n_partial_branches, + 'covered_branches': self.total.n_executed_branches, + 'missing_branches': self.total.n_missing_branches, }) json.dump( @@ -95,5 +97,7 @@ class JsonReporter(object): reported_file['summary'].update({ 'num_branches': nums.n_branches, 'num_partial_branches': nums.n_partial_branches, + 'covered_branches': nums.n_executed_branches, + 'missing_branches': nums.n_missing_branches, }) return reported_file diff --git a/coverage/multiproc.py b/coverage/multiproc.py index 2931b3be..0afcb0c9 100644 --- a/coverage/multiproc.py +++ b/coverage/multiproc.py @@ -28,7 +28,7 @@ original_bootstrap = OriginalProcess._bootstrap class ProcessWithCoverage(OriginalProcess): # pylint: disable=abstract-method """A replacement for multiprocess.Process that starts coverage.""" - def _bootstrap(self, *args, **kwargs): # pylint: disable=arguments-differ + def _bootstrap(self, *args, **kwargs): # pylint: disable=signature-differs """Wrapper around _bootstrap to start coverage.""" try: from coverage import Coverage # avoid circular import diff --git a/coverage/parser.py b/coverage/parser.py index f0d378c6..e3e43149 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -610,6 +610,7 @@ class AstArcAnalyzer(object): return node.lineno _line__FunctionDef = _line_decorated + _line__AsyncFunctionDef = _line_decorated def _line__List(self, node): if node.elts: diff --git a/coverage/plugin.py b/coverage/plugin.py index b9cb7238..6997b489 100644 --- a/coverage/plugin.py +++ b/coverage/plugin.py @@ -496,6 +496,7 @@ class FileReporter(object): * ``'num'``: a number * ``'op'``: an operator * ``'str'``: a string literal + * ``'ws'``: some white space * ``'txt'``: some other kind of text If you concatenate all the token texts, and then join them with diff --git a/coverage/version.py b/coverage/version.py index bc86fbaa..5167b71d 100644 --- a/coverage/version.py +++ b/coverage/version.py @@ -5,7 +5,7 @@ # This file is exec'ed in setup.py, don't import anything! # Same semantics as sys.version_info. -version_info = (5, 0, 4, 'alpha', 0) +version_info = (5, 1, 1, 'alpha', 0) def _make_version(major, minor, micro, releaselevel, serial): diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py index 265bf02c..ad44775f 100644 --- a/coverage/xmlreport.py +++ b/coverage/xmlreport.py @@ -41,7 +41,9 @@ class XmlReporter(object): if self.config.source: for src in self.config.source: if os.path.exists(src): - self.source_paths.add(files.canonical_filename(src)) + if not self.config.relative_files: + src = files.canonical_filename(src) + self.source_paths.add(src) self.packages = {} self.xml_out = None @@ -144,18 +146,18 @@ class XmlReporter(object): # are populated later. Note that a package == a directory. filename = fr.filename.replace("\\", "/") for source_path in self.source_paths: + source_path = files.canonical_filename(source_path) if filename.startswith(source_path.replace("\\", "/") + "/"): rel_name = filename[len(source_path)+1:] break else: rel_name = fr.relative_filename() + self.source_paths.add(fr.filename[:-len(rel_name)].rstrip(r"\/")) dirname = os.path.dirname(rel_name) or u"." dirname = "/".join(dirname.split("/")[:self.config.xml_package_depth]) package_name = dirname.replace("/", ".") - if rel_name != fr.filename: - self.source_paths.add(fr.filename[:-len(rel_name)].rstrip(r"\/")) package = self.packages.setdefault(package_name, [{}, 0, 0, 0, 0]) xclass = self.xml_out.createElement("class") |
