improved sentinel after learning from @taleinat on python-dev
This commit is contained in:
parent
08a4001b43
commit
0ce109a9fe
@ -1,23 +1,41 @@
|
|||||||
"""
|
"""
|
||||||
|
This module provides a ``Sentinel`` class that can be used directly as a
|
||||||
|
sentinel singleton, or subclassed if a distinct sentinel singleton is needed.
|
||||||
|
|
||||||
|
The ``repr`` of a ``Sentinel`` class is its name::
|
||||||
|
|
||||||
>>> class Missing(Sentinel): pass
|
>>> class Missing(Sentinel): pass
|
||||||
>>> Missing
|
>>> Missing
|
||||||
Missing
|
Missing
|
||||||
|
|
||||||
|
If a different ``repr`` is required,
|
||||||
|
you can define it as a class attribute::
|
||||||
|
|
||||||
>>> class CustomRepr(Sentinel):
|
>>> class CustomRepr(Sentinel):
|
||||||
... repr = '<CustomRepr>'
|
... repr = '<CustomRepr>'
|
||||||
...
|
...
|
||||||
>>> CustomRepr
|
>>> CustomRepr
|
||||||
<CustomRepr>
|
<CustomRepr>
|
||||||
|
|
||||||
|
``Sentinel`` classes cannot be instantiated::
|
||||||
|
|
||||||
|
>>> Missing()
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
TypeError: 'Missing' is a sentinel and cannot be instantiated
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class SentinelMeta(type):
|
|
||||||
|
class _SentinelMeta(type):
|
||||||
def __repr__(cls):
|
def __repr__(cls):
|
||||||
try:
|
try:
|
||||||
return cls.repr
|
return cls.repr
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return cls.__name__
|
return f'{cls.__name__}'
|
||||||
|
|
||||||
class Sentinel(metaclass=SentinelMeta):
|
|
||||||
|
class Sentinel(metaclass=_SentinelMeta):
|
||||||
def __new__(cls):
|
def __new__(cls):
|
||||||
return cls
|
msg = 'is a sentinel and cannot be instantiated'
|
||||||
|
raise TypeError(f"'{cls!r}' {msg}")
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from sentinel import Sentinel
|
from sentinel import Sentinel
|
||||||
|
|
||||||
class PlainSentinel(Sentinel): pass
|
|
||||||
|
class PlainSentinel(Sentinel):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SentinelCustomRepr(Sentinel):
|
class SentinelCustomRepr(Sentinel):
|
||||||
@ -13,16 +17,23 @@ def test_repr():
|
|||||||
assert repr(PlainSentinel) == 'PlainSentinel'
|
assert repr(PlainSentinel) == 'PlainSentinel'
|
||||||
|
|
||||||
|
|
||||||
def test_pickle():
|
def test_cannot_instantiate():
|
||||||
s = pickle.dumps(PlainSentinel)
|
with pytest.raises(TypeError) as e:
|
||||||
ps = pickle.loads(s)
|
PlainSentinel()
|
||||||
assert ps is PlainSentinel
|
msg = "'PlainSentinel' is a sentinel and cannot be instantiated"
|
||||||
|
assert msg in str(e.value)
|
||||||
|
|
||||||
|
|
||||||
def test_custom_repr():
|
def test_custom_repr():
|
||||||
assert repr(SentinelCustomRepr) == '***SentinelRepr***'
|
assert repr(SentinelCustomRepr) == '***SentinelRepr***'
|
||||||
|
|
||||||
|
|
||||||
|
def test_pickle():
|
||||||
|
s = pickle.dumps(SentinelCustomRepr)
|
||||||
|
ps = pickle.loads(s)
|
||||||
|
assert ps is SentinelCustomRepr
|
||||||
|
|
||||||
|
|
||||||
def test_sentinel_comes_ready_to_use():
|
def test_sentinel_comes_ready_to_use():
|
||||||
assert repr(Sentinel) == 'Sentinel'
|
assert repr(Sentinel) == 'Sentinel'
|
||||||
s = pickle.dumps(Sentinel)
|
s = pickle.dumps(Sentinel)
|
||||||
|
Loading…
Reference in New Issue
Block a user