Merge 260b5a7614
into f426c0b35a
This commit is contained in:
commit
42f7713bff
1
AUTHORS
1
AUTHORS
|
@ -376,6 +376,7 @@ Serhii Mozghovyi
|
||||||
Seth Junot
|
Seth Junot
|
||||||
Shantanu Jain
|
Shantanu Jain
|
||||||
Sharad Nair
|
Sharad Nair
|
||||||
|
Shaygan Hooshyari
|
||||||
Shubham Adep
|
Shubham Adep
|
||||||
Simon Blanchard
|
Simon Blanchard
|
||||||
Simon Gomizelj
|
Simon Gomizelj
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
The fixtures are now represented as fixture in test output.
|
||||||
|
|
||||||
|
-- by :user:`the-compiler` and :user:`glyphack`.
|
|
@ -190,6 +190,7 @@ nitpick_ignore = [
|
||||||
("py:class", "TerminalReporter"),
|
("py:class", "TerminalReporter"),
|
||||||
("py:class", "_pytest._code.code.TerminalRepr"),
|
("py:class", "_pytest._code.code.TerminalRepr"),
|
||||||
("py:class", "_pytest.fixtures.FixtureFunctionMarker"),
|
("py:class", "_pytest.fixtures.FixtureFunctionMarker"),
|
||||||
|
("py:class", "_pytest.fixtures.FixtureFunctionDefinition"),
|
||||||
("py:class", "_pytest.logging.LogCaptureHandler"),
|
("py:class", "_pytest.logging.LogCaptureHandler"),
|
||||||
("py:class", "_pytest.mark.structures.ParameterSet"),
|
("py:class", "_pytest.mark.structures.ParameterSet"),
|
||||||
# Intentionally undocumented/private
|
# Intentionally undocumented/private
|
||||||
|
|
|
@ -35,6 +35,7 @@ from _pytest._io.saferepr import saferepr
|
||||||
from _pytest._version import version
|
from _pytest._version import version
|
||||||
from _pytest.assertion import util
|
from _pytest.assertion import util
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
|
from _pytest.fixtures import FixtureFunctionDefinition
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
from _pytest.pathlib import absolutepath
|
from _pytest.pathlib import absolutepath
|
||||||
from _pytest.pathlib import fnmatch_ex
|
from _pytest.pathlib import fnmatch_ex
|
||||||
|
@ -462,7 +463,7 @@ def _format_assertmsg(obj: object) -> str:
|
||||||
|
|
||||||
def _should_repr_global_name(obj: object) -> bool:
|
def _should_repr_global_name(obj: object) -> bool:
|
||||||
if callable(obj):
|
if callable(obj):
|
||||||
return False
|
return isinstance(obj, FixtureFunctionDefinition)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return not hasattr(obj, "__name__")
|
return not hasattr(obj, "__name__")
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
|
||||||
import enum
|
import enum
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -210,29 +209,15 @@ def ascii_escaped(val: bytes | str) -> str:
|
||||||
return ret.translate(_non_printable_ascii_translate_table)
|
return ret.translate(_non_printable_ascii_translate_table)
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
|
||||||
class _PytestWrapper:
|
|
||||||
"""Dummy wrapper around a function object for internal use only.
|
|
||||||
|
|
||||||
Used to correctly unwrap the underlying function object when we are
|
|
||||||
creating fixtures, because we wrap the function object ourselves with a
|
|
||||||
decorator to issue warnings when the fixture function is called directly.
|
|
||||||
"""
|
|
||||||
|
|
||||||
obj: Any
|
|
||||||
|
|
||||||
|
|
||||||
def get_real_func(obj):
|
def get_real_func(obj):
|
||||||
"""Get the real function object of the (possibly) wrapped object by
|
"""Get the real function object of the (possibly) wrapped object by
|
||||||
functools.wraps or functools.partial."""
|
functools.wraps or functools.partial or pytest.fixture"""
|
||||||
|
from _pytest.fixtures import FixtureFunctionDefinition
|
||||||
|
|
||||||
start_obj = obj
|
start_obj = obj
|
||||||
for i in range(100):
|
for _ in range(100):
|
||||||
# __pytest_wrapped__ is set by @pytest.fixture when wrapping the fixture function
|
if isinstance(obj, FixtureFunctionDefinition):
|
||||||
# to trigger a warning if it gets called directly instead of by pytest: we don't
|
obj = obj._get_wrapped_function()
|
||||||
# want to unwrap further than this otherwise we lose useful wrappings like @mock.patch (#3774)
|
|
||||||
new_obj = getattr(obj, "__pytest_wrapped__", None)
|
|
||||||
if isinstance(new_obj, _PytestWrapper):
|
|
||||||
obj = new_obj.obj
|
|
||||||
break
|
break
|
||||||
new_obj = getattr(obj, "__wrapped__", None)
|
new_obj = getattr(obj, "__wrapped__", None)
|
||||||
if new_obj is None:
|
if new_obj is None:
|
||||||
|
@ -249,20 +234,6 @@ def get_real_func(obj):
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
def get_real_method(obj, holder):
|
|
||||||
"""Attempt to obtain the real function object that might be wrapping
|
|
||||||
``obj``, while at the same time returning a bound method to ``holder`` if
|
|
||||||
the original object was a bound method."""
|
|
||||||
try:
|
|
||||||
is_method = hasattr(obj, "__func__")
|
|
||||||
obj = get_real_func(obj)
|
|
||||||
except Exception: # pragma: no cover
|
|
||||||
return obj
|
|
||||||
if is_method and hasattr(obj, "__get__") and callable(obj.__get__):
|
|
||||||
obj = obj.__get__(holder)
|
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
def getimfunc(func):
|
def getimfunc(func):
|
||||||
try:
|
try:
|
||||||
return func.__func__
|
return func.__func__
|
||||||
|
|
|
@ -42,10 +42,8 @@ from _pytest._code import Source
|
||||||
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 _PytestWrapper
|
|
||||||
from _pytest.compat import assert_never
|
from _pytest.compat import assert_never
|
||||||
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 getfuncargnames
|
from _pytest.compat import getfuncargnames
|
||||||
from _pytest.compat import getimfunc
|
from _pytest.compat import getimfunc
|
||||||
from _pytest.compat import getlocation
|
from _pytest.compat import getlocation
|
||||||
|
@ -153,12 +151,10 @@ def get_scope_node(node: nodes.Node, scope: Scope) -> Optional[nodes.Node]:
|
||||||
|
|
||||||
|
|
||||||
def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]:
|
def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]:
|
||||||
"""Return fixturemarker or None if it doesn't exist or raised
|
"""Return fixturemarker or None if it doesn't exist"""
|
||||||
exceptions."""
|
if isinstance(obj, FixtureFunctionDefinition):
|
||||||
return cast(
|
return obj._fixture_function_marker
|
||||||
Optional[FixtureFunctionMarker],
|
return None
|
||||||
safe_getattr(obj, "_pytestfixturefunction", None),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Algorithm for sorting on a per-parametrized resource setup basis.
|
# Algorithm for sorting on a per-parametrized resource setup basis.
|
||||||
|
@ -1145,31 +1141,6 @@ def pytest_fixture_setup(
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
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,
|
|
||||||
instead of used as an argument in a test function."""
|
|
||||||
name = fixture_marker.name or function.__name__
|
|
||||||
message = (
|
|
||||||
f'Fixture "{name}" called directly. Fixtures are not meant to be called directly,\n'
|
|
||||||
"but are created automatically when test functions request them as parameters.\n"
|
|
||||||
"See https://docs.pytest.org/en/stable/explanation/fixtures.html for more information about fixtures, and\n"
|
|
||||||
"https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code."
|
|
||||||
)
|
|
||||||
|
|
||||||
@functools.wraps(function)
|
|
||||||
def result(*args, **kwargs):
|
|
||||||
fail(message, pytrace=False)
|
|
||||||
|
|
||||||
# Keep reference to the original function in our own custom attribute so we don't unwrap
|
|
||||||
# further than this point and lose useful wrappings like @mock.patch (#3774).
|
|
||||||
result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined]
|
|
||||||
|
|
||||||
return cast(FixtureFunction, result)
|
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class FixtureFunctionMarker:
|
class FixtureFunctionMarker:
|
||||||
|
@ -1186,11 +1157,11 @@ class FixtureFunctionMarker:
|
||||||
def __post_init__(self, _ispytest: bool) -> None:
|
def __post_init__(self, _ispytest: bool) -> None:
|
||||||
check_ispytest(_ispytest)
|
check_ispytest(_ispytest)
|
||||||
|
|
||||||
def __call__(self, function: FixtureFunction) -> FixtureFunction:
|
def __call__(self, function: FixtureFunction) -> "FixtureFunctionDefinition":
|
||||||
if inspect.isclass(function):
|
if inspect.isclass(function):
|
||||||
raise ValueError("class fixtures not supported (maybe in the future)")
|
raise ValueError("class fixtures not supported (maybe in the future)")
|
||||||
|
|
||||||
if getattr(function, "_pytestfixturefunction", False):
|
if isinstance(function, FixtureFunctionDefinition):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"@pytest.fixture is being applied more than once to the same function {function.__name__!r}"
|
f"@pytest.fixture is being applied more than once to the same function {function.__name__!r}"
|
||||||
)
|
)
|
||||||
|
@ -1198,7 +1169,7 @@ class FixtureFunctionMarker:
|
||||||
if hasattr(function, "pytestmark"):
|
if hasattr(function, "pytestmark"):
|
||||||
warnings.warn(MARKED_FIXTURE, stacklevel=2)
|
warnings.warn(MARKED_FIXTURE, stacklevel=2)
|
||||||
|
|
||||||
function = wrap_function_to_error_out_if_called_directly(function, self)
|
fixture_definition = FixtureFunctionDefinition(function, self)
|
||||||
|
|
||||||
name = self.name or function.__name__
|
name = self.name or function.__name__
|
||||||
if name == "request":
|
if name == "request":
|
||||||
|
@ -1208,14 +1179,50 @@ class FixtureFunctionMarker:
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Type ignored because https://github.com/python/mypy/issues/2087.
|
return fixture_definition
|
||||||
function._pytestfixturefunction = self # type: ignore[attr-defined]
|
|
||||||
return function
|
|
||||||
|
class FixtureFunctionDefinition:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
function: Callable[..., Any],
|
||||||
|
fixture_function_marker: FixtureFunctionMarker,
|
||||||
|
instance: Optional[type] = None,
|
||||||
|
):
|
||||||
|
self.name = fixture_function_marker.name or function.__name__
|
||||||
|
self.__name__ = self.name
|
||||||
|
self._fixture_function_marker = fixture_function_marker
|
||||||
|
self._fixture_function = function
|
||||||
|
self._instance = instance
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"pytest_fixture({self._fixture_function})"
|
||||||
|
|
||||||
|
def __get__(self, instance, owner=None):
|
||||||
|
return FixtureFunctionDefinition(
|
||||||
|
self._fixture_function, self._fixture_function_marker, instance
|
||||||
|
)
|
||||||
|
|
||||||
|
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
||||||
|
message = (
|
||||||
|
f'Fixture "{self.name}" called directly. Fixtures are not meant to be called directly,\n'
|
||||||
|
"but are created automatically when test functions request them as parameters.\n"
|
||||||
|
"See https://docs.pytest.org/en/stable/explanation/fixtures.html for more information about fixtures, and\n"
|
||||||
|
"https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly"
|
||||||
|
)
|
||||||
|
fail(message, pytrace=False)
|
||||||
|
|
||||||
|
def _get_wrapped_function(self) -> Callable[..., Any]:
|
||||||
|
if self._instance is not None:
|
||||||
|
return cast(
|
||||||
|
Callable[..., Any], self._fixture_function.__get__(self._instance)
|
||||||
|
)
|
||||||
|
return self._fixture_function
|
||||||
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def fixture(
|
def fixture(
|
||||||
fixture_function: FixtureFunction,
|
fixture_function: Callable[..., object],
|
||||||
*,
|
*,
|
||||||
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ...,
|
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ...,
|
||||||
params: Optional[Iterable[object]] = ...,
|
params: Optional[Iterable[object]] = ...,
|
||||||
|
@ -1224,7 +1231,7 @@ def fixture(
|
||||||
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
|
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
|
||||||
] = ...,
|
] = ...,
|
||||||
name: Optional[str] = ...,
|
name: Optional[str] = ...,
|
||||||
) -> FixtureFunction: ...
|
) -> FixtureFunctionDefinition: ...
|
||||||
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
|
@ -1238,7 +1245,7 @@ def fixture(
|
||||||
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
|
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
|
||||||
] = ...,
|
] = ...,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
) -> FixtureFunctionMarker: ...
|
) -> FixtureFunctionDefinition: ...
|
||||||
|
|
||||||
|
|
||||||
def fixture(
|
def fixture(
|
||||||
|
@ -1251,7 +1258,7 @@ def fixture(
|
||||||
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
|
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
|
||||||
] = None,
|
] = None,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
) -> Union[FixtureFunctionMarker, FixtureFunction]:
|
) -> Union[FixtureFunctionMarker, FixtureFunctionDefinition]:
|
||||||
"""Decorator to mark a fixture factory function.
|
"""Decorator to mark a fixture factory function.
|
||||||
|
|
||||||
This decorator can be used, with or without parameters, to define a
|
This decorator can be used, with or without parameters, to define a
|
||||||
|
@ -1321,7 +1328,7 @@ def fixture(
|
||||||
def yield_fixture(
|
def yield_fixture(
|
||||||
fixture_function=None,
|
fixture_function=None,
|
||||||
*args,
|
*args,
|
||||||
scope="function",
|
scope: _ScopeName = "function",
|
||||||
params=None,
|
params=None,
|
||||||
autouse=False,
|
autouse=False,
|
||||||
ids=None,
|
ids=None,
|
||||||
|
@ -1734,33 +1741,21 @@ class FixtureManager:
|
||||||
|
|
||||||
self._holderobjseen.add(holderobj)
|
self._holderobjseen.add(holderobj)
|
||||||
for name in dir(holderobj):
|
for name in dir(holderobj):
|
||||||
# The attribute can be an arbitrary descriptor, so the attribute
|
|
||||||
# access below can raise. safe_getatt() ignores such exceptions.
|
|
||||||
obj = safe_getattr(holderobj, name, None)
|
obj = safe_getattr(holderobj, name, None)
|
||||||
marker = getfixturemarker(obj)
|
if type(obj) is FixtureFunctionDefinition:
|
||||||
if not isinstance(marker, FixtureFunctionMarker):
|
marker = obj._fixture_function_marker
|
||||||
# Magic globals with __getattr__ might have got us a wrong
|
if marker.name:
|
||||||
# fixture attribute.
|
name = marker.name
|
||||||
continue
|
func = obj._get_wrapped_function()
|
||||||
|
self._register_fixture(
|
||||||
if marker.name:
|
name=name,
|
||||||
name = marker.name
|
nodeid=nodeid,
|
||||||
|
func=func,
|
||||||
# During fixture definition we wrap the original fixture function
|
scope=marker.scope,
|
||||||
# to issue a warning if called directly, so here we unwrap it in
|
params=marker.params,
|
||||||
# order to not emit the warning when pytest itself calls the
|
ids=marker.ids,
|
||||||
# fixture function.
|
autouse=marker.autouse,
|
||||||
func = get_real_method(obj, holderobj)
|
)
|
||||||
|
|
||||||
self._register_fixture(
|
|
||||||
name=name,
|
|
||||||
nodeid=nodeid,
|
|
||||||
func=func,
|
|
||||||
scope=marker.scope,
|
|
||||||
params=marker.params,
|
|
||||||
ids=marker.ids,
|
|
||||||
autouse=marker.autouse,
|
|
||||||
)
|
|
||||||
|
|
||||||
def getfixturedefs(
|
def getfixturedefs(
|
||||||
self, argname: str, node: nodes.Node
|
self, argname: str, node: nodes.Node
|
||||||
|
|
|
@ -478,12 +478,13 @@ def test_source_with_decorator() -> None:
|
||||||
def deco_fixture():
|
def deco_fixture():
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
src = inspect.getsource(deco_fixture)
|
# Since deco_fixture is now an instance of FixtureFunctionDef the getsource function will not work on it.
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
inspect.getsource(deco_fixture)
|
||||||
|
src = inspect.getsource(deco_fixture._get_wrapped_function())
|
||||||
assert src == " @pytest.fixture\n def deco_fixture():\n assert False\n"
|
assert src == " @pytest.fixture\n def deco_fixture():\n assert False\n"
|
||||||
# currently Source does not unwrap decorators, testing the
|
# Make sure the decorator is not a wrapped function
|
||||||
# existing behavior here for explicitness, but perhaps we should revisit/change this
|
assert not str(Source(deco_fixture)).startswith("@functools.wraps(function)")
|
||||||
# in the future
|
|
||||||
assert str(Source(deco_fixture)).startswith("@functools.wraps(function)")
|
|
||||||
assert (
|
assert (
|
||||||
textwrap.indent(str(Source(get_real_func(deco_fixture))), " ") + "\n" == src
|
textwrap.indent(str(Source(get_real_func(deco_fixture))), " ") + "\n" == src
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# mypy: allow-untyped-defs
|
# mypy: allow-untyped-defs
|
||||||
|
import inspect
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sys
|
import sys
|
||||||
|
@ -3295,6 +3296,33 @@ class TestFixtureMarker:
|
||||||
assert output1 == output2
|
assert output1 == output2
|
||||||
|
|
||||||
|
|
||||||
|
class FixtureFunctionDefTestClass:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.i = 10
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fixture_function_def_test_method(self):
|
||||||
|
return self.i
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fixture_function_def_test_func():
|
||||||
|
return 9
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_wrapped_func_returns_method():
|
||||||
|
obj = FixtureFunctionDefTestClass()
|
||||||
|
wrapped_function_result = (
|
||||||
|
obj.fixture_function_def_test_method._get_wrapped_function()
|
||||||
|
)
|
||||||
|
assert inspect.ismethod(wrapped_function_result)
|
||||||
|
assert wrapped_function_result() == 10
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_wrapped_func_returns_function():
|
||||||
|
assert fixture_function_def_test_func._get_wrapped_function()() == 9
|
||||||
|
|
||||||
|
|
||||||
class TestRequestScopeAccess:
|
class TestRequestScopeAccess:
|
||||||
pytestmark = pytest.mark.parametrize(
|
pytestmark = pytest.mark.parametrize(
|
||||||
("scope", "ok", "error"),
|
("scope", "ok", "error"),
|
||||||
|
@ -4465,6 +4493,21 @@ def test_fixture_double_decorator(pytester: Pytester) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_fixture_class(pytester: Pytester) -> None:
|
||||||
|
"""Check if an error is raised when using @pytest.fixture on a class."""
|
||||||
|
pytester.makepyfile(
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
class A:
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest()
|
||||||
|
result.assert_outcomes(errors=1)
|
||||||
|
|
||||||
|
|
||||||
def test_fixture_param_shadowing(pytester: Pytester) -> None:
|
def test_fixture_param_shadowing(pytester: Pytester) -> None:
|
||||||
"""Parametrized arguments would be shadowed if a fixture with the same name also exists (#5036)"""
|
"""Parametrized arguments would be shadowed if a fixture with the same name also exists (#5036)"""
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
|
|
@ -744,6 +744,23 @@ class TestAssertionRewrite:
|
||||||
assert "UnicodeDecodeError" not in msg
|
assert "UnicodeDecodeError" not in msg
|
||||||
assert "UnicodeEncodeError" not in msg
|
assert "UnicodeEncodeError" not in msg
|
||||||
|
|
||||||
|
def test_assert_fixture(self, pytester: Pytester) -> None:
|
||||||
|
pytester.makepyfile(
|
||||||
|
"""\
|
||||||
|
import pytest
|
||||||
|
@pytest.fixture
|
||||||
|
def fixt():
|
||||||
|
return 42
|
||||||
|
|
||||||
|
def test_something(): # missing "fixt" argument
|
||||||
|
assert fixt == 42
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
["*assert pytest_fixture(<function fixt at *>) == 42*"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestRewriteOnImport:
|
class TestRewriteOnImport:
|
||||||
def test_pycache_is_a_file(self, pytester: Pytester) -> None:
|
def test_pycache_is_a_file(self, pytester: Pytester) -> None:
|
||||||
|
|
|
@ -1310,7 +1310,7 @@ def test_collect_handles_raising_on_dunder_class(pytester: Pytester) -> None:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = pytester.runpytest()
|
result = pytester.runpytest()
|
||||||
result.stdout.fnmatch_lines(["*1 passed in*"])
|
result.assert_outcomes(passed=1)
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -1374,7 +1374,7 @@ def test_collect_pyargs_with_testpaths(
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.chdir(root)
|
mp.chdir(root)
|
||||||
result = pytester.runpytest_subprocess()
|
result = pytester.runpytest_subprocess()
|
||||||
result.stdout.fnmatch_lines(["*1 passed in*"])
|
result.assert_outcomes(passed=1)
|
||||||
|
|
||||||
|
|
||||||
def test_initial_conftests_with_testpaths(pytester: Pytester) -> None:
|
def test_initial_conftests_with_testpaths(pytester: Pytester) -> None:
|
||||||
|
|
|
@ -7,7 +7,6 @@ import sys
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from _pytest.compat import _PytestWrapper
|
|
||||||
from _pytest.compat import assert_never
|
from _pytest.compat import assert_never
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
from _pytest.compat import is_generator
|
from _pytest.compat import is_generator
|
||||||
|
@ -52,8 +51,8 @@ def test_real_func_loop_limit() -> None:
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match=(
|
match=(
|
||||||
"could not find real function of <Evil left=800>\n"
|
"could not find real function of <Evil left=900>\n"
|
||||||
"stopped at <Evil left=800>"
|
"stopped at <Evil left=900>"
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
get_real_func(evil)
|
get_real_func(evil)
|
||||||
|
@ -78,10 +77,13 @@ def test_get_real_func() -> None:
|
||||||
wrapped_func2 = decorator(decorator(wrapped_func))
|
wrapped_func2 = decorator(decorator(wrapped_func))
|
||||||
assert get_real_func(wrapped_func2) is func
|
assert get_real_func(wrapped_func2) is func
|
||||||
|
|
||||||
# special case for __pytest_wrapped__ attribute: used to obtain the function up until the point
|
# obtain the function up until the point a function was wrapped by pytest itself
|
||||||
# a function was wrapped by pytest itself
|
@pytest.fixture
|
||||||
wrapped_func2.__pytest_wrapped__ = _PytestWrapper(wrapped_func)
|
def wrapped_func3():
|
||||||
assert get_real_func(wrapped_func2) is wrapped_func
|
pass # pragma: no cover
|
||||||
|
|
||||||
|
wrapped_func4 = decorator(wrapped_func3)
|
||||||
|
assert get_real_func(wrapped_func4) is wrapped_func3._get_wrapped_function()
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_func_partial() -> None:
|
def test_get_real_func_partial() -> None:
|
||||||
|
|
Loading…
Reference in New Issue