Skip to content

Commit cf7f6f2

Browse files
committed
Port sentinel from Python when available
1 parent e86435c commit cf7f6f2

1 file changed

Lines changed: 67 additions & 60 deletions

File tree

src/typing_extensions.py

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -176,80 +176,87 @@ def _caller(depth=1, default='__main__'):
176176
# Placeholder for sentinel methods, because sentinels can not have their own sentinels
177177
_sentinel_placeholder = object()
178178

179+
if hasattr(builtins, "sentinel"): # 3.15+
180+
sentinel = builtins.sentinel
181+
else:
182+
class sentinel:
183+
"""Create a unique sentinel object.
179184
180-
class sentinel:
181-
"""Create a unique sentinel object.
182-
183-
*name* should be the name of the variable to which the return value shall be assigned.
184-
"""
185-
186-
def __init__(
187-
self,
188-
__name: str = _sentinel_placeholder,
189-
/,
190-
repr: typing.Optional[str] = None,
191-
*,
192-
name: str = _sentinel_placeholder,
193-
) -> None:
194-
if name is not _sentinel_placeholder:
195-
warnings.warn(
196-
"Passing 'name' as a keyword argument is deprecated; pass it positionally instead.",
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-
"The 'repr' parameter is deprecated and will be removed in Python 3.15.",
206-
DeprecationWarning,
207-
stacklevel=2,
208-
)
185+
*name* should be the name of the variable to which the return value
186+
shall be assigned.
187+
"""
209188

210-
self.__name__ = __name
211-
self._repr = repr if repr is not None else __name
189+
def __init__(
190+
self,
191+
__name: str = _sentinel_placeholder,
192+
/,
193+
repr: typing.Optional[str] = None,
194+
*,
195+
name: str = _sentinel_placeholder,
196+
) -> None:
197+
if name is not _sentinel_placeholder:
198+
warnings.warn(
199+
"Passing 'name' as a keyword argument is deprecated; "
200+
"pass it positionally instead.",
201+
DeprecationWarning,
202+
stacklevel=2,
203+
)
204+
__name = name
205+
if __name is _sentinel_placeholder:
206+
raise TypeError("First parameter 'name' is required")
207+
if repr is not None:
208+
warnings.warn(
209+
"The 'repr' parameter is deprecated "
210+
"and will be removed in Python 3.15.",
211+
DeprecationWarning,
212+
stacklevel=2,
213+
)
212214

213-
# For pickling as a singleton:
214-
self.__module__ = _caller()
215+
self.__name__ = __name
216+
self._repr = repr if repr is not None else __name
215217

216-
def __init_subclass__(cls):
217-
warnings.warn(
218-
"Subclassing sentinel is deprecated and will be disallowed in Python 3.15",
219-
DeprecationWarning,
220-
stacklevel=2,
221-
)
222-
super().__init_subclass__()
218+
# For pickling as a singleton:
219+
self.__module__ = _caller()
223220

224-
def __setattr__(self, attr: str, value: object) -> None:
225-
if attr not in {"__name__", "_repr", "__module__"}:
221+
def __init_subclass__(cls):
226222
warnings.warn(
227-
f"Setting attribute {attr!r} on sentinel objects is deprecated and will be disallowed in Python 3.15.",
223+
"Subclassing sentinel is deprecated "
224+
"and will be disallowed in Python 3.15",
228225
DeprecationWarning,
229226
stacklevel=2,
230227
)
231-
super().__setattr__(attr, value)
228+
super().__init_subclass__()
229+
230+
def __setattr__(self, attr: str, value: object) -> None:
231+
if attr not in {"__name__", "_repr", "__module__"}:
232+
warnings.warn(
233+
f"Setting attribute {attr!r} on sentinel objects is deprecated "
234+
"and will be disallowed in Python 3.15.",
235+
DeprecationWarning,
236+
stacklevel=2,
237+
)
238+
super().__setattr__(attr, value)
232239

233-
def __repr__(self):
234-
return self._repr
240+
def __repr__(self):
241+
return self._repr
235242

236-
if sys.version_info < (3, 11):
237-
# The presence of this method convinces typing._type_check
238-
# that Sentinels are types.
239-
def __call__(self, *args, **kwargs):
240-
raise TypeError(f"{type(self).__name__!r} object is not callable")
243+
if sys.version_info < (3, 11):
244+
# The presence of this method convinces typing._type_check
245+
# that Sentinels are types.
246+
def __call__(self, *args, **kwargs):
247+
raise TypeError(f"{type(self).__name__!r} object is not callable")
241248

242-
# Breakpoint: https://github.com/python/cpython/pull/21515
243-
if sys.version_info >= (3, 10):
244-
def __or__(self, other):
245-
return typing.Union[self, other]
249+
# Breakpoint: https://github.com/python/cpython/pull/21515
250+
if sys.version_info >= (3, 10):
251+
def __or__(self, other):
252+
return typing.Union[self, other]
246253

247-
def __ror__(self, other):
248-
return typing.Union[other, self]
254+
def __ror__(self, other):
255+
return typing.Union[other, self]
249256

250-
def __reduce__(self) -> str:
251-
"""Reduce this sentinel to a singleton."""
252-
return self.__name__ # Module is taken from the __module__ attribute
257+
def __reduce__(self) -> str:
258+
"""Reduce this sentinel to a singleton."""
259+
return self.__name__ # Module is taken from the __module__ attribute
253260

254261
Sentinel = sentinel
255262

0 commit comments

Comments
 (0)