Skip to content

Commit ab69076

Browse files
committed
well, let's just deprecate these then... ezpzzzz
1 parent d1e7d9d commit ab69076

File tree

22 files changed

+356
-162
lines changed

22 files changed

+356
-162
lines changed

src/_pytest/deprecated.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,42 @@
1111

1212
from __future__ import annotations
1313

14+
import sys
15+
from typing import TYPE_CHECKING
1416
from warnings import warn
1517

1618
from _pytest.warning_types import PytestDeprecationWarning
1719
from _pytest.warning_types import PytestRemovedIn9Warning
1820
from _pytest.warning_types import UnformattedWarning
1921

2022

23+
# the `as` indicates explicit re-export to type checkers
24+
# mypy currently does not support overload+deprecated
25+
if sys.version_info >= (3, 13):
26+
from warnings import deprecated as deprecated
27+
elif TYPE_CHECKING:
28+
from typing_extensions import deprecated as deprecated
29+
else:
30+
31+
def deprecated(func: object) -> object:
32+
return func
33+
34+
35+
CALLABLE_RAISES = PytestDeprecationWarning(
36+
"The callable form of pytest.raises is deprecated.\n"
37+
"Use `with pytest.raises(...):` instead."
38+
)
39+
40+
CALLABLE_WARNS = PytestDeprecationWarning(
41+
"The callable form of pytest.warns is deprecated.\n"
42+
"Use `with pytest.warns(...):` instead."
43+
)
44+
CALLABLE_DEPRECATED_CALL = PytestDeprecationWarning(
45+
"The callable form of pytest.deprecated_call is deprecated.\n"
46+
"Use `with pytest.deprecated_call():` instead."
47+
)
48+
49+
2150
# set of plugins which have been integrated into the core; we use this list to ignore
2251
# them during registration to avoid conflicts
2352
DEPRECATED_EXTERNAL_PLUGINS = {

src/_pytest/python_api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
from typing import overload
2323
from typing import TYPE_CHECKING
2424
from typing import TypeVar
25+
import warnings
2526

2627
import _pytest._code
28+
from _pytest.deprecated import CALLABLE_RAISES
29+
from _pytest.deprecated import deprecated
2730
from _pytest.outcomes import fail
2831

2932

@@ -806,6 +809,7 @@ def raises(
806809

807810

808811
@overload
812+
@deprecated("Use context-manager form instead")
809813
def raises(
810814
expected_exception: type[E] | tuple[type[E], ...],
811815
func: Callable[P, object],
@@ -1020,6 +1024,7 @@ def validate_exc(exc: type[E]) -> type[E]:
10201024
else:
10211025
if not callable(func):
10221026
raise TypeError(f"{func!r} object (type: {type(func)}) must be callable")
1027+
warnings.warn(CALLABLE_RAISES, stacklevel=2)
10231028
try:
10241029
func(*args, **kwargs)
10251030
except expected_exceptions as e:

src/_pytest/recwarn.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@
1717

1818

1919
if TYPE_CHECKING:
20+
from typing_extensions import ParamSpec
2021
from typing_extensions import Self
2122

23+
P = ParamSpec("P")
24+
2225
import warnings
2326

27+
from _pytest.deprecated import CALLABLE_DEPRECATED_CALL
28+
from _pytest.deprecated import CALLABLE_WARNS
2429
from _pytest.deprecated import check_ispytest
30+
from _pytest.deprecated import deprecated
2531
from _pytest.fixtures import fixture
2632
from _pytest.outcomes import Exit
2733
from _pytest.outcomes import fail
@@ -49,7 +55,8 @@ def deprecated_call(
4955

5056

5157
@overload
52-
def deprecated_call(func: Callable[..., T], *args: Any, **kwargs: Any) -> T: ...
58+
@deprecated("Use context-manager form instead")
59+
def deprecated_call(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: ...
5360

5461

5562
def deprecated_call(
@@ -79,11 +86,13 @@ def deprecated_call(
7986
one for each warning raised.
8087
"""
8188
__tracebackhide__ = True
89+
# potential QoL: allow `with deprecated_call:` - i.e. no parens
90+
dep_warnings = (DeprecationWarning, PendingDeprecationWarning, FutureWarning)
8291
if func is not None:
83-
args = (func, *args)
84-
return warns(
85-
(DeprecationWarning, PendingDeprecationWarning, FutureWarning), *args, **kwargs
86-
)
92+
warnings.warn(CALLABLE_DEPRECATED_CALL, stacklevel=2)
93+
with warns(dep_warnings):
94+
return func(*args, **kwargs)
95+
return warns(dep_warnings, *args, **kwargs)
8796

8897

8998
@overload
@@ -95,18 +104,19 @@ def warns(
95104

96105

97106
@overload
107+
@deprecated("Use context-manager form instead")
98108
def warns(
99109
expected_warning: type[Warning] | tuple[type[Warning], ...],
100-
func: Callable[..., T],
101-
*args: Any,
102-
**kwargs: Any,
110+
func: Callable[P, T],
111+
*args: P.args,
112+
**kwargs: P.kwargs,
103113
) -> T: ...
104114

105115

106116
def warns(
107117
expected_warning: type[Warning] | tuple[type[Warning], ...] = Warning,
118+
func: Callable[..., object] | None = None,
108119
*args: Any,
109-
match: str | re.Pattern[str] | None = None,
110120
**kwargs: Any,
111121
) -> WarningsChecker | Any:
112122
r"""Assert that code raises a particular class of warning.
@@ -151,7 +161,8 @@ def warns(
151161
152162
"""
153163
__tracebackhide__ = True
154-
if not args:
164+
if func is None and not args:
165+
match: str | re.Pattern[str] | None = kwargs.pop("match", None)
155166
if kwargs:
156167
argnames = ", ".join(sorted(kwargs))
157168
raise TypeError(
@@ -160,11 +171,11 @@ def warns(
160171
)
161172
return WarningsChecker(expected_warning, match_expr=match, _ispytest=True)
162173
else:
163-
func = args[0]
164174
if not callable(func):
165175
raise TypeError(f"{func!r} object (type: {type(func)}) must be callable")
176+
warnings.warn(CALLABLE_WARNS, stacklevel=2)
166177
with WarningsChecker(expected_warning, _ispytest=True):
167-
return func(*args[1:], **kwargs)
178+
return func(*args, **kwargs)
168179

169180

170181
class WarningsRecorder(warnings.catch_warnings): # type:ignore[type-arg]

testing/_py/test_local.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,8 @@ def test_chdir_gone(self, path1):
625625
p = path1.ensure("dir_to_be_removed", dir=1)
626626
p.chdir()
627627
p.remove()
628-
pytest.raises(error.ENOENT, local)
628+
with pytest.raises(error.ENOENT):
629+
local()
629630
assert path1.chdir() is None
630631
assert os.getcwd() == str(path1)
631632

@@ -998,8 +999,10 @@ def test_locked_make_numbered_dir(self, tmpdir):
998999
assert numdir.new(ext=str(j)).check()
9991000

10001001
def test_error_preservation(self, path1):
1001-
pytest.raises(EnvironmentError, path1.join("qwoeqiwe").mtime)
1002-
pytest.raises(EnvironmentError, path1.join("qwoeqiwe").read)
1002+
with pytest.raises(EnvironmentError):
1003+
path1.join("qwoeqiwe").mtime()
1004+
with pytest.raises(EnvironmentError):
1005+
path1.join("qwoeqiwe").read()
10031006

10041007
# def test_parentdirmatch(self):
10051008
# local.parentdirmatch('std', startmodule=__name__)
@@ -1099,7 +1102,8 @@ def test_pyimport_check_filepath_consistency(self, monkeypatch, tmpdir):
10991102
pseudopath = tmpdir.ensure(name + "123.py")
11001103
mod.__file__ = str(pseudopath)
11011104
monkeypatch.setitem(sys.modules, name, mod)
1102-
excinfo = pytest.raises(pseudopath.ImportMismatchError, p.pyimport)
1105+
with pytest.raises(pseudopath.ImportMismatchError) as excinfo:
1106+
p.pyimport()
11031107
modname, modfile, orig = excinfo.value.args
11041108
assert modname == name
11051109
assert modfile == pseudopath
@@ -1397,7 +1401,8 @@ def test_stat_helpers(self, tmpdir, monkeypatch):
13971401

13981402
def test_stat_non_raising(self, tmpdir):
13991403
path1 = tmpdir.join("file")
1400-
pytest.raises(error.ENOENT, lambda: path1.stat())
1404+
with pytest.raises(error.ENOENT):
1405+
path1.stat()
14011406
res = path1.stat(raising=False)
14021407
assert res is None
14031408

testing/code/test_code.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ def test_code_from_func() -> None:
8585
def test_unicode_handling() -> None:
8686
value = "ąć".encode()
8787

88-
def f() -> None:
88+
with pytest.raises(Exception) as excinfo:
8989
raise Exception(value)
90-
91-
excinfo = pytest.raises(Exception, f)
9290
str(excinfo)
9391

9492

0 commit comments

Comments
 (0)