Skip to content

Sentinels

The sentinels module provides a mechanism for creating unique, singleton-like objects and enum-like values for use as special markers in Python code. Sentinels are useful for representing missing values, statuses, or other unique tokens that should not collide with regular data.


Why?

Sentinels are commonly used to indicate special states such as "missing", "pending", or "completed" in APIs, data structures, and function arguments. Using unique objects instead of regular values (like None or strings) avoids ambiguity and bugs.

Instead of manually creating singleton objects or using enums, the @sentinel decorator automates the creation of unique, immutable sentinel instances or enum-like classes.


Features

  • Single unique sentinel objects (e.g., MISSING)
  • Enum-like sentinel classes (e.g., STATUS.PENDING, STATUS.COMPLETED)
  • Guaranteed uniqueness (instances are singletons per name/module)
  • Pickle support (sentinels can be serialized and deserialized)
  • Automatic registry for all sentinels
  • Simple, type-safe API

Usage

Single Sentinel

from escudeiro.ds.sentinels import sentinel

@sentinel
class MISSING:
    pass

assert repr(MISSING) == "MISSING"
assert MISSING is sentinel(MISSING)  # Uniqueness guaranteed

Enum-like Sentinels

from escudeiro.ds.sentinels import sentinel

@sentinel
class STATUS:
    PENDING = 1
    COMPLETED = 2
    CANCELLED = "cancelled"

assert repr(STATUS.PENDING) == "1"
assert repr(STATUS.COMPLETED) == "2"
assert repr(STATUS.CANCELLED) == "'cancelled'"
assert STATUS.PENDING == 1
assert STATUS.COMPLETED == 2
assert STATUS.CANCELLED == "cancelled"

Uniqueness

@sentinel
class A:
    pass

@sentinel
class B:
    pass

assert A is not B

@sentinel
class STATUS_A:
    PENDING = 1

@sentinel
class STATUS_B:
    PENDING = 1

assert STATUS_A.PENDING is not STATUS_B.PENDING

Pickling Support

import pickle
from escudeiro.ds.sentinels import sentinel

@sentinel
class MISSING:
    pass

pickled = pickle.dumps(MISSING)
unpickled = pickle.loads(pickled)
assert unpickled is MISSING

Registry

All sentinels are registered in an internal registry:

from escudeiro.ds.sentinels import _registry, sentinel

@sentinel
class FIRST_CALL:
    pass

assert "your_module:FIRST_CALL" in _registry
assert _registry["your_module:FIRST_CALL"] is FIRST_CALL

API Reference

sentinel

def sentinel[T](cls: type[T]) -> T
  • Description: Decorator for creating unique sentinel objects or enum-like sentinel classes.
  • Parameters:
  • cls: The class to decorate.
  • Returns: A unique sentinel instance (if class is empty) or a new type with sentinel members.

Notes

  • Sentinel instances are always unique per name and module.
  • Enum-like sentinels allow for value comparison and identity checks.
  • Callable and dunder members are ignored when creating enum-like sentinels.
  • Use sentinels for missing values, statuses, or any special marker.

See Also