diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e8ad90ff7..e828bdca9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,8 @@ 3.0.1.dev ========= -* +* Fix regression when ``importorskip`` is used at module level (`#1822`_). + Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR. * @@ -11,6 +12,9 @@ +.. _#1822: https://github.com/pytest-dev/pytest/issues/1822 + + 3.0.0 ===== diff --git a/_pytest/python.py b/_pytest/python.py index 9e9c78897..50a68ec80 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -431,7 +431,9 @@ class Module(pytest.File, PyCollector): "Make sure your test modules/packages have valid Python names." % (self.fspath, exc or exc_class) ) - except _pytest.runner.Skipped: + except _pytest.runner.Skipped as e: + if e.allow_module_level: + raise raise self.CollectError( "Using @pytest.skip outside a test (e.g. as a test function " "decorator) is not allowed. Use @pytest.mark.skip or " diff --git a/_pytest/runner.py b/_pytest/runner.py index 525a2b00f..c619ac39b 100644 --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -492,10 +492,16 @@ class Skipped(OutcomeException): # in order to have Skipped exception printing shorter/nicer __module__ = 'builtins' + def __init__(self, msg=None, pytrace=True, allow_module_level=False): + OutcomeException.__init__(self, msg=msg, pytrace=pytrace) + self.allow_module_level = allow_module_level + + class Failed(OutcomeException): """ raised from an explicit call to pytest.fail() """ __module__ = 'builtins' + class Exit(KeyboardInterrupt): """ raised for immediate program exits (no tracebacks/summaries)""" def __init__(self, msg="unknown reason"): @@ -546,7 +552,7 @@ def importorskip(modname, minversion=None): # Do not raise chained exception here(#1485) should_skip = True if should_skip: - skip("could not import %r" %(modname,)) + raise Skipped("could not import %r" %(modname,), allow_module_level=True) mod = sys.modules[modname] if minversion is None: return mod @@ -555,10 +561,11 @@ def importorskip(modname, minversion=None): try: from pkg_resources import parse_version as pv except ImportError: - skip("we have a required version for %r but can not import " - "no pkg_resources to parse version strings." %(modname,)) + raise Skipped("we have a required version for %r but can not import " + "no pkg_resources to parse version strings." % (modname,), + allow_module_level=True) if verattr is None or pv(verattr) < pv(minversion): - skip("module %r has __version__ %r, required is: %r" %( - modname, verattr, minversion)) + raise Skipped("module %r has __version__ %r, required is: %r" %( + modname, verattr, minversion), allow_module_level=True) return mod diff --git a/testing/test_runner.py b/testing/test_runner.py index a4fe80912..e88a548d7 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -571,6 +571,19 @@ def test_importorskip_dev_module(monkeypatch): pytest.fail("spurious skip") +def test_importorskip_module_level(testdir): + """importorskip must be able to skip entire modules when used at module level""" + testdir.makepyfile(''' + import pytest + foobarbaz = pytest.importorskip("foobarbaz") + + def test_foo(): + pass + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*collected 0 items / 1 skipped*']) + + def test_pytest_cmdline_main(testdir): p = testdir.makepyfile(""" import pytest