ENH: Figure out where to go
This commit is contained in:
parent
3efcff8bd1
commit
9733d57bed
|
@ -11,7 +11,10 @@ in case of warnings which need to format their messages.
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from pathlib import Path
|
||||
from warnings import warn
|
||||
from warnings import warn_explicit
|
||||
|
||||
from _pytest.warning_types import PytestDeprecationWarning
|
||||
from _pytest.warning_types import PytestRemovedIn9Warning
|
||||
|
@ -89,3 +92,25 @@ MARKED_FIXTURE = PytestRemovedIn9Warning(
|
|||
def check_ispytest(ispytest: bool) -> None:
|
||||
if not ispytest:
|
||||
warn(PRIVATE, stacklevel=3)
|
||||
|
||||
|
||||
def _warn_auto_stacklevel(message, category=UserWarning):
|
||||
"""Emit a warning with trace outside the pytest namespace."""
|
||||
root_dir = Path(__file__).parents[1]
|
||||
frame = inspect.currentframe()
|
||||
fname, lineno = "unknown", 0
|
||||
while frame:
|
||||
fname = frame.f_code.co_filename
|
||||
lineno = frame.f_lineno
|
||||
if fname and root_dir not in Path(fname).parents:
|
||||
break
|
||||
frame = frame.f_back
|
||||
del frame
|
||||
warn_explicit(
|
||||
message,
|
||||
category,
|
||||
filename=fname,
|
||||
lineno=lineno,
|
||||
module="pytest",
|
||||
registry=globals().get("__warningregistry__", {}),
|
||||
)
|
||||
|
|
|
@ -60,6 +60,7 @@ from _pytest.config.argparsing import Parser
|
|||
from _pytest.deprecated import check_ispytest
|
||||
from _pytest.deprecated import MARKED_FIXTURE
|
||||
from _pytest.deprecated import YIELD_FIXTURE
|
||||
from _pytest.deprecated import _warn_auto_stacklevel
|
||||
from _pytest.main import Session
|
||||
from _pytest.mark import Mark
|
||||
from _pytest.mark import ParameterSet
|
||||
|
@ -1192,7 +1193,7 @@ class FixtureFunctionMarker:
|
|||
)
|
||||
|
||||
if hasattr(function, "pytestmark"):
|
||||
warnings.warn(MARKED_FIXTURE, stacklevel=4)
|
||||
_warn_auto_stacklevel(MARKED_FIXTURE)
|
||||
|
||||
function = wrap_function_to_error_out_if_called_directly(function, self)
|
||||
|
||||
|
@ -1322,7 +1323,7 @@ def yield_fixture(
|
|||
.. deprecated:: 3.0
|
||||
Use :py:func:`pytest.fixture` directly instead.
|
||||
"""
|
||||
warnings.warn(YIELD_FIXTURE, stacklevel=2)
|
||||
_warn_auto_stacklevel(YIELD_FIXTURE)
|
||||
return fixture(
|
||||
fixture_function,
|
||||
*args,
|
||||
|
|
|
@ -18,7 +18,6 @@ from typing import Sequence
|
|||
from typing import TYPE_CHECKING
|
||||
from typing import TypeVar
|
||||
from typing import Union
|
||||
import warnings
|
||||
|
||||
from .._code import getfslineno
|
||||
from ..compat import ascii_escaped
|
||||
|
@ -27,6 +26,7 @@ from ..compat import NotSetType
|
|||
from _pytest.config import Config
|
||||
from _pytest.deprecated import check_ispytest
|
||||
from _pytest.deprecated import MARKED_FIXTURE
|
||||
from _pytest.deprecated import _warn_auto_stacklevel
|
||||
from _pytest.outcomes import fail
|
||||
from _pytest.scope import _ScopeName
|
||||
from _pytest.warning_types import PytestUnknownMarkWarning
|
||||
|
@ -353,7 +353,7 @@ class MarkDecorator:
|
|||
func = args[0]
|
||||
is_class = inspect.isclass(func)
|
||||
if len(args) == 1 and (istestfunc(func) or is_class):
|
||||
store_mark(func, self.mark, stacklevel=3)
|
||||
store_mark(func, self.mark)
|
||||
return func
|
||||
return self.with_args(*args, **kwargs)
|
||||
|
||||
|
@ -408,7 +408,7 @@ def normalize_mark_list(
|
|||
yield mark_obj
|
||||
|
||||
|
||||
def store_mark(obj, mark: Mark, *, stacklevel: int = 2) -> None:
|
||||
def store_mark(obj, mark: Mark) -> None:
|
||||
"""Store a Mark on an object.
|
||||
|
||||
This is used to implement the Mark declarations/decorators correctly.
|
||||
|
@ -418,7 +418,7 @@ def store_mark(obj, mark: Mark, *, stacklevel: int = 2) -> None:
|
|||
from ..fixtures import getfixturemarker
|
||||
|
||||
if getfixturemarker(obj) is not None:
|
||||
warnings.warn(MARKED_FIXTURE, stacklevel=stacklevel)
|
||||
_warn_auto_stacklevel(MARKED_FIXTURE)
|
||||
|
||||
# Always reassign name to avoid updating pytestmark in a reference that
|
||||
# was only borrowed.
|
||||
|
@ -543,12 +543,11 @@ class MarkGenerator:
|
|||
__tracebackhide__ = True
|
||||
fail(f"Unknown '{name}' mark, did you mean 'parametrize'?")
|
||||
|
||||
warnings.warn(
|
||||
_warn_auto_stacklevel(
|
||||
f"Unknown pytest.mark.{name} - is this a typo? You can register "
|
||||
"custom marks to avoid this warning - for details, see "
|
||||
"https://docs.pytest.org/en/stable/how-to/mark.html",
|
||||
PytestUnknownMarkWarning,
|
||||
2,
|
||||
)
|
||||
|
||||
return MarkDecorator(Mark(name, (), {}, _ispytest=True), _ispytest=True)
|
||||
|
|
|
@ -59,7 +59,7 @@ def test_hookimpl_via_function_attributes_are_deprecated():
|
|||
|
||||
with pytest.warns(
|
||||
PytestDeprecationWarning,
|
||||
match=r"Please use the pytest.hookimpl\(tryfirst=True\)",
|
||||
match=r"Please use the pytest\.hookimpl\(tryfirst=True\)",
|
||||
) as recorder:
|
||||
pm.register(DeprecatedMarkImplPlugin())
|
||||
(record,) = recorder
|
||||
|
@ -188,6 +188,18 @@ def test_fixture_disallow_on_marked_functions():
|
|||
# should point to this file
|
||||
assert record[0].filename == __file__
|
||||
|
||||
# Same with a different order
|
||||
with pytest.warns(
|
||||
pytest.PytestRemovedIn9Warning,
|
||||
match=r"Marks applied to fixtures have no effect",
|
||||
) as record:
|
||||
@pytest.mark.parametrize("example", ["hello"])
|
||||
@pytest.fixture
|
||||
def foo():
|
||||
raise NotImplementedError()
|
||||
assert len(record) == 1
|
||||
assert record[0].filename == __file__
|
||||
|
||||
|
||||
def test_fixture_disallow_marks_on_fixtures():
|
||||
"""Test that applying a mark to a fixture warns (#3364)."""
|
||||
|
|
Loading…
Reference in New Issue