summaryrefslogtreecommitdiff
path: root/src/_pytest/nose.py
diff options
context:
space:
mode:
authorRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2018-05-26 09:05:41 +0200
committerRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2018-05-26 09:10:38 +0200
commiteaa882f3d5340956beb176aa1753e07e3f3f2190 (patch)
treef06d332cb33b5172c63bcfc7247d1ee25cd94795 /src/_pytest/nose.py
parentee6c54904b236fae0a15245ac0317a1818e71afc (diff)
downloadpytest-eaa882f3d5340956beb176aa1753e07e3f3f2190.tar.gz
switch to src layout
Diffstat (limited to 'src/_pytest/nose.py')
-rw-r--r--src/_pytest/nose.py72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/_pytest/nose.py b/src/_pytest/nose.py
new file mode 100644
index 000000000..bb2e4277d
--- /dev/null
+++ b/src/_pytest/nose.py
@@ -0,0 +1,72 @@
+""" run test suites written for nose. """
+from __future__ import absolute_import, division, print_function
+
+import sys
+
+from _pytest import unittest, runner, python
+from _pytest.config import hookimpl
+
+
+def get_skip_exceptions():
+ skip_classes = set()
+ for module_name in ("unittest", "unittest2", "nose"):
+ mod = sys.modules.get(module_name)
+ if hasattr(mod, "SkipTest"):
+ skip_classes.add(mod.SkipTest)
+ return tuple(skip_classes)
+
+
+def pytest_runtest_makereport(item, call):
+ if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
+ # let's substitute the excinfo with a pytest.skip one
+ call2 = call.__class__(lambda: runner.skip(str(call.excinfo.value)), call.when)
+ call.excinfo = call2.excinfo
+
+
+@hookimpl(trylast=True)
+def pytest_runtest_setup(item):
+ if is_potential_nosetest(item):
+ if isinstance(item.parent, python.Generator):
+ gen = item.parent
+ if not hasattr(gen, "_nosegensetup"):
+ call_optional(gen.obj, "setup")
+ if isinstance(gen.parent, python.Instance):
+ call_optional(gen.parent.obj, "setup")
+ gen._nosegensetup = True
+ if not call_optional(item.obj, "setup"):
+ # call module level setup if there is no object level one
+ call_optional(item.parent.obj, "setup")
+ # XXX this implies we only call teardown when setup worked
+ item.session._setupstate.addfinalizer((lambda: teardown_nose(item)), item)
+
+
+def teardown_nose(item):
+ if is_potential_nosetest(item):
+ if not call_optional(item.obj, "teardown"):
+ call_optional(item.parent.obj, "teardown")
+ # if hasattr(item.parent, '_nosegensetup'):
+ # #call_optional(item._nosegensetup, 'teardown')
+ # del item.parent._nosegensetup
+
+
+def pytest_make_collect_report(collector):
+ if isinstance(collector, python.Generator):
+ call_optional(collector.obj, "setup")
+
+
+def is_potential_nosetest(item):
+ # extra check needed since we do not do nose style setup/teardown
+ # on direct unittest style classes
+ return isinstance(item, python.Function) and not isinstance(
+ item, unittest.TestCaseFunction
+ )
+
+
+def call_optional(obj, name):
+ method = getattr(obj, name, None)
+ isfixture = hasattr(method, "_pytestfixturefunction")
+ if method is not None and not isfixture and callable(method):
+ # If there's any problems allow the exception to raise rather than
+ # silently ignoring them
+ method()
+ return True