Skip to content

Commit 232a38f

Browse files
committed
Warn if a Sentinel repr does not match its initial definition
Remove documentation implying that multiple definitions of Sentinel objects are a regular occurrence
1 parent 72d4379 commit 232a38f

File tree

3 files changed

+21
-5
lines changed

3 files changed

+21
-5
lines changed

doc/index.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,6 @@ Sentinel objects
10421042

10431043
If *repr* is provided, it will be used for the :meth:`~object.__repr__`
10441044
of the sentinel object. If not provided, *name* will be used.
1045-
Only the initial definition of the sentinel can configure *repr*.
10461045

10471046
All sentinels with the same *name* and *module_name* have the same identity.
10481047
Sentinel objects are tested using :py:ref:`is`.

src/test_typing_extensions.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9278,7 +9278,11 @@ def test_sentinel_repr(self):
92789278
def test_sentinel_explicit_repr(self):
92799279
sentinel_explicit_repr = Sentinel("sentinel_explicit_repr", repr="explicit_repr")
92809280
self.assertEqual(repr(sentinel_explicit_repr), "explicit_repr")
9281-
self.assertEqual(repr(Sentinel("sentinel_explicit_repr")), "explicit_repr")
9281+
with self.assertWarnsRegex(
9282+
DeprecationWarning,
9283+
r"repr='sentinel_explicit_repr' conflicts with initial definition of repr='explicit_repr'"
9284+
):
9285+
self.assertEqual(repr(Sentinel("sentinel_explicit_repr")), "explicit_repr")
92829286

92839287
def test_sentinel_explicit_repr_deprecated(self):
92849288
with self.assertWarnsRegex(
@@ -9287,7 +9291,11 @@ def test_sentinel_explicit_repr_deprecated(self):
92879291
):
92889292
deprecated_repr = Sentinel("deprecated_repr", "explicit_repr")
92899293
self.assertEqual(repr(deprecated_repr), "explicit_repr")
9290-
self.assertEqual(repr(Sentinel("deprecated_repr")), "explicit_repr")
9294+
with self.assertWarnsRegex(
9295+
DeprecationWarning,
9296+
r"repr='deprecated_repr' conflicts with initial definition of repr='explicit_repr'"
9297+
):
9298+
self.assertEqual(repr(Sentinel("deprecated_repr")), "explicit_repr")
92919299

92929300
@skipIf(sys.version_info < (3, 10), reason='New unions not available in 3.9')
92939301
def test_sentinel_type_expression_union(self):

src/typing_extensions.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4169,7 +4169,6 @@ class Sentinel:
41694169
41704170
*repr*, if supplied, will be used for the repr of the sentinel object.
41714171
If not provided, *name* will be used.
4172-
Only the initial definition of the sentinel can configure *repr*.
41734172
41744173
All sentinels with the same *name* and *module_name* have the same identity.
41754174
The ``is`` operator is used to test if an object is a sentinel.
@@ -4206,16 +4205,26 @@ def __new__(
42064205

42074206
registry_key = f"{module_name}-{name}"
42084207

4208+
repr = repr if repr is not None else name
4209+
42094210
# Check registered sentinels
42104211
sentinel = _sentinel_registry.get(registry_key, None)
42114212
if sentinel is not None:
4213+
if sentinel._repr != repr:
4214+
warnings.warn(
4215+
f"repr={repr!r} conflicts with initial definition of "
4216+
f"repr={sentinel._repr!r} and will be ignored"
4217+
"\nUsage of repr should be consistent across definitions",
4218+
DeprecationWarning,
4219+
stacklevel=2,
4220+
)
42124221
return sentinel
42134222

42144223
# Create initial or anonymous sentinel
42154224
sentinel = super().__new__(cls)
42164225
sentinel._name = name
42174226
sentinel.__module__ = module_name # Assign which module defined this instance
4218-
sentinel._repr = repr if repr is not None else name
4227+
sentinel._repr = repr
42194228
return _sentinel_registry.setdefault(registry_key, sentinel)
42204229

42214230
def __repr__(self) -> str:

0 commit comments

Comments
 (0)