@@ -141,6 +141,18 @@ different possible implementations, the design below was chosen to meet these
141141criteria while keeping the API and implementation small (see
142142`Reference Implementation `_).
143143
144+ To support common use cases, we add two customization points:
145+
146+ - The ``repr `` argument can be used to customize the ``repr() `` of sentinels. Many
147+ pre-existing sentinels in the standard library use a custom repr like ``<missing> ``,
148+ and this argument allows us to convert these sentinels to the new API while
149+ preserving this behavior.
150+ - The ``__module__ `` attribute of sentinels is writable, allowing users to
151+ control the module used for pickling in some unusual cases, such as sentinels
152+ created through ``exec() ``. This aligns with the behavior of other built-in
153+ types with a ``__module__ `` attribute, including classes, functions, ``TypeVar ``
154+ objects, and (as of Python 3.15) type aliases.
155+
144156
145157Specification
146158=============
@@ -151,14 +163,17 @@ A new built-in callable named ``sentinel`` will be added.
151163 >>> MISSING
152164 MISSING
153165
154- ``sentinel() `` takes a single positional-only argument, ``name ``, which must
155- be a ``str ``. Passing a non-string raises ``TypeError ``. The name is used as
156- the sentinel's name and repr.
166+ ``sentinel() `` takes a single required positional-only argument, ``name ``, which must
167+ be a ``str ``, and an optional keyword-only argument, ``repr ``.
168+ Passing a non-string as the ``name `` raises ``TypeError ``. The name is used as
169+ the sentinel's name. The value of the ``repr `` argument is used for the ``str() `` and ``repr() ``
170+ of the sentinel object, if given. If not given, the name is used instead.
157171
158172Sentinel objects have two public attributes:
159173
160174* ``__name__ `` is the sentinel's name.
161175* ``__module__ `` is the name of the module where ``sentinel() `` was called.
176+ This attribute is writable.
162177
163178``sentinel `` may not be subclassed.
164179
@@ -303,23 +318,20 @@ A sketch of the intended behavior follows::
303318 class sentinel:
304319 """Unique sentinel values."""
305320
306- __slots__ = ("__name__", "_module_name ")
321+ __slots__ = ("__name__", "__module__", "_repr ")
307322
308323 def __init_subclass__(cls):
309324 raise TypeError("type 'sentinel' is not an acceptable base type")
310325
311- def __init__(self, name, /):
326+ def __init__(self, name, /, repr=None ):
312327 if not isinstance(name, str):
313328 raise TypeError("sentinel name must be a string")
314329 self.__name__ = name
315- self._module_name = sys._getframemodulename(1)
316-
317- @property
318- def __module__(self):
319- return self._module_name
330+ self.__module__ = sys._getframemodulename(1)
331+ self._repr = repr if repr is not None else name
320332
321333 def __repr__(self):
322- return self.__name__
334+ return self._repr
323335
324336 def __reduce__(self):
325337 return self.__name__
@@ -492,14 +504,6 @@ module or class name, they can include it in the single ``name`` argument
492504explicitly, e.g. ``sentinel("mymodule.MISSING") ``.
493505
494506
495- Allowing customization of repr
496- ------------------------------
497-
498- This was desirable to allow using this for existing sentinel values without
499- changing their repr. However, this was eventually dropped as it wasn't
500- considered worth the added complexity.
501-
502-
503507Allowing customization of boolean evaluation
504508--------------------------------------------
505509
0 commit comments