c108.sentinels
Sentinel objects for distinguishing between unset values, None, and other states.
This module provides a set of singleton sentinel objects that can be used to represent special states in function arguments, data structures, and control flow. All sentinels use identity checks (using 'is') rather than equality checks.
Sentinels
- UNSET: Represents an unprovided optional argument (distinguishes from None)
- MISSING: Marks uninitialized or missing values in data structures
- DEFAULT: Signals use of internal/calculated default value
- NOT_FOUND: Indicates failed lookup operations (alternative to None)
- STOP: Signals termination in iterators, queues, or producers/consumers
Helper Functions
- ifunset: Return default if value is UNSET, otherwise return value
- ifnotmissing: Return default if value is MISSING, otherwise return value
- ifnotdefault: Return default if value is DEFAULT, otherwise return value
- iffound: Return default if value is NOT_FOUND, otherwise return value
- ifnotstop: Return default if value is STOP, otherwise return value
Examples:
>>> from c108.sentinels import UNSET, NOT_FOUND
>>> def get_default_timeout() -> int:
... return 30
...
>>> def ifnotunset(value, default):
... return default if value is UNSET else value
...
>>> def fetch_data(timeout=UNSET):
... timeout = ifnotunset(timeout, default=get_default_timeout())
... return {"timeout": timeout}
...
>>> fetch_data()
{'timeout': 30}
>>> cache = {"a": 1}
>>> key = "b"
>>> result = cache.get(key, NOT_FOUND)
>>> if result is NOT_FOUND:
... result = "computed"
...
>>> result
'computed'
DefaultType = create_sentinel_type('DEFAULT', is_truthy=True)
module-attribute
Sentinel type for DEFAULT.
Signals that a function should use its internal or calculated default value.
MissingType = create_sentinel_type('MISSING')
module-attribute
Sentinel type for MISSING.
Used to mark a value as not yet defined in a data structure, such as an uninitialized dataclass field or missing dictionary key.
NotFoundType = create_sentinel_type('NOT_FOUND')
module-attribute
Sentinel type for NOT_FOUND.
Return value for lookup operations that fail, where None might be ambiguous. Provides an alternative to raising exceptions in performance-critical code.
StopType = create_sentinel_type('STOP')
module-attribute
Sentinel type for STOP.
Used in iterators, queues, and producers/consumers to signal termination.
UnsetType = create_sentinel_type('UNSET')
module-attribute
Sentinel type for UNSET.
Used to distinguish between 'not provided' and 'explicitly set to None'. This is the most common sentinel for optional function arguments.
DEFAULT = DefaultType()
module-attribute
Sentinel signaling use of internal default value.
Useful when you need to distinguish between "use this specific default" and "calculate/use the standarddefault".
MISSING = MissingType()
module-attribute
Sentinel representing an uninitialized or missing value.
Commonly used in data validation libraries and ORMs to distinguish between "field not provided" and "field set to None".
NOT_FOUND = NotFoundType()
module-attribute
Sentinel representing a failed lookup operation.
Useful for cache lookups, dictionary searches, or any operation where None is a valid stored value but you need to signal absence.
STOP = StopType()
module-attribute
Sentinel signaling termination in iterators or queues.
Particularly useful in multi-threaded contexts where None might be a legitimate queue item.
UNSET = UnsetType()
module-attribute
Sentinel representing an unprovided optional argument.
Use with identity check: if arg is UNSET:
This is particularly useful when None is a valid input value.
SentinelBase
Base class for sentinel objects.
Sentinels are singleton objects optimized for identity checks. They provide clean representations and consistent behavior.
Source code in c108/sentinels.py
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | |
__bool__()
Returns False by default (sentinels are typically falsy).
Source code in c108/sentinels.py
78 79 80 | |
__eq__(other)
Ensures identity-based comparison.
Source code in c108/sentinels.py
70 71 72 | |
__hash__()
Returns a hash based on object identity.
Source code in c108/sentinels.py
74 75 76 | |
__reduce__()
Prevent pickling of sentinels.
Source code in c108/sentinels.py
82 83 84 85 86 87 | |
__repr__()
Returns a clean string representation for debugging.
Source code in c108/sentinels.py
66 67 68 | |
create_sentinel_type(name, is_truthy=False)
Factory function to create singleton sentinel types.
This method allows creating new sentinels with unified behavior like UNSET, MISSING, etc. provided by c108.sentinels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the sentinel (e.g., "UNSET", "MISSING", "PENDING") |
required |
is_truthy
|
bool
|
Whether the sentinel should evaluate to True in boolean context. Default is False (falsy). Set to True for sentinels that represent a "present" or "active" state. |
False
|
Returns:
| Type | Description |
|---|---|
Type[SentinelBase]
|
A new sentinel type class with singleton behavior. |
Example
Create a custom sentinel for async operations::
PendingType = create_sentinel_type("PENDING")
PENDING: Final[PendingType] = PendingType()
async def fetch_data():
result = PENDING
# ... async operation ...
return result if result is not PENDING else None
Create a sentinel that's truthy::
ActiveType = create_sentinel_type("ACTIVE", is_truthy=True)
ACTIVE: Final[ActiveType] = ActiveType()
if ACTIVE: # Evaluates to True
print("This will print")
Use in function signatures::
TimeoutType = create_sentinel_type("TIMEOUT")
TIMEOUT: Final[TimeoutType] = TimeoutType()
def wait_for(timeout=TIMEOUT):
if timeout is TIMEOUT:
# Use default timeout logic
pass
Source code in c108/sentinels.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
iffound(value, *, default=None, default_factory=None)
Return value if it's not NOT_FOUND, otherwise return default.
This helper is useful for lookup operations where None might be a valid stored value, so you need a separate sentinel to indicate "not found".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The value to check. If not NOT_FOUND, this value is returned. |
required |
default
|
Any
|
The fallback value when value is NOT_FOUND. |
None
|
default_factory
|
Callable[[], Any] | None
|
Callable returning the fallback value. Takes precedence over default. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The value itself if not NOT_FOUND, otherwise the default (or result of default_factory). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If both default and default_factory are provided. |
Example
cache = {"a": 1} result = cache.get("x", NOT_FOUND) result = iffound(result, default=0) result 0
Source code in c108/sentinels.py
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | |
ifnotdefault(value, *, default=None, default_factory=None)
Return value if it's not DEFAULT, otherwise return default.
This helper is useful when you want to allow users to explicitly request the default behavior by passing DEFAULT, while still accepting custom values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The value to check. If not DEFAULT, this value is returned. |
required |
default
|
Any
|
The fallback value when value is DEFAULT. |
None
|
default_factory
|
Callable[[], Any] | None
|
Callable returning the fallback value. Takes precedence over default. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The value itself if not DEFAULT, otherwise the default (or result of default_factory). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If both default and default_factory are provided. |
Example
def process(mode: str | DefaultType = DEFAULT): ... mode = ifnotdefault(mode, default='auto') ... return mode process('manual') 'manual' process(DEFAULT) 'auto'
Source code in c108/sentinels.py
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | |
ifnotmissing(value, *, default=None, default_factory=None)
Return value if it's not MISSING, otherwise return default.
This helper is useful for data validation and handling uninitialized fields in data structures where you need to distinguish "not provided" from None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The value to check. If not MISSING, this value is returned. |
required |
default
|
Any
|
The fallback value when value is MISSING. |
None
|
default_factory
|
Callable[[], Any] | None
|
Callable returning the fallback value. Takes precedence over default. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The value itself if not MISSING, otherwise the default (or result of default_factory). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If both default and default_factory are provided. |
Example
data = {"x": 1} field = data.get('optional_field', MISSING) ifnotmissing(field, default=0) 0
Source code in c108/sentinels.py
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | |
ifnotnone(value, *, default=None, default_factory=None)
Return value if it's not None, otherwise return default.
This helper is useful for providing fallback values when a variable might be None. When the value is None, it falls back to the default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The value to check. If not None, this value is returned. |
required |
default
|
Any
|
The fallback value when value is None. |
None
|
default_factory
|
Callable[[], Any] | None
|
Callable returning the fallback value. Takes precedence over default. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The value itself if not None, otherwise the default (or result of default_factory). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If both default and default_factory are provided. |
Example
def get_config(timeout: int | None = None): ... timeout = ifnotnone(timeout, default=30) ... return timeout get_config() 30 get_config(60) 60 get_config(None) 30
Source code in c108/sentinels.py
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | |
ifnotstop(value, *, default=None, default_factory=None)
Return value if it's not STOP, otherwise return default.
This helper is useful in iterators, queues, and producer-consumer patterns where you need to signal termination without using None or exceptions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The value to check. If not STOP, this value is returned. |
required |
default
|
Any
|
The fallback value when value is STOP. |
None
|
default_factory
|
Callable[[], Any] | None
|
Callable returning the fallback value. Takes precedence over default. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The value itself if not STOP, otherwise the default (or result of default_factory). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If both default and default_factory are provided. |
Example
from queue import Queue queue = Queue() queue.put(0) queue.put(STOP) while (item := ifnotstop(queue.get(), default=None)) is not None: ... print(item) 0
Source code in c108/sentinels.py
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | |
ifnotunset(value, *, default=None, default_factory=None)
Return value if it's not UNSET, otherwise return default.
This helper is useful for handling optional parameters where None is a valid value. When the value is UNSET (not provided), it falls back to the default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The value to check. If not UNSET, this value is returned. |
required |
default
|
Any
|
The fallback value when value is UNSET. |
None
|
default_factory
|
Callable[[], Any] | None
|
Callable returning the fallback value. Takes precedence over default. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The value itself if not UNSET, otherwise the default (or result of default_factory). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If both default and default_factory are provided. |
Example
def configure(timeout: int | None = UNSET): ... timeout = ifnotunset(timeout, default=30) ... return timeout configure() 30 configure(60) 60 configure(None) # Returns None
Source code in c108/sentinels.py
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | |