diff options
-rw-r--r-- | coverage/env.py | 5 | ||||
-rw-r--r-- | coverage/misc.py | 16 | ||||
-rw-r--r-- | coverage/parser.py | 8 | ||||
-rw-r--r-- | coverage/summary.py | 7 | ||||
-rw-r--r-- | tests/coveragetest.py | 27 | ||||
-rw-r--r-- | tests/test_concurrency.py | 4 | ||||
-rw-r--r-- | tests/test_execfile.py | 4 | ||||
-rw-r--r-- | tests/test_farm.py | 4 | ||||
-rw-r--r-- | tests/test_oddball.py | 3 |
9 files changed, 62 insertions, 16 deletions
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/misc.py b/coverage/misc.py index 5d330c6d..270c1468 100644 --- a/coverage/misc.py +++ b/coverage/misc.py @@ -10,6 +10,7 @@ import locale import os import sys import types +import unittest from coverage import env from coverage.backward import to_bytes, unicode_class @@ -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/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)) diff --git a/tests/coveragetest.py b/tests/coveragetest.py index 7ec623b3..a98462c4 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -20,6 +20,7 @@ from unittest_mixins import ( ) import coverage +from coverage import env from coverage.backunittest import TestCase from coverage.backward import StringIO, import_local_file, string_class, shlex_quote from coverage.backward import invalidate_import_caches @@ -377,7 +378,7 @@ class CoverageTest( """ # Make sure "python" and "coverage" mean specifically what we want # them to mean. - split_commandline = cmd.split(" ", 1) + split_commandline = cmd.split() command_name = split_commandline[0] command_args = split_commandline[1:] @@ -387,14 +388,26 @@ class CoverageTest( # get executed as "python3.3 foo.py". This is important because # Python 3.x doesn't install as "python", so you might get a Python # 2 executable instead if you don't use the executable's basename. - command_name = os.path.basename(sys.executable) + command_words = [os.path.basename(sys.executable)] + + elif command_name == "coverage": + if env.JYTHON: + # Jython can't do reporting, so let's skip the test now. + if command_args and command_args[0] in ('report', 'html', 'xml', 'annotate'): + self.skipTest("Can't run reporting commands in Jython") + # Jython can't run "coverage" as a command because the shebang + # refers to another shebang'd Python script. So run them as + # modules. + command_words = "jython -m coverage".split() + else: + # The invocation requests the Coverage.py program. Substitute the + # actual Coverage.py main command name. + command_words = [self.coverage_command] - if command_name == "coverage": - # The invocation requests the Coverage.py program. Substitute the - # actual Coverage.py main command name. - command_name = self.coverage_command + else: + command_words = [command_name] - cmd = " ".join([shlex_quote(command_name)] + command_args) + cmd = " ".join([shlex_quote(w) for w in command_words] + command_args) # Add our test modules directory to PYTHONPATH. I'm sure there's too # much path munging here, but... diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py index b441909f..a7dac064 100644 --- a/tests/test_concurrency.py +++ b/tests/test_concurrency.py @@ -353,9 +353,9 @@ class MultiprocessingTest(CoverageTest): """Test support of the multiprocessing module.""" def setUp(self): - if not multiprocessing: - self.skip("No multiprocessing in this Python") # pragma: only jython super(MultiprocessingTest, self).setUp() + if not multiprocessing: + self.skipTest("No multiprocessing in this Python") # pragma: only jython def try_multiprocessing_code( self, code, expected_out, the_module, concurrency="multiprocessing" diff --git a/tests/test_execfile.py b/tests/test_execfile.py index 8585b16d..6973022a 100644 --- a/tests/test_execfile.py +++ b/tests/test_execfile.py @@ -10,6 +10,7 @@ import os.path import re import sys +from coverage import env from coverage.backward import binary_bytes from coverage.execfile import run_python_file, run_python_module from coverage.misc import NoCode, NoSource @@ -102,6 +103,9 @@ class RunPycFileTest(CoverageTest): def make_pyc(self): """Create a .pyc file, and return the relative path to it.""" + if env.JYTHON: + self.skipTest("Can't make .pyc files on Jython") # pragma: only jython + self.make_file("compiled.py", """\ def doit(): print("I am here!") diff --git a/tests/test_farm.py b/tests/test_farm.py index 86238115..4a80be47 100644 --- a/tests/test_farm.py +++ b/tests/test_farm.py @@ -18,6 +18,7 @@ from unittest_mixins import ModuleAwareMixin, SysPathAwareMixin, change_dir from tests.helpers import run_command from tests.backtest import execfile # pylint: disable=redefined-builtin +from coverage import env from coverage.backunittest import unittest from coverage.debug import _TEST_NAME_FILE @@ -28,6 +29,9 @@ TEST_FILES = glob.glob("tests/farm/*/*.py") @pytest.mark.parametrize("filename", TEST_FILES) def test_farm(filename): + if env.JYTHON: + # All of the farm tests use reporting, so skip them all. + skip("Farm tests don't run on Jython") FarmTestCase(filename).run_fully() diff --git a/tests/test_oddball.py b/tests/test_oddball.py index da6c8fbb..98eee1bc 100644 --- a/tests/test_oddball.py +++ b/tests/test_oddball.py @@ -144,6 +144,9 @@ class MemoryLeakTest(CoverageTest): """ def test_for_leaks(self): + if env.JYTHON: + self.skipTest("Don't bother on Jython") # pragma: only jython + # Our original bad memory leak only happened on line numbers > 255, so # make a code object with more lines than that. Ugly string mumbo # jumbo to get 300 blank lines at the beginning.. |