nose.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. """Run testsuites written for nose."""
  2. import warnings
  3. from _pytest.config import hookimpl
  4. from _pytest.deprecated import NOSE_SUPPORT
  5. from _pytest.fixtures import getfixturemarker
  6. from _pytest.nodes import Item
  7. from _pytest.python import Function
  8. from _pytest.unittest import TestCaseFunction
  9. @hookimpl(trylast=True)
  10. def pytest_runtest_setup(item: Item) -> None:
  11. if not isinstance(item, Function):
  12. return
  13. # Don't do nose style setup/teardown on direct unittest style classes.
  14. if isinstance(item, TestCaseFunction):
  15. return
  16. # Capture the narrowed type of item for the teardown closure,
  17. # see https://github.com/python/mypy/issues/2608
  18. func = item
  19. call_optional(func.obj, "setup", func.nodeid)
  20. func.addfinalizer(lambda: call_optional(func.obj, "teardown", func.nodeid))
  21. # NOTE: Module- and class-level fixtures are handled in python.py
  22. # with `pluginmanager.has_plugin("nose")` checks.
  23. # It would have been nicer to implement them outside of core, but
  24. # it's not straightforward.
  25. def call_optional(obj: object, name: str, nodeid: str) -> bool:
  26. method = getattr(obj, name, None)
  27. if method is None:
  28. return False
  29. is_fixture = getfixturemarker(method) is not None
  30. if is_fixture:
  31. return False
  32. if not callable(method):
  33. return False
  34. # Warn about deprecation of this plugin.
  35. method_name = getattr(method, "__name__", str(method))
  36. warnings.warn(
  37. NOSE_SUPPORT.format(nodeid=nodeid, method=method_name, stage=name), stacklevel=2
  38. )
  39. # If there are any problems allow the exception to raise rather than
  40. # silently ignoring it.
  41. method()
  42. return True