Skip to content

Commit e306cc1

Browse files
committed
Switch to manual warnings for outdated sentinel parameters
1 parent 0a6544b commit e306cc1

2 files changed

Lines changed: 33 additions & 14 deletions

File tree

src/test_typing_extensions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9551,7 +9551,8 @@ def test_sentinel_no_repr(self):
95519551
self.assertEqual(repr(sentinel_no_repr), 'sentinel_no_repr')
95529552

95539553
def test_sentinel_deprecated_explicit_repr(self):
9554-
sentinel_explicit_repr = sentinel('sentinel_explicit_repr', repr='explicit_repr')
9554+
with self.assertWarnsRegex(DeprecationWarning, r"'repr' is deprecated and must be removed"):
9555+
sentinel_explicit_repr = sentinel('sentinel_explicit_repr', repr='explicit_repr')
95559556

95569557
self.assertEqual(repr(sentinel_explicit_repr), 'explicit_repr')
95579558

@@ -9598,8 +9599,11 @@ def test_sentinel_deprecated(self):
95989599
with self.assertWarnsRegex(DeprecationWarning, r"Subclassing sentinel is forbidden by PEP 661"):
95999600
class SentinelSubclass(Sentinel):
96009601
pass
9602+
with self.assertRaisesRegex(TypeError, r"First parameter 'name' is required"):
9603+
sentinel()
96019604

9602-
my_sentinel = Sentinel(name="my_sentinel")
9605+
with self.assertWarnsRegex(DeprecationWarning, r"'name' is positional-only and must not be a keyword parameter"):
9606+
my_sentinel = Sentinel(name="my_sentinel")
96039607
with self.assertWarnsRegex(DeprecationWarning, r"Setting attributes on sentinel is deprecated"):
96049608
my_sentinel.foo = "bar"
96059609

src/typing_extensions.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -173,27 +173,42 @@ def _caller(depth=1, default='__main__'):
173173
return None
174174

175175

176+
# Placeholder for sentinel methods, because sentinels can not have their own sentinels
177+
_sentinel_placeholder = object()
178+
179+
176180
class sentinel:
177181
"""Create a unique sentinel object.
178182
179183
*name* should be the name of the variable to which the return value shall be assigned.
180184
"""
181185

182-
@overload
183-
def __init__(self, name: str, /): ...
184-
185-
@overload
186-
@deprecated("'name' must be positional-only, \
187-
'repr' is deprecated and must be removed.")
188-
def __init__(self, name: str, repr: typing.Optional[str] = None): ...
189-
190186
def __init__(
191187
self,
192-
name: str,
188+
__name: str = _sentinel_placeholder,
189+
/,
193190
repr: typing.Optional[str] = None,
194-
):
195-
self.__name__ = name
196-
self._repr = repr if repr is not None else name
191+
*,
192+
name: str = _sentinel_placeholder,
193+
) -> None:
194+
if name is not _sentinel_placeholder:
195+
warnings.warn(
196+
"'name' is positional-only and must not be a keyword parameter",
197+
DeprecationWarning,
198+
stacklevel=2,
199+
)
200+
__name = name
201+
if __name is _sentinel_placeholder:
202+
raise TypeError("First parameter 'name' is required")
203+
if repr is not None:
204+
warnings.warn(
205+
"'repr' is deprecated and must be removed",
206+
DeprecationWarning,
207+
stacklevel=2,
208+
)
209+
210+
self.__name__ = __name
211+
self._repr = repr if repr is not None else __name
197212

198213
# For pickling as a singleton:
199214
self.__module__ = _caller()

0 commit comments

Comments
 (0)