diff options
Diffstat (limited to 'coverage')
-rw-r--r-- | coverage/control.py | 11 | ||||
-rw-r--r-- | coverage/debug.py | 5 | ||||
-rw-r--r-- | coverage/env.py | 5 | ||||
-rw-r--r-- | coverage/html.py | 18 | ||||
-rw-r--r-- | coverage/misc.py | 16 | ||||
-rw-r--r-- | coverage/parser.py | 8 | ||||
-rw-r--r-- | coverage/pytracer.py | 5 | ||||
-rw-r--r-- | coverage/summary.py | 7 |
8 files changed, 57 insertions, 18 deletions
diff --git a/coverage/control.py b/coverage/control.py index 243fe587..ebb449c3 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -24,7 +24,6 @@ from coverage.files import ModuleMatcher, abs_file from coverage.html import HtmlReporter from coverage.misc import CoverageException, bool_or_none, join_regex from coverage.misc import file_be_gone, isolate_module -from coverage.multiproc import patch_multiprocessing from coverage.plugin import FileReporter from coverage.plugin_support import Plugins from coverage.python import PythonFileReporter, source_for_file @@ -32,6 +31,12 @@ from coverage.results import Analysis, Numbers from coverage.summary import SummaryReporter from coverage.xmlreport import XmlReporter +try: + from coverage.multiproc import patch_multiprocessing +except ImportError: # pragma: only jython + # Jython has no multiprocessing module. + patch_multiprocessing = None + os = isolate_module(os) # Pypy has some unusual stuff in the "stdlib". Consider those locations @@ -231,6 +236,10 @@ class Coverage(object): concurrency = self.config.concurrency or [] if "multiprocessing" in concurrency: + if not patch_multiprocessing: + raise CoverageException( # pragma: only jython + "multiprocessing is not supported on this Python" + ) patch_multiprocessing(rcfile=self.config_file) # Multi-processing uses parallel for the subprocesses, so also use # it for the main process. diff --git a/coverage/debug.py b/coverage/debug.py index 91ccba77..5ffed39d 100644 --- a/coverage/debug.py +++ b/coverage/debug.py @@ -202,8 +202,9 @@ def enable_aspectlib_maybe(): # pragma: debugging Define COVERAGE_ASPECTLIB to enable and configure aspectlib to trace execution:: - export COVERAGE_LOG=covaspect.txt - COVERAGE_ASPECTLIB=coverage.Coverage:coverage.data.CoverageData program... + $ export COVERAGE_LOG=covaspect.txt + $ export COVERAGE_ASPECTLIB=coverage.Coverage:coverage.data.CoverageData + $ coverage run blah.py ... This will trace all the public methods on Coverage and CoverageData, writing the information to covaspect.txt. diff --git a/coverage/env.py b/coverage/env.py index 6db3b857..528c774a 100644 --- a/coverage/env.py +++ b/coverage/env.py @@ -4,6 +4,7 @@ """Determine facts about the environment.""" import os +import platform import sys # Operating systems. @@ -11,10 +12,12 @@ WINDOWS = sys.platform == "win32" LINUX = sys.platform == "linux2" # Python implementations. -PYPY = '__pypy__' in sys.builtin_module_names +PYPY = (platform.python_implementation() == 'PyPy') if PYPY: PYPYVERSION = sys.pypy_version_info +JYTHON = (platform.python_implementation() == 'Jython') + # Python versions. PYVERSION = sys.version_info PY2 = PYVERSION < (3, 0) diff --git a/coverage/html.py b/coverage/html.py index 22783ef7..b0c61649 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -12,7 +12,7 @@ import coverage from coverage import env from coverage.backward import iitems from coverage.files import flat_rootname -from coverage.misc import CoverageException, Hasher, isolate_module +from coverage.misc import CoverageException, file_be_gone, Hasher, isolate_module from coverage.report import Reporter from coverage.results import Numbers from coverage.templite import Templite @@ -105,6 +105,7 @@ class HtmlReporter(Reporter): self.coverage = cov self.files = [] + self.all_files_nums = [] self.has_arcs = self.coverage.data.has_arcs() self.status = HtmlStatus() self.extra_css = None @@ -137,7 +138,7 @@ class HtmlReporter(Reporter): # Process all the files. self.report_files(self.html_file, morfs, self.config.html_dir) - if not self.files: + if not self.all_files_nums: raise CoverageException("No data to report.") # Write the index file. @@ -171,19 +172,26 @@ class HtmlReporter(Reporter): def html_file(self, fr, analysis): """Generate an HTML file for one source file.""" + rootname = flat_rootname(fr.relative_filename()) + html_filename = rootname + ".html" + html_path = os.path.join(self.directory, html_filename) + # Get the numbers for this file. nums = analysis.numbers + self.all_files_nums.append(nums) + if self.config.skip_covered: # Don't report on 100% files. no_missing_lines = (nums.n_missing == 0) no_missing_branches = (nums.n_partial_branches == 0) if no_missing_lines and no_missing_branches: + # If there's an existing file, remove it. + file_be_gone(html_path) return source = fr.source() # Find out if the file on disk is already correct. - rootname = flat_rootname(fr.relative_filename()) this_hash = self.file_hash(source.encode('utf-8'), fr) that_hash = self.status.file_hash(rootname) if this_hash == that_hash: @@ -275,8 +283,6 @@ class HtmlReporter(Reporter): 'time_stamp': self.time_stamp, }) - html_filename = rootname + ".html" - html_path = os.path.join(self.directory, html_filename) write_html(html_path, html) # Save this file's information for the index file. @@ -292,7 +298,7 @@ class HtmlReporter(Reporter): """Write the index.html file for this report.""" index_tmpl = Templite(read_data("index.html"), self.template_globals) - self.totals = sum(f['nums'] for f in self.files) + self.totals = sum(self.all_files_nums) html = index_tmpl.render({ 'has_arcs': self.has_arcs, diff --git a/coverage/misc.py b/coverage/misc.py index 5d330c6d..240a2587 100644 --- a/coverage/misc.py +++ b/coverage/misc.py @@ -13,6 +13,7 @@ import types from coverage import env from coverage.backward import to_bytes, unicode_class +from coverage.backunittest import unittest ISOLATED_MODULES = {} @@ -264,3 +265,18 @@ class ExceptionDuringRun(CoverageException): """ pass + + +class StopEverything(unittest.SkipTest): + """An exception that means everything should stop. + + This derives from SkipTest so that tests that spring this trap will be + skipped automatically, without a lot of boilerplate all over the place. + + """ + pass + + +class IncapablePython(CoverageException, StopEverything): + """An operation is attempted that this version of Python cannot do.""" + pass diff --git a/coverage/parser.py b/coverage/parser.py index 540ad098..54603bf3 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -16,7 +16,7 @@ from coverage.backward import bytes_to_ints, string_class from coverage.bytecode import CodeObjects from coverage.debug import short_stack from coverage.misc import contract, new_contract, nice_pair, join_regex -from coverage.misc import CoverageException, NoSource, NotPython +from coverage.misc import NoSource, IncapablePython, NotPython from coverage.phystokens import compile_unicode, generate_tokens, neuter_encoding_declaration @@ -371,11 +371,11 @@ class ByteParser(object): # Alternative Python implementations don't always provide all the # attributes on code objects that we need to do the analysis. - for attr in ['co_lnotab', 'co_firstlineno', 'co_consts']: + for attr in ['co_lnotab', 'co_firstlineno']: if not hasattr(self.code, attr): - raise CoverageException( + raise IncapablePython( # pragma: only jython "This implementation of Python doesn't support code analysis.\n" - "Run coverage.py under CPython for this command." + "Run coverage.py under another Python for this command." ) def child_parsers(self): diff --git a/coverage/pytracer.py b/coverage/pytracer.py index 5a1b5d7b..bb300563 100644 --- a/coverage/pytracer.py +++ b/coverage/pytracer.py @@ -116,8 +116,9 @@ class PyTracer(object): if self.trace_arcs and self.cur_file_dict: # Record an arc leaving the function, but beware that a # "return" event might just mean yielding from a generator. - bytecode = frame.f_code.co_code[frame.f_lasti] - if bytecode != YIELD_VALUE: + # Jython seems to have an empty co_code, so just assume return. + code = frame.f_code.co_code + if (not code) or code[frame.f_lasti] != YIELD_VALUE: first = frame.f_code.co_firstlineno self.cur_file_dict[(self.last_line, -first)] = None # Leaving this function, pop the filename stack. diff --git a/coverage/summary.py b/coverage/summary.py index d94ce8b2..271b648a 100644 --- a/coverage/summary.py +++ b/coverage/summary.py @@ -8,7 +8,7 @@ import sys from coverage import env from coverage.report import Reporter from coverage.results import Numbers -from coverage.misc import NotPython, CoverageException, output_encoding +from coverage.misc import NotPython, CoverageException, output_encoding, StopEverything class SummaryReporter(Reporter): @@ -55,13 +55,16 @@ class SummaryReporter(Reporter): skipped_count += 1 continue fr_analysis.append((fr, analysis)) + except StopEverything: + # Don't report this on single files, it's a systemic problem. + raise except Exception: report_it = not self.config.ignore_errors if report_it: typ, msg = sys.exc_info()[:2] # NotPython is only raised by PythonFileReporter, which has a # should_be_python() method. - if typ is NotPython and not fr.should_be_python(): + if issubclass(typ, NotPython) and not fr.should_be_python(): report_it = False if report_it: writeout(fmt_err % (fr.relative_filename(), typ.__name__, msg)) |