|
91 | 91 | 'overload', |
92 | 92 | 'override', |
93 | 93 | 'Protocol', |
| 94 | + 'sentinel', |
94 | 95 | 'Sentinel', |
95 | 96 | 'reveal_type', |
96 | 97 | 'runtime', |
|
159 | 160 | # Added with bpo-45166 to 3.10.1+ and some 3.9 versions |
160 | 161 | _FORWARD_REF_HAS_CLASS = "__forward_is_class__" in typing.ForwardRef.__slots__ |
161 | 162 |
|
162 | | -class Sentinel: |
163 | | - """Create a unique sentinel object. |
164 | 163 |
|
165 | | - *name* should be the name of the variable to which the return value shall be assigned. |
| 164 | +def _caller(depth=1, default='__main__'): |
| 165 | + try: |
| 166 | + return sys._getframemodulename(depth + 1) or default |
| 167 | + except AttributeError: # For platforms without _getframemodulename() |
| 168 | + pass |
| 169 | + try: |
| 170 | + return sys._getframe(depth + 1).f_globals.get('__name__', default) |
| 171 | + except (AttributeError, ValueError): # For platforms without _getframe() |
| 172 | + pass |
| 173 | + return None |
166 | 174 |
|
167 | | - *repr*, if supplied, will be used for the repr of the sentinel object. |
168 | | - If not provided, "<name>" will be used. |
169 | | - """ |
170 | 175 |
|
171 | | - def __init__( |
172 | | - self, |
173 | | - name: str, |
174 | | - repr: typing.Optional[str] = None, |
175 | | - ): |
176 | | - self._name = name |
177 | | - self._repr = repr if repr is not None else f'<{name}>' |
| 176 | +# Placeholder for sentinel methods, because sentinels can not have their own sentinels |
| 177 | +_sentinel_placeholder = object() |
178 | 178 |
|
179 | | - def __repr__(self): |
180 | | - return self._repr |
| 179 | +if hasattr(builtins, "sentinel"): # 3.15+ |
| 180 | + sentinel = builtins.sentinel |
| 181 | +else: |
| 182 | + class sentinel: |
| 183 | + """Create a unique sentinel object. |
181 | 184 |
|
182 | | - if sys.version_info < (3, 11): |
183 | | - # The presence of this method convinces typing._type_check |
184 | | - # that Sentinels are types. |
185 | | - def __call__(self, *args, **kwargs): |
186 | | - raise TypeError(f"{type(self).__name__!r} object is not callable") |
| 185 | + *name* should be the name of the variable to which the return value |
| 186 | + shall be assigned. |
| 187 | + """ |
| 188 | + |
| 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 | + ) |
| 214 | + |
| 215 | + self.__name__ = __name |
| 216 | + self._repr = repr if repr is not None else __name |
| 217 | + |
| 218 | + # For pickling as a singleton: |
| 219 | + self.__module__ = _caller() |
| 220 | + |
| 221 | + def __init_subclass__(cls): |
| 222 | + warnings.warn( |
| 223 | + "Subclassing sentinel is deprecated " |
| 224 | + "and will be disallowed in Python 3.15", |
| 225 | + DeprecationWarning, |
| 226 | + stacklevel=2, |
| 227 | + ) |
| 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) |
| 239 | + |
| 240 | + def __repr__(self): |
| 241 | + return self._repr |
| 242 | + |
| 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") |
| 248 | + |
| 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] |
187 | 253 |
|
188 | | - # Breakpoint: https://github.com/python/cpython/pull/21515 |
189 | | - if sys.version_info >= (3, 10): |
190 | | - def __or__(self, other): |
191 | | - return typing.Union[self, other] |
| 254 | + def __ror__(self, other): |
| 255 | + return typing.Union[other, self] |
192 | 256 |
|
193 | | - def __ror__(self, other): |
194 | | - return typing.Union[other, self] |
| 257 | + def __reduce__(self) -> str: |
| 258 | + """Reduce this sentinel to a singleton.""" |
| 259 | + return self.__name__ # Module is taken from the __module__ attribute |
195 | 260 |
|
196 | | - def __getstate__(self): |
197 | | - raise TypeError(f"Cannot pickle {type(self).__name__!r} object") |
| 261 | +Sentinel = sentinel |
198 | 262 |
|
| 263 | +_marker = sentinel("sentinel") |
199 | 264 |
|
200 | | -_marker = Sentinel("sentinel") |
201 | 265 |
|
202 | 266 | # The functions below are modified copies of typing internal helpers. |
203 | 267 | # They are needed by _ProtocolMeta and they provide support for PEP 646. |
@@ -638,18 +702,6 @@ def _get_protocol_attrs(cls): |
638 | 702 | return attrs |
639 | 703 |
|
640 | 704 |
|
641 | | -def _caller(depth=1, default='__main__'): |
642 | | - try: |
643 | | - return sys._getframemodulename(depth + 1) or default |
644 | | - except AttributeError: # For platforms without _getframemodulename() |
645 | | - pass |
646 | | - try: |
647 | | - return sys._getframe(depth + 1).f_globals.get('__name__', default) |
648 | | - except (AttributeError, ValueError): # For platforms without _getframe() |
649 | | - pass |
650 | | - return None |
651 | | - |
652 | | - |
653 | 705 | # `__match_args__` attribute was removed from protocol members in 3.13, |
654 | 706 | # we want to backport this change to older Python versions. |
655 | 707 | # Breakpoint: https://github.com/python/cpython/pull/110683 |
|
0 commit comments