summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/env.py5
-rw-r--r--coverage/misc.py16
-rw-r--r--coverage/parser.py8
-rw-r--r--coverage/summary.py7
-rw-r--r--tests/coveragetest.py27
-rw-r--r--tests/test_concurrency.py4
-rw-r--r--tests/test_execfile.py4
-rw-r--r--tests/test_farm.py4
-rw-r--r--tests/test_oddball.py3
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..