@@ -4,53 +4,122 @@ sentinel — create sentinel and singleton objects
4
4
5
5
|Tests | |PyPI version |
6
6
7
- .. |Tests | image :: https://github.com/eddieantonio/sentinel/workflows/Python%20package /badge.svg
8
- :target: https://github.com/eddieantonio/sentinel/actions?query=workflow%3A%22Python+package %22
7
+ .. |Tests | image :: https://github.com/eddieantonio/sentinel/workflows/Test%20and%20Lint /badge.svg
8
+ :target: https://github.com/eddieantonio/sentinel/actions?query=workflow%3A%22Test+and+Lint %22
9
9
.. |PyPI version | image :: https://img.shields.io/pypi/v/sentinel
10
10
:target: https://pypi.org/project/sentinel/
11
11
12
- Creates simple sentinel objects which are the only instance of their own
13
- anonymous class. As a singleton, there is a guarantee that there will only
14
- ever be one instance: they can be safely used with ``pickle `` and ``cPickle ``
15
- alike, as well as being able to be used properly with ``copy.deepcopy() ``. In
16
- addition, a self-documenting ``__repr__ `` is provided for free!
12
+ Creates simple sentinel objects.
13
+
14
+
15
+ Install
16
+ =======
17
+
18
+ Basic features::
19
+
20
+ pip install sentinel
21
+
22
+ with extra magic features powered by python-varname _::
23
+
24
+ pip install 'sentinel[varname]'
25
+
26
+
27
+ What is a sentinel?
28
+ ===================
29
+
30
+ Sentinels _ are singleton _ objects that typically represent some
31
+ terminating (end) condition or have a special, symbolic meaning. Python's built-in
32
+ ``None `` is a sentinel. Python also has other sentinels like ``NotImplemented `` and
33
+ ``Ellipsis ``.
34
+
35
+ If you want to create your own sentinels, use this library! Make your calls to
36
+ ``dict.get() `` more meaningful! You can replace the ``object() `` idiom with a sentinel:
37
+
38
+ .. code-block :: python
39
+
40
+ d = {" a" : 1 , " b" : None }
41
+
42
+ # Before sentinel:
43
+ missing = object ()
44
+ if d.get(" c" , missing) is missing:
45
+ ... # do some stuff
46
+
47
+ # After sentinel:
48
+ Missing = sentinel.create()
49
+ if d.get(" c" , Missing) is Missing:
50
+ ... # do some stuff
51
+
52
+
53
+ Features
54
+ --------
55
+
56
+ - sentinels are unique
57
+ - sentinels are singletons — the **only ** instance of their own anonymous class
58
+ - sentinels can be used with ``is `` comparisons
59
+ - sentinels can be used with ``pickle ``
60
+ - sentinels can be used with ``copy.deepcopy ``
61
+ - you can **add ** arbitrary attributes and methods to sentinels
62
+ - sentinels have a nice, self-documenting ``__repr__ ``!
17
63
18
64
Usage
19
65
=====
20
66
21
- Sentinels _ are singleton _ objects that typically represent some end or
22
- terminating condition. Some singletons already exist in Python, like ``None ``,
23
- ``NotImplemented ``, and ``Ellipsis ``.
67
+ Create a sentinel:
24
68
69
+ >>> import sentinel
70
+ >>> MySentinel = sentinel.create(" MySentinel" )
71
+ >>> Sentinel
72
+ Sentinel
25
73
26
- All that's needed to create a sentinel is its name:
74
+ If you have python-varname _ installed, or installed this module using
75
+ ``pip install 'sentinel[varname]' ``, ``sentinel.create() `` can infer the name
76
+ from the assignment expression:
27
77
28
- >>> import sentinel
29
- >>> Nothing = sentinel.create(' Nothing' )
30
- >>> Nothing
31
- Nothing
78
+ .. code-block :: python
79
+
80
+ import sentinel
32
81
33
- This by itself is useful when other objects such as ``None ``, ``False ``,
34
- ``0 ``, ``-1 ``, etc. are entirely valid values. For example, setting default
35
- values when all other values are valid with: ``dict.setdefault() ``:
82
+ MySentinel = sentinel.create()
36
83
37
- >>> MissingEntry = sentinel.create(' MissingEntry' )
38
- >>> d = {' stdout' : None , ' stdin' : 0 , ' EOF' : - 1 }
39
- >>> [d.setdefault(key, MissingEntry) for key in (' stdin' , ' stdout' , ' stderr' )]
40
- [0, None, MissingEntry]
84
+ print (MySentinel) # prints `MySentinel`
85
+
86
+
87
+ Example
88
+ -------
89
+
90
+ Sentinels are useful when other objects such as ``None ``, ``False ``,
91
+ ``0 ``, ``-1 ``, are valid values within some data structure. For example, setting
92
+ default values when all other values are valid with:
93
+ ``dict.setdefault() ``:
94
+
95
+ .. code-block :: python
96
+
97
+ d = {" stdout" : None , " stdin" : 0 , " EOF" : - 1 }
98
+
99
+ MissingEntry = sentinel.create()
100
+
101
+ [d.setdefault(key, MissingEntry) for key in (" stdin" , " stdout" , " stderr" )]
102
+ [0 , None , MissingEntry]
41
103
42
104
Alternatively, using ``dict.get() `` when fetching values:
43
105
44
- >>> d = {' stdout' : None , ' stdin' : 0 , ' EOF' : - 1 }
45
- >>> d.get(' stdout' , MissingEntry)
106
+ >>> d = {" stdout" : None , " stdin" : 0 , " EOF" : - 1 }
107
+ >>> d.get(" stdout" , MissingEntry)
46
108
None
47
- >>> d.get(' stdin' , MissingEntry)
109
+ >>> d.get(" stdin" , MissingEntry)
48
110
0
49
- >>> d.get(' stderr' , MissingEntry)
111
+ >>> d.get(" stderr" , MissingEntry)
50
112
MissingEntry
51
113
52
- It's known immediately which value was missing from the dictionary in a
53
- self-documenting manner.
114
+ Since a new sentinel can never occur in the original dictionary, you can tell which
115
+ entries are missing or unset in a dictionary in a self-documenting way:
116
+
117
+ .. code-block :: python
118
+
119
+ Unset = sentinel.create()
120
+ if d.get(" stdin" , Unset) is Unset:
121
+ stdin = 0 # some reasonable default
122
+
54
123
55
124
Adding extra methods and class attributes
56
125
-----------------------------------------
@@ -110,7 +179,7 @@ Contributing
110
179
This project uses Poetry _. To contribute to the codebase, make sure to `install poetry `_,
111
180
With Poetry installed, clone then repo, then within the repo directory, install the developer dependencies::
112
181
113
- $ poetry install
182
+ $ poetry install --extras varname
114
183
115
184
Next, I recommend you do all development tasks within the ``poetry shell ``::
116
185
@@ -122,3 +191,4 @@ Next, I recommend you do all development tasks within the ``poetry shell``::
122
191
.. _singleton : http://en.wikipedia.org/wiki/Singleton_pattern
123
192
.. _Poetry : https://python-poetry.org/
124
193
.. _install poetry : https://python-poetry.org/docs/#installation
194
+ .. _python-varname : https://github.com/pwwang/python-varname
0 commit comments