fixup nose/pytest plugins

This commit is contained in:
Ronny Pfannschmidt 2017-03-16 20:51:22 +01:00
parent c9ab421398
commit efe03400d8
2 changed files with 34 additions and 30 deletions

View File

@ -4,8 +4,8 @@ from __future__ import absolute_import, division, print_function
import sys import sys
import py import py
import pytest from _pytest import unittest, runner, python
from _pytest import unittest from _pytest.config import hookimpl
def get_skip_exceptions(): def get_skip_exceptions():
@ -20,19 +20,19 @@ def get_skip_exceptions():
def pytest_runtest_makereport(item, call): def pytest_runtest_makereport(item, call):
if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()): if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
# let's substitute the excinfo with a pytest.skip one # let's substitute the excinfo with a pytest.skip one
call2 = call.__class__(lambda: call2 = call.__class__(
pytest.skip(str(call.excinfo.value)), call.when) lambda: runner.skip(str(call.excinfo.value)), call.when)
call.excinfo = call2.excinfo call.excinfo = call2.excinfo
@pytest.hookimpl(trylast=True) @hookimpl(trylast=True)
def pytest_runtest_setup(item): def pytest_runtest_setup(item):
if is_potential_nosetest(item): if is_potential_nosetest(item):
if isinstance(item.parent, pytest.Generator): if isinstance(item.parent, python.Generator):
gen = item.parent gen = item.parent
if not hasattr(gen, '_nosegensetup'): if not hasattr(gen, '_nosegensetup'):
call_optional(gen.obj, 'setup') call_optional(gen.obj, 'setup')
if isinstance(gen.parent, pytest.Instance): if isinstance(gen.parent, python.Instance):
call_optional(gen.parent.obj, 'setup') call_optional(gen.parent.obj, 'setup')
gen._nosegensetup = True gen._nosegensetup = True
if not call_optional(item.obj, 'setup'): if not call_optional(item.obj, 'setup'):
@ -51,14 +51,14 @@ def teardown_nose(item):
def pytest_make_collect_report(collector): def pytest_make_collect_report(collector):
if isinstance(collector, pytest.Generator): if isinstance(collector, python.Generator):
call_optional(collector.obj, 'setup') call_optional(collector.obj, 'setup')
def is_potential_nosetest(item): def is_potential_nosetest(item):
# extra check needed since we do not do nose style setup/teardown # extra check needed since we do not do nose style setup/teardown
# on direct unittest style classes # on direct unittest style classes
return isinstance(item, pytest.Function) and \ return isinstance(item, python.Function) and \
not isinstance(item, unittest.TestCaseFunction) not isinstance(item, unittest.TestCaseFunction)

View File

@ -4,11 +4,12 @@ from __future__ import absolute_import, division, print_function
import sys import sys
import traceback import traceback
import pytest
# for transferring markers # for transferring markers
import _pytest._code import _pytest._code
from _pytest.python import transfer_markers from _pytest.config import hookimpl
from _pytest.skipping import MarkEvaluator from _pytest.runner import fail, skip
from _pytest.python import transfer_markers, Class, Module, Function
from _pytest.skipping import MarkEvaluator, xfail
def pytest_pycollect_makeitem(collector, name, obj): def pytest_pycollect_makeitem(collector, name, obj):
@ -22,11 +23,11 @@ def pytest_pycollect_makeitem(collector, name, obj):
return UnitTestCase(name, parent=collector) return UnitTestCase(name, parent=collector)
class UnitTestCase(pytest.Class): class UnitTestCase(Class):
# marker for fixturemanger.getfixtureinfo() # marker for fixturemanger.getfixtureinfo()
# to declare that our children do not support funcargs # to declare that our children do not support funcargs
nofuncargs = True nofuncargs = True
def setup(self): def setup(self):
cls = self.obj cls = self.obj
if getattr(cls, '__unittest_skip__', False): if getattr(cls, '__unittest_skip__', False):
@ -46,7 +47,7 @@ class UnitTestCase(pytest.Class):
return return
self.session._fixturemanager.parsefactories(self, unittest=True) self.session._fixturemanager.parsefactories(self, unittest=True)
loader = TestLoader() loader = TestLoader()
module = self.getparent(pytest.Module).obj module = self.getparent(Module).obj
foundsomething = False foundsomething = False
for name in loader.getTestCaseNames(self.obj): for name in loader.getTestCaseNames(self.obj):
x = getattr(self.obj, name) x = getattr(self.obj, name)
@ -65,7 +66,7 @@ class UnitTestCase(pytest.Class):
yield TestCaseFunction('runTest', parent=self) yield TestCaseFunction('runTest', parent=self)
class TestCaseFunction(pytest.Function): class TestCaseFunction(Function):
_excinfo = None _excinfo = None
def setup(self): def setup(self):
@ -110,36 +111,37 @@ class TestCaseFunction(pytest.Function):
try: try:
l = traceback.format_exception(*rawexcinfo) l = traceback.format_exception(*rawexcinfo)
l.insert(0, "NOTE: Incompatible Exception Representation, " l.insert(0, "NOTE: Incompatible Exception Representation, "
"displaying natively:\n\n") "displaying natively:\n\n")
pytest.fail("".join(l), pytrace=False) fail("".join(l), pytrace=False)
except (pytest.fail.Exception, KeyboardInterrupt): except (fail.Exception, KeyboardInterrupt):
raise raise
except: except:
pytest.fail("ERROR: Unknown Incompatible Exception " fail("ERROR: Unknown Incompatible Exception "
"representation:\n%r" %(rawexcinfo,), pytrace=False) "representation:\n%r" % (rawexcinfo,), pytrace=False)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except pytest.fail.Exception: except fail.Exception:
excinfo = _pytest._code.ExceptionInfo() excinfo = _pytest._code.ExceptionInfo()
self.__dict__.setdefault('_excinfo', []).append(excinfo) self.__dict__.setdefault('_excinfo', []).append(excinfo)
def addError(self, testcase, rawexcinfo): def addError(self, testcase, rawexcinfo):
self._addexcinfo(rawexcinfo) self._addexcinfo(rawexcinfo)
def addFailure(self, testcase, rawexcinfo): def addFailure(self, testcase, rawexcinfo):
self._addexcinfo(rawexcinfo) self._addexcinfo(rawexcinfo)
def addSkip(self, testcase, reason): def addSkip(self, testcase, reason):
try: try:
pytest.skip(reason) skip(reason)
except pytest.skip.Exception: except skip.Exception:
self._evalskip = MarkEvaluator(self, 'SkipTest') self._evalskip = MarkEvaluator(self, 'SkipTest')
self._evalskip.result = True self._evalskip.result = True
self._addexcinfo(sys.exc_info()) self._addexcinfo(sys.exc_info())
def addExpectedFailure(self, testcase, rawexcinfo, reason=""): def addExpectedFailure(self, testcase, rawexcinfo, reason=""):
try: try:
pytest.xfail(str(reason)) xfail(str(reason))
except pytest.xfail.Exception: except xfail.Exception:
self._addexcinfo(sys.exc_info()) self._addexcinfo(sys.exc_info())
def addUnexpectedSuccess(self, testcase, reason=""): def addUnexpectedSuccess(self, testcase, reason=""):
@ -179,13 +181,14 @@ class TestCaseFunction(pytest.Function):
self._testcase.debug() self._testcase.debug()
def _prunetraceback(self, excinfo): def _prunetraceback(self, excinfo):
pytest.Function._prunetraceback(self, excinfo) Function._prunetraceback(self, excinfo)
traceback = excinfo.traceback.filter( traceback = excinfo.traceback.filter(
lambda x:not x.frame.f_globals.get('__unittest')) lambda x: not x.frame.f_globals.get('__unittest'))
if traceback: if traceback:
excinfo.traceback = traceback excinfo.traceback = traceback
@pytest.hookimpl(tryfirst=True)
@hookimpl(tryfirst=True)
def pytest_runtest_makereport(item, call): def pytest_runtest_makereport(item, call):
if isinstance(item, TestCaseFunction): if isinstance(item, TestCaseFunction):
if item._excinfo: if item._excinfo:
@ -197,7 +200,8 @@ def pytest_runtest_makereport(item, call):
# twisted trial support # twisted trial support
@pytest.hookimpl(hookwrapper=True)
@hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item): def pytest_runtest_protocol(item):
if isinstance(item, TestCaseFunction) and \ if isinstance(item, TestCaseFunction) and \
'twisted.trial.unittest' in sys.modules: 'twisted.trial.unittest' in sys.modules: