Type annotate _pytest.unittest
This commit is contained in:
parent
db52928684
commit
b51ea4f1a5
|
@ -1,17 +1,23 @@
|
|||
""" discovery and running of std-library "unittest" style tests. """
|
||||
import sys
|
||||
import traceback
|
||||
import types
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import Generator
|
||||
from typing import Iterable
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
from typing import Union
|
||||
|
||||
import _pytest._code
|
||||
import pytest
|
||||
from _pytest.compat import getimfunc
|
||||
from _pytest.compat import is_async_function
|
||||
from _pytest.compat import TYPE_CHECKING
|
||||
from _pytest.config import hookimpl
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from _pytest.nodes import Collector
|
||||
from _pytest.nodes import Item
|
||||
from _pytest.outcomes import exit
|
||||
|
@ -25,6 +31,17 @@ from _pytest.runner import CallInfo
|
|||
from _pytest.skipping import skipped_by_mark_key
|
||||
from _pytest.skipping import unexpectedsuccess_key
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import unittest
|
||||
from typing import Type
|
||||
|
||||
from _pytest.fixtures import _Scope
|
||||
|
||||
_SysExcInfoType = Union[
|
||||
Tuple[Type[BaseException], BaseException, types.TracebackType],
|
||||
Tuple[None, None, None],
|
||||
]
|
||||
|
||||
|
||||
def pytest_pycollect_makeitem(
|
||||
collector: PyCollector, name: str, obj
|
||||
|
@ -78,30 +95,32 @@ class UnitTestCase(Class):
|
|||
if ut is None or runtest != ut.TestCase.runTest: # type: ignore
|
||||
yield TestCaseFunction.from_parent(self, name="runTest")
|
||||
|
||||
def _inject_setup_teardown_fixtures(self, cls):
|
||||
def _inject_setup_teardown_fixtures(self, cls: type) -> None:
|
||||
"""Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding
|
||||
teardown functions (#517)"""
|
||||
class_fixture = _make_xunit_fixture(
|
||||
cls, "setUpClass", "tearDownClass", scope="class", pass_self=False
|
||||
)
|
||||
if class_fixture:
|
||||
cls.__pytest_class_setup = class_fixture
|
||||
cls.__pytest_class_setup = class_fixture # type: ignore[attr-defined] # noqa: F821
|
||||
|
||||
method_fixture = _make_xunit_fixture(
|
||||
cls, "setup_method", "teardown_method", scope="function", pass_self=True
|
||||
)
|
||||
if method_fixture:
|
||||
cls.__pytest_method_setup = method_fixture
|
||||
cls.__pytest_method_setup = method_fixture # type: ignore[attr-defined] # noqa: F821
|
||||
|
||||
|
||||
def _make_xunit_fixture(obj, setup_name, teardown_name, scope, pass_self):
|
||||
def _make_xunit_fixture(
|
||||
obj: type, setup_name: str, teardown_name: str, scope: "_Scope", pass_self: bool
|
||||
):
|
||||
setup = getattr(obj, setup_name, None)
|
||||
teardown = getattr(obj, teardown_name, None)
|
||||
if setup is None and teardown is None:
|
||||
return None
|
||||
|
||||
@pytest.fixture(scope=scope, autouse=True)
|
||||
def fixture(self, request):
|
||||
def fixture(self, request: FixtureRequest) -> Generator[None, None, None]:
|
||||
if _is_skipped(self):
|
||||
reason = self.__unittest_skip_why__
|
||||
pytest.skip(reason)
|
||||
|
@ -122,32 +141,33 @@ def _make_xunit_fixture(obj, setup_name, teardown_name, scope, pass_self):
|
|||
|
||||
class TestCaseFunction(Function):
|
||||
nofuncargs = True
|
||||
_excinfo = None
|
||||
_testcase = None
|
||||
_excinfo = None # type: Optional[List[_pytest._code.ExceptionInfo]]
|
||||
_testcase = None # type: Optional[unittest.TestCase]
|
||||
|
||||
def setup(self):
|
||||
def setup(self) -> None:
|
||||
# a bound method to be called during teardown() if set (see 'runtest()')
|
||||
self._explicit_tearDown = None
|
||||
self._testcase = self.parent.obj(self.name)
|
||||
self._explicit_tearDown = None # type: Optional[Callable[[], None]]
|
||||
assert self.parent is not None
|
||||
self._testcase = self.parent.obj(self.name) # type: ignore[attr-defined] # noqa: F821
|
||||
self._obj = getattr(self._testcase, self.name)
|
||||
if hasattr(self, "_request"):
|
||||
self._request._fillfixtures()
|
||||
|
||||
def teardown(self):
|
||||
def teardown(self) -> None:
|
||||
if self._explicit_tearDown is not None:
|
||||
self._explicit_tearDown()
|
||||
self._explicit_tearDown = None
|
||||
self._testcase = None
|
||||
self._obj = None
|
||||
|
||||
def startTest(self, testcase):
|
||||
def startTest(self, testcase: "unittest.TestCase") -> None:
|
||||
pass
|
||||
|
||||
def _addexcinfo(self, rawexcinfo):
|
||||
def _addexcinfo(self, rawexcinfo: "_SysExcInfoType") -> None:
|
||||
# unwrap potential exception info (see twisted trial support below)
|
||||
rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo)
|
||||
try:
|
||||
excinfo = _pytest._code.ExceptionInfo(rawexcinfo)
|
||||
excinfo = _pytest._code.ExceptionInfo(rawexcinfo) # type: ignore[arg-type] # noqa: F821
|
||||
# invoke the attributes to trigger storing the traceback
|
||||
# trial causes some issue there
|
||||
excinfo.value
|
||||
|
@ -176,7 +196,9 @@ class TestCaseFunction(Function):
|
|||
excinfo = _pytest._code.ExceptionInfo.from_current()
|
||||
self.__dict__.setdefault("_excinfo", []).append(excinfo)
|
||||
|
||||
def addError(self, testcase, rawexcinfo):
|
||||
def addError(
|
||||
self, testcase: "unittest.TestCase", rawexcinfo: "_SysExcInfoType"
|
||||
) -> None:
|
||||
try:
|
||||
if isinstance(rawexcinfo[1], exit.Exception):
|
||||
exit(rawexcinfo[1].msg)
|
||||
|
@ -184,29 +206,38 @@ class TestCaseFunction(Function):
|
|||
pass
|
||||
self._addexcinfo(rawexcinfo)
|
||||
|
||||
def addFailure(self, testcase, rawexcinfo):
|
||||
def addFailure(
|
||||
self, testcase: "unittest.TestCase", rawexcinfo: "_SysExcInfoType"
|
||||
) -> None:
|
||||
self._addexcinfo(rawexcinfo)
|
||||
|
||||
def addSkip(self, testcase, reason):
|
||||
def addSkip(self, testcase: "unittest.TestCase", reason: str) -> None:
|
||||
try:
|
||||
skip(reason)
|
||||
except skip.Exception:
|
||||
self._store[skipped_by_mark_key] = True
|
||||
self._addexcinfo(sys.exc_info())
|
||||
|
||||
def addExpectedFailure(self, testcase, rawexcinfo, reason=""):
|
||||
def addExpectedFailure(
|
||||
self,
|
||||
testcase: "unittest.TestCase",
|
||||
rawexcinfo: "_SysExcInfoType",
|
||||
reason: str = "",
|
||||
) -> None:
|
||||
try:
|
||||
xfail(str(reason))
|
||||
except xfail.Exception:
|
||||
self._addexcinfo(sys.exc_info())
|
||||
|
||||
def addUnexpectedSuccess(self, testcase, reason=""):
|
||||
def addUnexpectedSuccess(
|
||||
self, testcase: "unittest.TestCase", reason: str = ""
|
||||
) -> None:
|
||||
self._store[unexpectedsuccess_key] = reason
|
||||
|
||||
def addSuccess(self, testcase):
|
||||
def addSuccess(self, testcase: "unittest.TestCase") -> None:
|
||||
pass
|
||||
|
||||
def stopTest(self, testcase):
|
||||
def stopTest(self, testcase: "unittest.TestCase") -> None:
|
||||
pass
|
||||
|
||||
def _expecting_failure(self, test_method) -> bool:
|
||||
|
@ -218,14 +249,17 @@ class TestCaseFunction(Function):
|
|||
expecting_failure_class = getattr(self, "__unittest_expecting_failure__", False)
|
||||
return bool(expecting_failure_class or expecting_failure_method)
|
||||
|
||||
def runtest(self):
|
||||
def runtest(self) -> None:
|
||||
from _pytest.debugging import maybe_wrap_pytest_function_for_tracing
|
||||
|
||||
assert self._testcase is not None
|
||||
|
||||
maybe_wrap_pytest_function_for_tracing(self)
|
||||
|
||||
# let the unittest framework handle async functions
|
||||
if is_async_function(self.obj):
|
||||
self._testcase(self)
|
||||
# Type ignored because self acts as the TestResult, but is not actually one.
|
||||
self._testcase(result=self) # type: ignore[arg-type] # noqa: F821
|
||||
else:
|
||||
# when --pdb is given, we want to postpone calling tearDown() otherwise
|
||||
# when entering the pdb prompt, tearDown() would have probably cleaned up
|
||||
|
@ -241,11 +275,11 @@ class TestCaseFunction(Function):
|
|||
# wrap_pytest_function_for_tracing replaces self.obj by a wrapper
|
||||
setattr(self._testcase, self.name, self.obj)
|
||||
try:
|
||||
self._testcase(result=self)
|
||||
self._testcase(result=self) # type: ignore[arg-type] # noqa: F821
|
||||
finally:
|
||||
delattr(self._testcase, self.name)
|
||||
|
||||
def _prunetraceback(self, excinfo):
|
||||
def _prunetraceback(self, excinfo: _pytest._code.ExceptionInfo) -> None:
|
||||
Function._prunetraceback(self, excinfo)
|
||||
traceback = excinfo.traceback.filter(
|
||||
lambda x: not x.frame.f_globals.get("__unittest")
|
||||
|
@ -313,7 +347,7 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
|||
yield
|
||||
|
||||
|
||||
def check_testcase_implements_trial_reporter(done=[]):
|
||||
def check_testcase_implements_trial_reporter(done: List[int] = []) -> None:
|
||||
if done:
|
||||
return
|
||||
from zope.interface import classImplements
|
||||
|
|
Loading…
Reference in New Issue