Create sentinel objects, akin to None, NotImplemented, Ellipsis
Project description
Creates simple sentinel objects.
Install
Basic features:
pip install sentinel
with extra magic features powered by python-varname:
pip install 'sentinel[varname]'
What is a sentinel?
Sentinels are singleton objects that typically represent some terminating (end) condition or have a special, symbolic meaning. Python’s built-in None is a sentinel. Python also has other sentinels like NotImplemented and Ellipsis.
If you want to create your own sentinels, use this library! Make your calls to dict.get() more meaningful! You can replace the object() idiom with a sentinel:
d = {"a": 1, "b": None}
# Before sentinel:
missing = object()
if d.get("c", missing) is missing:
... # do some stuff
# After sentinel:
Missing = sentinel.create()
if d.get("c", Missing) is Missing:
... # do some stuff
Features
sentinels are unique
sentinels are singletons — the only instance of their own anonymous class
sentinels can be used with is comparisons
sentinels can be used with pickle
sentinels can be used with copy.deepcopy
you can add arbitrary attributes and methods to sentinels
sentinels have a nice, self-documenting __repr__!
Usage
Create a sentinel:
>>> import sentinel >>> MySentinel = sentinel.create("MySentinel") >>> Sentinel Sentinel
If you have python-varname installed, or installed this module using pip install 'sentinel[varname]', sentinel.create() can infer the name from the assignment expression:
import sentinel
MySentinel = sentinel.create()
print(MySentinel) # prints `MySentinel`
Example
Sentinels are useful when other objects such as None, False, 0, -1, are valid values within some data structure. For example, setting default values when all other values are valid with: dict.setdefault():
d = {"stdout": None, "stdin": 0, "EOF": -1}
MissingEntry = sentinel.create()
[d.setdefault(key, MissingEntry) for key in ("stdin", "stdout", "stderr")]
[0, None, MissingEntry]
Alternatively, using dict.get() when fetching values:
>>> d = {"stdout": None, "stdin": 0, "EOF": -1} >>> d.get("stdout", MissingEntry) None >>> d.get("stdin", MissingEntry) 0 >>> d.get("stderr", MissingEntry) MissingEntry
Since a new sentinel can never occur in the original dictionary, you can tell which entries are missing or unset in a dictionary in a self-documenting way:
Unset = sentinel.create()
if d.get("stdin", Unset) is Unset:
stdin = 0 # some reasonable default
Adding extra methods and class attributes
Sentinels may also inherit from base classes, or implement extra methods.
Consider a binary search tree with two kinds of nodes: interior nodes (Node) which contain some payload and leaves (Leaf), which simply terminate traversal.
To create singleton leaf which implements a search method and an is_leaf property, you may provide any extra class attributes in the cls_dict keyword argument. The following is a full example of both the singleton Leaf and its Node counterpart:
def _search_leaf(self, key):
raise KeyError(key)
Leaf = sentinel.create('Leaf', cls_dict={
'search': _search_leaf,
'is_leaf': property(lambda self: True)
})
class Node(object):
def __init__(self, key, payload, left=Leaf, right=Leaf):
self.left = left
self.right = right
self.key = key
self.payload = payload
def search(self, key):
if key < self.key:
return self.left.search(key)
elif key > self.key:
return self.right.search(key)
else:
return self.payload
is_leaf = property(lambda: false)
Example usage:
>>> tree = Node(2, 'bar', Node(1, 'foo'), Node(3, 'baz')) >>> tree.search(1) 'foo' >>> tree.search(4) Traceback (most recent call last): ... KeyError: 2
Contributing
This project uses Poetry. To contribute to the codebase, make sure to install poetry, With Poetry installed, clone then repo, then within the repo directory, install the developer dependencies:
$ poetry install --extras varname
Next, I recommend you do all development tasks within the poetry shell:
$ poetry shell (sentinel-nUnrocCf-py3.9) $ black . (sentinel-nUnrocCf-py3.9) $ pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file sentinel-0.3.0a1.tar.gz
.
File metadata
- Download URL: sentinel-0.3.0a1.tar.gz
- Upload date:
- Size: 6.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.4 CPython/3.9.1 Linux/5.4.0-1032-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6d7168563466572fcd7e19db46091013a1f85e7c02e0b8cf601c1286d9987e63 |
|
MD5 | 3ec3ac151f8897c71c6213da53048a2c |
|
BLAKE2b-256 | 4925701117b8d57631cccbebb4ea991578ef4988bf39218a303c86ea937484fd |
File details
Details for the file sentinel-0.3.0a1-py3-none-any.whl
.
File metadata
- Download URL: sentinel-0.3.0a1-py3-none-any.whl
- Upload date:
- Size: 6.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.4 CPython/3.9.1 Linux/5.4.0-1032-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2cb17f4821a32cdda29422df7da34ba67b489d252e53fee9b1ab1cef48139be0 |
|
MD5 | c408856e402a2a6d72e4cf0491ea6984 |
|
BLAKE2b-256 | bc08f0bc71e922aaf2dc1b65b2a1869d247a32411413a7cf4be3babf821a137c |