Skip to content

Commit b687905

Browse files
committed
PEP 661: Amend to allow two customizations
1 parent 0cde95d commit b687905

1 file changed

Lines changed: 23 additions & 19 deletions

File tree

peps/pep-0661.rst

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,18 @@ different possible implementations, the design below was chosen to meet these
141141
criteria 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

145157
Specification
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

158172
Sentinel 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
492504
explicitly, 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-
503507
Allowing customization of boolean evaluation
504508
--------------------------------------------
505509

0 commit comments

Comments
 (0)