#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------
# Copyright (c) Merchise Autrement [~º/~] and Contributors
# All rights reserved.
#
# This is free software; you can do what the LICENCE file allows you to.
#
"""Special logical values like Unset, Undefined, Ignored, Invalid, ...
All values only could be `True` or `False` but are intended in places where
`None` is expected to be a valid value or for special Boolean formats.
"""
SYMBOL = "symbol"
BOOLEAN = "boolean"
TIMEOUT = 2.0
[docs]class symbol(int, metaclass=MetaSymbol):
"""Instances are custom symbols.
Symbol instances identify uniquely a semantic concept by its name. Each
one has an ordinal value associated.
For example::
>>> ONE2MANY = symbol('ONE2MANY')
>>> ONE_TO_MANY = symbol('ONE2MANY')
>>> ONE_TO_MANY is ONE2MANY
True
"""
__slots__ = ()
def __new__(cls, name, value=None):
"""Get or create a new symbol instance.
:param name: String representing the internal name. `Symbol`:class:
instances are unique (singletons) in the context of this
argument. ``#`` and spaces are invalid characters to allow
comments.
:param value: Any value compatible with Python `bool` or `int` types.
`None` is used as a special value to create a value using the
name hash.
"""
from sys import intern as unique
name = unique(name)
if name:
if value is None:
value = hash(name)
res = cls._instances.get(name)
if res is None: # Create the new instance
if isinstance(value, int):
res = super().__new__(cls, value)
cls._instances[name] = res
else:
msg = 'instancing "{}" with name "{}" and incorrect ' 'value "{}" of type "{}"'
cn, vt = cls.__name__, type(value).__name__
raise TypeError(msg.format(cn, name, value, vt))
elif res != value: # Check existing instance
msg = 'value "{}" mismatch for existing instance: "{}"'
raise ValueError(msg.format(value, name))
return res
else:
raise ValueError("name must be a valid non empty string")
def __init__(self, *args, **kwds):
pass
def __repr__(self):
return symbol.nameof(self)
__str__ = __repr__
[docs]class boolean(symbol):
"""Instances are custom logical values (`True` or `False`).
Special symbols allowing only logical (False or True) values.
For example::
>>> true = boolean('true', True)
>>> false = boolean('false')
>>> none = boolean('false')
>>> unset = boolean('unset')
>>> class X:
... attr = None
>>> getattr(X(), 'attr') is not None
False
>>> getattr(X(), 'attr', false) is not false
True
>>> none is false
True
>>> false == False
True
>>> false == unset
True
>>> false is unset
False
>>> true == True
True
"""
__slots__ = ()
def __new__(cls, name, value=False):
"""Get or create a new symbol instance.
See `~Symbol.__new__`:meth: for information about parameters.
"""
return super().__new__(cls, name, bool(value))
def __getnewargs__(self):
cls = type(self)
name = next((key for key, obj in cls._instances.items() if obj is self))
return (name, bool(self))
# --- Special singleton values ---
#: False value, mainly for function parameter definitions, where None could
#: be a valid value.
Unset = boolean("Unset")
#: False value for local scope use or where ``Unset`` could be a valid value
Undefined = boolean("Undefined")
#: To be used in arguments that are currently ignored because they are being
#: deprecated. The only valid reason to use `Ignored` is to signal ignored
#: arguments in method's/function's signature
Ignored = boolean("Ignored")
#: To be used in functions resulting in a fail where False could be a valid
#: value.
Invalid = boolean("Invalid")
#: To be used as a mark for current context as a mechanism of comfort.
This = boolean("This", True)