Merge pull request #7844 from bluetech/typing-fixtures
fixtures: some type annotations, remove cyclic dependency
This commit is contained in:
commit
1c08f1dd0f
|
@ -29,12 +29,14 @@ import attr
|
||||||
import py
|
import py
|
||||||
|
|
||||||
import _pytest
|
import _pytest
|
||||||
|
from _pytest import nodes
|
||||||
from _pytest._code import getfslineno
|
from _pytest._code import getfslineno
|
||||||
from _pytest._code.code import FormattedExcinfo
|
from _pytest._code.code import FormattedExcinfo
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest.compat import _format_args
|
from _pytest.compat import _format_args
|
||||||
from _pytest.compat import _PytestWrapper
|
from _pytest.compat import _PytestWrapper
|
||||||
|
from _pytest.compat import assert_never
|
||||||
from _pytest.compat import final
|
from _pytest.compat import final
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
from _pytest.compat import get_real_method
|
from _pytest.compat import get_real_method
|
||||||
|
@ -51,16 +53,17 @@ from _pytest.config.argparsing import Parser
|
||||||
from _pytest.deprecated import FILLFUNCARGS
|
from _pytest.deprecated import FILLFUNCARGS
|
||||||
from _pytest.mark import Mark
|
from _pytest.mark import Mark
|
||||||
from _pytest.mark import ParameterSet
|
from _pytest.mark import ParameterSet
|
||||||
|
from _pytest.mark.structures import MarkDecorator
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import TEST_OUTCOME
|
from _pytest.outcomes import TEST_OUTCOME
|
||||||
from _pytest.pathlib import absolutepath
|
from _pytest.pathlib import absolutepath
|
||||||
|
from _pytest.store import StoreKey
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Deque
|
from typing import Deque
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
from typing_extensions import Literal
|
from typing_extensions import Literal
|
||||||
|
|
||||||
from _pytest import nodes
|
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
from _pytest.python import CallSpec2
|
from _pytest.python import CallSpec2
|
||||||
from _pytest.python import Function
|
from _pytest.python import Function
|
||||||
|
@ -103,24 +106,9 @@ class PseudoFixtureDef(Generic[_FixtureValue]):
|
||||||
|
|
||||||
|
|
||||||
def pytest_sessionstart(session: "Session") -> None:
|
def pytest_sessionstart(session: "Session") -> None:
|
||||||
import _pytest.python
|
|
||||||
import _pytest.nodes
|
|
||||||
|
|
||||||
scopename2class.update(
|
|
||||||
{
|
|
||||||
"package": _pytest.python.Package,
|
|
||||||
"class": _pytest.python.Class,
|
|
||||||
"module": _pytest.python.Module,
|
|
||||||
"function": _pytest.nodes.Item,
|
|
||||||
"session": _pytest.main.Session,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
session._fixturemanager = FixtureManager(session)
|
session._fixturemanager = FixtureManager(session)
|
||||||
|
|
||||||
|
|
||||||
scopename2class = {} # type: Dict[str, Type[nodes.Node]]
|
|
||||||
|
|
||||||
|
|
||||||
def get_scope_package(node, fixturedef: "FixtureDef[object]"):
|
def get_scope_package(node, fixturedef: "FixtureDef[object]"):
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -136,15 +124,31 @@ def get_scope_package(node, fixturedef: "FixtureDef[object]"):
|
||||||
return current
|
return current
|
||||||
|
|
||||||
|
|
||||||
def get_scope_node(node, scope):
|
def get_scope_node(
|
||||||
cls = scopename2class.get(scope)
|
node: nodes.Node, scope: "_Scope"
|
||||||
if cls is None:
|
) -> Optional[Union[nodes.Item, nodes.Collector]]:
|
||||||
raise ValueError("unknown scope")
|
import _pytest.python
|
||||||
return node.getparent(cls)
|
|
||||||
|
if scope == "function":
|
||||||
|
return node.getparent(nodes.Item)
|
||||||
|
elif scope == "class":
|
||||||
|
return node.getparent(_pytest.python.Class)
|
||||||
|
elif scope == "module":
|
||||||
|
return node.getparent(_pytest.python.Module)
|
||||||
|
elif scope == "package":
|
||||||
|
return node.getparent(_pytest.python.Package)
|
||||||
|
elif scope == "session":
|
||||||
|
return node.getparent(_pytest.main.Session)
|
||||||
|
else:
|
||||||
|
assert_never(scope)
|
||||||
|
|
||||||
|
|
||||||
|
# Used for storing artificial fixturedefs for direct parametrization.
|
||||||
|
name2pseudofixturedef_key = StoreKey[Dict[str, "FixtureDef[Any]"]]()
|
||||||
|
|
||||||
|
|
||||||
def add_funcarg_pseudo_fixture_def(
|
def add_funcarg_pseudo_fixture_def(
|
||||||
collector, metafunc: "Metafunc", fixturemanager: "FixtureManager"
|
collector: nodes.Collector, metafunc: "Metafunc", fixturemanager: "FixtureManager"
|
||||||
) -> None:
|
) -> None:
|
||||||
# This function will transform all collected calls to functions
|
# This function will transform all collected calls to functions
|
||||||
# if they use direct funcargs (i.e. direct parametrization)
|
# if they use direct funcargs (i.e. direct parametrization)
|
||||||
|
@ -186,8 +190,15 @@ def add_funcarg_pseudo_fixture_def(
|
||||||
assert scope == "class" and isinstance(collector, _pytest.python.Module)
|
assert scope == "class" and isinstance(collector, _pytest.python.Module)
|
||||||
# Use module-level collector for class-scope (for now).
|
# Use module-level collector for class-scope (for now).
|
||||||
node = collector
|
node = collector
|
||||||
if node and argname in node._name2pseudofixturedef:
|
if node is None:
|
||||||
arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]]
|
name2pseudofixturedef = None
|
||||||
|
else:
|
||||||
|
default: Dict[str, FixtureDef[Any]] = {}
|
||||||
|
name2pseudofixturedef = node._store.setdefault(
|
||||||
|
name2pseudofixturedef_key, default
|
||||||
|
)
|
||||||
|
if name2pseudofixturedef is not None and argname in name2pseudofixturedef:
|
||||||
|
arg2fixturedefs[argname] = [name2pseudofixturedef[argname]]
|
||||||
else:
|
else:
|
||||||
fixturedef = FixtureDef(
|
fixturedef = FixtureDef(
|
||||||
fixturemanager=fixturemanager,
|
fixturemanager=fixturemanager,
|
||||||
|
@ -200,8 +211,8 @@ def add_funcarg_pseudo_fixture_def(
|
||||||
ids=None,
|
ids=None,
|
||||||
)
|
)
|
||||||
arg2fixturedefs[argname] = [fixturedef]
|
arg2fixturedefs[argname] = [fixturedef]
|
||||||
if node is not None:
|
if name2pseudofixturedef is not None:
|
||||||
node._name2pseudofixturedef[argname] = fixturedef
|
name2pseudofixturedef[argname] = fixturedef
|
||||||
|
|
||||||
|
|
||||||
def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]:
|
def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]:
|
||||||
|
@ -222,7 +233,7 @@ def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]:
|
||||||
_Key = Tuple[object, ...]
|
_Key = Tuple[object, ...]
|
||||||
|
|
||||||
|
|
||||||
def get_parametrized_fixture_keys(item: "nodes.Item", scopenum: int) -> Iterator[_Key]:
|
def get_parametrized_fixture_keys(item: nodes.Item, scopenum: int) -> Iterator[_Key]:
|
||||||
"""Return list of keys for all parametrized arguments which match
|
"""Return list of keys for all parametrized arguments which match
|
||||||
the specified scope. """
|
the specified scope. """
|
||||||
assert scopenum < scopenum_function # function
|
assert scopenum < scopenum_function # function
|
||||||
|
@ -256,7 +267,7 @@ def get_parametrized_fixture_keys(item: "nodes.Item", scopenum: int) -> Iterator
|
||||||
# setups and teardowns.
|
# setups and teardowns.
|
||||||
|
|
||||||
|
|
||||||
def reorder_items(items: "Sequence[nodes.Item]") -> "List[nodes.Item]":
|
def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]:
|
||||||
argkeys_cache = {} # type: Dict[int, Dict[nodes.Item, Dict[_Key, None]]]
|
argkeys_cache = {} # type: Dict[int, Dict[nodes.Item, Dict[_Key, None]]]
|
||||||
items_by_argkey = {} # type: Dict[int, Dict[_Key, Deque[nodes.Item]]]
|
items_by_argkey = {} # type: Dict[int, Dict[_Key, Deque[nodes.Item]]]
|
||||||
for scopenum in range(0, scopenum_function):
|
for scopenum in range(0, scopenum_function):
|
||||||
|
@ -278,15 +289,15 @@ def reorder_items(items: "Sequence[nodes.Item]") -> "List[nodes.Item]":
|
||||||
item_d[key].append(item)
|
item_d[key].append(item)
|
||||||
# cast is a workaround for https://github.com/python/typeshed/issues/3800.
|
# cast is a workaround for https://github.com/python/typeshed/issues/3800.
|
||||||
items_dict = cast(
|
items_dict = cast(
|
||||||
"Dict[nodes.Item, None]", order_preserving_dict.fromkeys(items, None)
|
Dict[nodes.Item, None], order_preserving_dict.fromkeys(items, None)
|
||||||
)
|
)
|
||||||
return list(reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, 0))
|
return list(reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, 0))
|
||||||
|
|
||||||
|
|
||||||
def fix_cache_order(
|
def fix_cache_order(
|
||||||
item: "nodes.Item",
|
item: nodes.Item,
|
||||||
argkeys_cache: "Dict[int, Dict[nodes.Item, Dict[_Key, None]]]",
|
argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]],
|
||||||
items_by_argkey: "Dict[int, Dict[_Key, Deque[nodes.Item]]]",
|
items_by_argkey: Dict[int, Dict[_Key, "Deque[nodes.Item]"]],
|
||||||
) -> None:
|
) -> None:
|
||||||
for scopenum in range(0, scopenum_function):
|
for scopenum in range(0, scopenum_function):
|
||||||
for key in argkeys_cache[scopenum].get(item, []):
|
for key in argkeys_cache[scopenum].get(item, []):
|
||||||
|
@ -294,11 +305,11 @@ def fix_cache_order(
|
||||||
|
|
||||||
|
|
||||||
def reorder_items_atscope(
|
def reorder_items_atscope(
|
||||||
items: "Dict[nodes.Item, None]",
|
items: Dict[nodes.Item, None],
|
||||||
argkeys_cache: "Dict[int, Dict[nodes.Item, Dict[_Key, None]]]",
|
argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]],
|
||||||
items_by_argkey: "Dict[int, Dict[_Key, Deque[nodes.Item]]]",
|
items_by_argkey: Dict[int, Dict[_Key, "Deque[nodes.Item]"]],
|
||||||
scopenum: int,
|
scopenum: int,
|
||||||
) -> "Dict[nodes.Item, None]":
|
) -> Dict[nodes.Item, None]:
|
||||||
if scopenum >= scopenum_function or len(items) < 3:
|
if scopenum >= scopenum_function or len(items) < 3:
|
||||||
return items
|
return items
|
||||||
ignore = set() # type: Set[Optional[_Key]]
|
ignore = set() # type: Set[Optional[_Key]]
|
||||||
|
@ -519,9 +530,9 @@ class FixtureRequest:
|
||||||
return self.node.keywords
|
return self.node.keywords
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def session(self):
|
def session(self) -> "Session":
|
||||||
"""Pytest session object."""
|
"""Pytest session object."""
|
||||||
return self._pyfuncitem.session
|
return self._pyfuncitem.session # type: ignore[no-any-return]
|
||||||
|
|
||||||
def addfinalizer(self, finalizer: Callable[[], object]) -> None:
|
def addfinalizer(self, finalizer: Callable[[], object]) -> None:
|
||||||
"""Add finalizer/teardown function to be called after the last test
|
"""Add finalizer/teardown function to be called after the last test
|
||||||
|
@ -535,7 +546,7 @@ class FixtureRequest:
|
||||||
finalizer=finalizer, colitem=colitem
|
finalizer=finalizer, colitem=colitem
|
||||||
)
|
)
|
||||||
|
|
||||||
def applymarker(self, marker) -> None:
|
def applymarker(self, marker: Union[str, MarkDecorator]) -> None:
|
||||||
"""Apply a marker to a single test function invocation.
|
"""Apply a marker to a single test function invocation.
|
||||||
|
|
||||||
This method is useful if you don't want to have a keyword/marker
|
This method is useful if you don't want to have a keyword/marker
|
||||||
|
@ -685,7 +696,9 @@ class FixtureRequest:
|
||||||
functools.partial(fixturedef.finish, request=subrequest), subrequest.node
|
functools.partial(fixturedef.finish, request=subrequest), subrequest.node
|
||||||
)
|
)
|
||||||
|
|
||||||
def _check_scope(self, argname, invoking_scope: "_Scope", requested_scope) -> None:
|
def _check_scope(
|
||||||
|
self, argname: str, invoking_scope: "_Scope", requested_scope: "_Scope",
|
||||||
|
) -> None:
|
||||||
if argname == "request":
|
if argname == "request":
|
||||||
return
|
return
|
||||||
if scopemismatch(invoking_scope, requested_scope):
|
if scopemismatch(invoking_scope, requested_scope):
|
||||||
|
@ -709,11 +722,11 @@ class FixtureRequest:
|
||||||
lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args))
|
lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args))
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _getscopeitem(self, scope):
|
def _getscopeitem(self, scope: "_Scope") -> Union[nodes.Item, nodes.Collector]:
|
||||||
if scope == "function":
|
if scope == "function":
|
||||||
# This might also be a non-function Item despite its attribute name.
|
# This might also be a non-function Item despite its attribute name.
|
||||||
return self._pyfuncitem
|
node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem
|
||||||
if scope == "package":
|
elif scope == "package":
|
||||||
# FIXME: _fixturedef is not defined on FixtureRequest (this class),
|
# FIXME: _fixturedef is not defined on FixtureRequest (this class),
|
||||||
# but on FixtureRequest (a subclass).
|
# but on FixtureRequest (a subclass).
|
||||||
node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined]
|
node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined]
|
||||||
|
@ -962,7 +975,7 @@ class FixtureDef(Generic[_FixtureValue]):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
fixturemanager: "FixtureManager",
|
fixturemanager: "FixtureManager",
|
||||||
baseid,
|
baseid: Optional[str],
|
||||||
argname: str,
|
argname: str,
|
||||||
func: "_FixtureFunc[_FixtureValue]",
|
func: "_FixtureFunc[_FixtureValue]",
|
||||||
scope: "Union[_Scope, Callable[[str, Config], _Scope]]",
|
scope: "Union[_Scope, Callable[[str, Config], _Scope]]",
|
||||||
|
@ -1144,7 +1157,9 @@ def _params_converter(
|
||||||
return tuple(params) if params is not None else None
|
return tuple(params) if params is not None else None
|
||||||
|
|
||||||
|
|
||||||
def wrap_function_to_error_out_if_called_directly(function, fixture_marker):
|
def wrap_function_to_error_out_if_called_directly(
|
||||||
|
function: _FixtureFunction, fixture_marker: "FixtureFunctionMarker",
|
||||||
|
) -> _FixtureFunction:
|
||||||
"""Wrap the given fixture function so we can raise an error about it being called directly,
|
"""Wrap the given fixture function so we can raise an error about it being called directly,
|
||||||
instead of used as an argument in a test function."""
|
instead of used as an argument in a test function."""
|
||||||
message = (
|
message = (
|
||||||
|
@ -1162,7 +1177,7 @@ def wrap_function_to_error_out_if_called_directly(function, fixture_marker):
|
||||||
# further than this point and lose useful wrappings like @mock.patch (#3774).
|
# further than this point and lose useful wrappings like @mock.patch (#3774).
|
||||||
result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined]
|
result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined]
|
||||||
|
|
||||||
return result
|
return cast(_FixtureFunction, result)
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
|
@ -1410,7 +1425,7 @@ class FixtureManager:
|
||||||
] # type: List[Tuple[str, List[str]]]
|
] # type: List[Tuple[str, List[str]]]
|
||||||
session.config.pluginmanager.register(self, "funcmanage")
|
session.config.pluginmanager.register(self, "funcmanage")
|
||||||
|
|
||||||
def _get_direct_parametrize_args(self, node: "nodes.Node") -> List[str]:
|
def _get_direct_parametrize_args(self, node: nodes.Node) -> List[str]:
|
||||||
"""Return all direct parametrization arguments of a node, so we don't
|
"""Return all direct parametrization arguments of a node, so we don't
|
||||||
mistake them for fixtures.
|
mistake them for fixtures.
|
||||||
|
|
||||||
|
@ -1430,7 +1445,7 @@ class FixtureManager:
|
||||||
return parametrize_argnames
|
return parametrize_argnames
|
||||||
|
|
||||||
def getfixtureinfo(
|
def getfixtureinfo(
|
||||||
self, node: "nodes.Node", func, cls, funcargs: bool = True
|
self, node: nodes.Node, func, cls, funcargs: bool = True
|
||||||
) -> FuncFixtureInfo:
|
) -> FuncFixtureInfo:
|
||||||
if funcargs and not getattr(node, "nofuncargs", False):
|
if funcargs and not getattr(node, "nofuncargs", False):
|
||||||
argnames = getfuncargnames(func, name=node.name, cls=cls)
|
argnames = getfuncargnames(func, name=node.name, cls=cls)
|
||||||
|
@ -1454,8 +1469,6 @@ class FixtureManager:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
from _pytest import nodes
|
|
||||||
|
|
||||||
# Construct the base nodeid which is later used to check
|
# Construct the base nodeid which is later used to check
|
||||||
# what fixtures are visible for particular tests (as denoted
|
# what fixtures are visible for particular tests (as denoted
|
||||||
# by their test id).
|
# by their test id).
|
||||||
|
@ -1485,7 +1498,10 @@ class FixtureManager:
|
||||||
return autousenames
|
return autousenames
|
||||||
|
|
||||||
def getfixtureclosure(
|
def getfixtureclosure(
|
||||||
self, fixturenames: Tuple[str, ...], parentnode, ignore_args: Sequence[str] = ()
|
self,
|
||||||
|
fixturenames: Tuple[str, ...],
|
||||||
|
parentnode: nodes.Node,
|
||||||
|
ignore_args: Sequence[str] = (),
|
||||||
) -> Tuple[Tuple[str, ...], List[str], Dict[str, Sequence[FixtureDef[Any]]]]:
|
) -> Tuple[Tuple[str, ...], List[str], Dict[str, Sequence[FixtureDef[Any]]]]:
|
||||||
# Collect the closure of all fixtures, starting with the given
|
# Collect the closure of all fixtures, starting with the given
|
||||||
# fixturenames as the initial set. As we have to visit all
|
# fixturenames as the initial set. As we have to visit all
|
||||||
|
@ -1579,7 +1595,7 @@ class FixtureManager:
|
||||||
|
|
||||||
# Try next super fixture, if any.
|
# Try next super fixture, if any.
|
||||||
|
|
||||||
def pytest_collection_modifyitems(self, items: "List[nodes.Item]") -> None:
|
def pytest_collection_modifyitems(self, items: List[nodes.Item]) -> None:
|
||||||
# Separate parametrized setups.
|
# Separate parametrized setups.
|
||||||
items[:] = reorder_items(items)
|
items[:] = reorder_items(items)
|
||||||
|
|
||||||
|
@ -1660,8 +1676,6 @@ class FixtureManager:
|
||||||
def _matchfactories(
|
def _matchfactories(
|
||||||
self, fixturedefs: Iterable[FixtureDef[Any]], nodeid: str
|
self, fixturedefs: Iterable[FixtureDef[Any]], nodeid: str
|
||||||
) -> Iterator[FixtureDef[Any]]:
|
) -> Iterator[FixtureDef[Any]]:
|
||||||
from _pytest import nodes
|
|
||||||
|
|
||||||
for fixturedef in fixturedefs:
|
for fixturedef in fixturedefs:
|
||||||
if nodes.ischildnode(fixturedef.baseid, nodeid):
|
if nodes.ischildnode(fixturedef.baseid, nodeid):
|
||||||
yield fixturedef
|
yield fixturedef
|
||||||
|
|
|
@ -2,9 +2,7 @@ import os
|
||||||
import warnings
|
import warnings
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -27,8 +25,6 @@ from _pytest.compat import cached_property
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ConftestImportFailure
|
from _pytest.config import ConftestImportFailure
|
||||||
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
|
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
|
||||||
from _pytest.fixtures import FixtureDef
|
|
||||||
from _pytest.fixtures import FixtureLookupError
|
|
||||||
from _pytest.mark.structures import Mark
|
from _pytest.mark.structures import Mark
|
||||||
from _pytest.mark.structures import MarkDecorator
|
from _pytest.mark.structures import MarkDecorator
|
||||||
from _pytest.mark.structures import NodeKeywords
|
from _pytest.mark.structures import NodeKeywords
|
||||||
|
@ -170,9 +166,6 @@ class Node(metaclass=NodeMeta):
|
||||||
#: Allow adding of extra keywords to use for matching.
|
#: Allow adding of extra keywords to use for matching.
|
||||||
self.extra_keyword_matches = set() # type: Set[str]
|
self.extra_keyword_matches = set() # type: Set[str]
|
||||||
|
|
||||||
# Used for storing artificial fixturedefs for direct parametrization.
|
|
||||||
self._name2pseudofixturedef = {} # type: Dict[str, FixtureDef[Any]]
|
|
||||||
|
|
||||||
if nodeid is not None:
|
if nodeid is not None:
|
||||||
assert "::()" not in nodeid
|
assert "::()" not in nodeid
|
||||||
self._nodeid = nodeid
|
self._nodeid = nodeid
|
||||||
|
@ -366,6 +359,8 @@ class Node(metaclass=NodeMeta):
|
||||||
excinfo: ExceptionInfo[BaseException],
|
excinfo: ExceptionInfo[BaseException],
|
||||||
style: "Optional[_TracebackStyle]" = None,
|
style: "Optional[_TracebackStyle]" = None,
|
||||||
) -> TerminalRepr:
|
) -> TerminalRepr:
|
||||||
|
from _pytest.fixtures import FixtureLookupError
|
||||||
|
|
||||||
if isinstance(excinfo.value, ConftestImportFailure):
|
if isinstance(excinfo.value, ConftestImportFailure):
|
||||||
excinfo = ExceptionInfo(excinfo.value.excinfo)
|
excinfo = ExceptionInfo(excinfo.value.excinfo)
|
||||||
if isinstance(excinfo.value, fail.Exception):
|
if isinstance(excinfo.value, fail.Exception):
|
||||||
|
|
|
@ -1059,7 +1059,7 @@ class TestRequestMarking:
|
||||||
req1.applymarker(pytest.mark.skipif)
|
req1.applymarker(pytest.mark.skipif)
|
||||||
assert "skipif" in item1.keywords
|
assert "skipif" in item1.keywords
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
req1.applymarker(42)
|
req1.applymarker(42) # type: ignore[arg-type]
|
||||||
|
|
||||||
def test_accesskeywords(self, testdir):
|
def test_accesskeywords(self, testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
|
|
Loading…
Reference in New Issue