Skip to content

Commit 0ddc080

Browse files
committed
Merge branch 'master' of github.com:fluentpython/example-code-2e
2 parents 135eca2 + abf7ac2 commit 0ddc080

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed
Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
"""
2+
This module provides a ``Sentinel`` class that can be used directly as a
3+
sentinel singleton, or subclassed if a distinct sentinel singleton is needed.
4+
5+
The ``repr`` of a ``Sentinel`` class is its name::
26
37
>>> class Missing(Sentinel): pass
48
>>> Missing
59
Missing
10+
11+
If a different ``repr`` is required,
12+
you can define it as a class attribute::
13+
614
>>> class CustomRepr(Sentinel):
715
... repr = '<CustomRepr>'
816
...
917
>>> CustomRepr
1018
<CustomRepr>
1119
20+
``Sentinel`` classes cannot be instantiated::
21+
22+
>>> Missing()
23+
Traceback (most recent call last):
24+
...
25+
TypeError: 'Missing' is a sentinel and cannot be instantiated
26+
1227
"""
1328

14-
class SentinelMeta(type):
29+
30+
class _SentinelMeta(type):
1531
def __repr__(cls):
1632
try:
1733
return cls.repr
1834
except AttributeError:
1935
return cls.__name__
2036

21-
class Sentinel(metaclass=SentinelMeta):
37+
38+
class Sentinel(metaclass=_SentinelMeta):
2239
def __new__(cls):
23-
return cls
40+
msg = 'is a sentinel and cannot be instantiated'
41+
raise TypeError(f"'{cls!r}' {msg}")

25-class-metaprog/sentinel/sentinel_test.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import pickle
22

3+
import pytest
4+
35
from sentinel import Sentinel
46

5-
class PlainSentinel(Sentinel): pass
7+
8+
class PlainSentinel(Sentinel):
9+
pass
610

711

812
class SentinelCustomRepr(Sentinel):
@@ -13,16 +17,23 @@ def test_repr():
1317
assert repr(PlainSentinel) == 'PlainSentinel'
1418

1519

16-
def test_pickle():
17-
s = pickle.dumps(PlainSentinel)
18-
ps = pickle.loads(s)
19-
assert ps is PlainSentinel
20+
def test_cannot_instantiate():
21+
with pytest.raises(TypeError) as e:
22+
PlainSentinel()
23+
msg = "'PlainSentinel' is a sentinel and cannot be instantiated"
24+
assert msg in str(e.value)
2025

2126

2227
def test_custom_repr():
2328
assert repr(SentinelCustomRepr) == '***SentinelRepr***'
2429

2530

31+
def test_pickle():
32+
s = pickle.dumps(SentinelCustomRepr)
33+
ps = pickle.loads(s)
34+
assert ps is SentinelCustomRepr
35+
36+
2637
def test_sentinel_comes_ready_to_use():
2738
assert repr(Sentinel) == 'Sentinel'
2839
s = pickle.dumps(Sentinel)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Fluent Python 2e example code
22

3-
Example code for the book **Fluent Python, 2<sup>nd</sup> edition** by Luciano Ramalho (O'Reilly, 2020).
3+
Example code for the book **Fluent Python, 2<sup>nd</sup> edition** by Luciano Ramalho (O'Reilly, 2021).
44

55
> **BEWARE**: This is a work in progress!
66
>

0 commit comments

Comments
 (0)