nose2.plugins.coverage 源代码

"""
Use this plugin to activate coverage report.

To use this plugin, you need to install ``nose2[coverage_plugin]``. e.g.

::

    $ pip install nose2[coverage_plugin]>=0.6.5


Then, you can enable coverage reporting with :

::

    $ nose2 --with-coverage

Or with this lines in ``unittest.cfg`` :

::

    [coverage]
    always-on = True


You can further specify coverage behaviors with a ``.coveragerc`` file, as
specified by `Coverage Config
<http://coverage.readthedocs.io/en/latest/config.html>`_.
However, when doing so you should also be aware of
`Differences From coverage`_.
"""
from __future__ import absolute_import, print_function
import six
import logging

from nose2.events import Plugin

log = logging.getLogger(__name__)


[文档]class Coverage(Plugin): configSection = 'coverage' commandLineSwitch = ('C', 'with-coverage', 'Turn on coverage reporting') _mpmode = False _subprocess = False def __init__(self): """Get our config and add our command line arguments.""" # tracking var for any decision which marks the entire run as failed self.decided_failure = False # buffer for error output data self.error_output_buffer = six.StringIO() self.covSource = (self.config.as_list('coverage', []) or ['.']) self.covReport = (self.config.as_list('coverage-report', []) or ['term']) self.covConfig = (self.config.as_str('coverage-config', '').strip() or '.coveragerc') group = self.session.pluginargs group.add_argument( '--coverage', action='append', default=[], metavar='PATH', dest='coverage_source', help='Measure coverage for filesystem path (multi-allowed)' ) group.add_argument( '--coverage-report', action='append', default=[], metavar='TYPE', choices=['term', 'term-missing', 'annotate', 'html', 'xml'], dest='coverage_report', help='Generate selected reports, available types:' ' term, term-missing, annotate, html, xml (multi-allowed)' ) group.add_argument( '--coverage-config', action='store', default='', metavar='FILE', dest='coverage_config', help='Config file for coverage, default: .coveragerc' ) self.covController = None def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) self._mpmode = True
[文档] def handleArgs(self, event): """Get our options in order command line, config file, hard coded.""" self.covSource = event.args.coverage_source or self.covSource self.covReport = event.args.coverage_report or self.covReport self.covConfig = event.args.coverage_config or self.covConfig
[文档] def createTests(self, event): """Start coverage early to catch imported modules. Only called if active so, safe to just start without checking flags""" if event.handled: log.error( 'createTests already handled -- ' 'coverage reporting will be inaccurate') else: log.debug( 'createTests not already handled. coverage should work') self._start_coverage()
[文档] def beforeSummaryReport(self, event): """Only called if active so stop coverage and produce reports.""" if self.covController: self.covController.stop() # write to .coverage file # do this explicitly (instead of passing auto_data=True to # Coverage constructor) in order to not load an existing .coverage # this better imitates the behavior of invoking `coverage` from the # command-line, which sets `Coverage._auto_save` (triggers atexit # saving to this file), but not `Coverage._auto_load` # requesting a better fix in nedbat/coveragepy#34 self.covController.save() if self._mpmode: self.covController.combine(strict=True) percent_coverage = None if 'term' in self.covReport or 'term-missing' in self.covReport: # only pass `show_missing` if "term-missing" was given # otherwise, just allow coverage to load show_missing from # config kwargs = {} if 'term-missing' in self.covReport: kwargs['show_missing'] = True percent_coverage = self.covController.report( file=self.error_output_buffer, **kwargs) if 'annotate' in self.covReport: percent_coverage = self.covController.annotate() if 'html' in self.covReport: percent_coverage = self.covController.html_report() if 'xml' in self.covReport: percent_coverage = self.covController.xml_report() fail_under = self.covController.get_option("report:fail_under") if (fail_under is not None and percent_coverage is not None and fail_under > percent_coverage): self.decided_failure = True
def startSubprocess(self, event): self._mpmode = True self._subprocess = True self._start_coverage() def stopSubprocess(self, event): self.covController.stop() self.covController.save()
[文档] def wasSuccessful(self, event): """Mark full test run as successful or unsuccessful""" if self.decided_failure: event.success = False
[文档] def afterSummaryReport(self, event): """Reporting data is collected, failure status determined and set. Now print any buffered error output saved from beforeSummaryReport""" print(self.error_output_buffer.getvalue(), file=event.stream)
def _start_coverage(self): try: import coverage except ImportError: print('Warning: you need to install "coverage_plugin" ' 'extra requirements to use this plugin. ' 'e.g. `pip install nose2[coverage_plugin]`') return self.covController = coverage.Coverage( source=self.covSource, config_file=self.covConfig, data_suffix=self._mpmode, ) # Call erase() to remove old files. This is important in multiprocess # mode, where per-process coverage files are unlikely to be # overwritten. self.covController.erase() # start immediately (don't wait until startTestRun) so that coverage # will pick up on things which happen at import time self.covController.start()