17
17
18
18
19
19
if TYPE_CHECKING :
20
+ from typing_extensions import ParamSpec
20
21
from typing_extensions import Self
21
22
23
+ P = ParamSpec ("P" )
24
+
22
25
import warnings
23
26
24
27
from _pytest .deprecated import check_ispytest
@@ -49,7 +52,7 @@ def deprecated_call(
49
52
50
53
51
54
@overload
52
- def deprecated_call (func : Callable [... , T ], * args : Any , ** kwargs : Any ) -> T : ...
55
+ def deprecated_call (func : Callable [P , T ], * args : P . args , ** kwargs : P . kwargs ) -> T : ...
53
56
54
57
55
58
def deprecated_call (
@@ -67,6 +70,8 @@ def deprecated_call(
67
70
>>> import pytest
68
71
>>> with pytest.deprecated_call():
69
72
... assert api_call_v2() == 200
73
+ >>> with pytest.deprecated_call(match="^use v3 of this api$") as warning_messages:
74
+ ... assert api_call_v2() == 200
70
75
71
76
It can also be used by passing a function and ``*args`` and ``**kwargs``,
72
77
in which case it will ensure calling ``func(*args, **kwargs)`` produces one of
@@ -76,14 +81,17 @@ def deprecated_call(
76
81
that the warning matches a text or regex.
77
82
78
83
The context manager produces a list of :class:`warnings.WarningMessage` objects,
79
- one for each warning raised.
84
+ one for each warning emitted
85
+ (regardless of whether it is an ``expected_warning`` or not).
80
86
"""
81
87
__tracebackhide__ = True
82
- if func is not None :
83
- args = (func , * args )
84
- return warns (
85
- (DeprecationWarning , PendingDeprecationWarning , FutureWarning ), * args , ** kwargs
86
- )
88
+ # Potential QoL: allow `with deprecated_call:` - i.e. no parens
89
+ dep_warnings = (DeprecationWarning , PendingDeprecationWarning , FutureWarning )
90
+ if func is None :
91
+ return warns (dep_warnings , * args , ** kwargs )
92
+
93
+ with warns (dep_warnings ):
94
+ return func (* args , ** kwargs )
87
95
88
96
89
97
@overload
@@ -97,16 +105,16 @@ def warns(
97
105
@overload
98
106
def warns (
99
107
expected_warning : type [Warning ] | tuple [type [Warning ], ...],
100
- func : Callable [... , T ],
101
- * args : Any ,
102
- ** kwargs : Any ,
108
+ func : Callable [P , T ],
109
+ * args : P . args ,
110
+ ** kwargs : P . kwargs ,
103
111
) -> T : ...
104
112
105
113
106
114
def warns (
107
115
expected_warning : type [Warning ] | tuple [type [Warning ], ...] = Warning ,
116
+ func : Callable [..., object ] | None = None ,
108
117
* args : Any ,
109
- match : str | re .Pattern [str ] | None = None ,
110
118
** kwargs : Any ,
111
119
) -> WarningsChecker | Any :
112
120
r"""Assert that code raises a particular class of warning.
@@ -151,7 +159,8 @@ def warns(
151
159
152
160
"""
153
161
__tracebackhide__ = True
154
- if not args :
162
+ if func is None and not args :
163
+ match : str | re .Pattern [str ] | None = kwargs .pop ("match" , None )
155
164
if kwargs :
156
165
argnames = ", " .join (sorted (kwargs ))
157
166
raise TypeError (
@@ -160,11 +169,10 @@ def warns(
160
169
)
161
170
return WarningsChecker (expected_warning , match_expr = match , _ispytest = True )
162
171
else :
163
- func = args [0 ]
164
172
if not callable (func ):
165
173
raise TypeError (f"{ func !r} object (type: { type (func )} ) must be callable" )
166
174
with WarningsChecker (expected_warning , _ispytest = True ):
167
- return func (* args [ 1 :] , ** kwargs )
175
+ return func (* args , ** kwargs )
168
176
169
177
170
178
class WarningsRecorder (warnings .catch_warnings ):
0 commit comments