"""
Provides extra ready-to-use classes for constructing custom constants.
"""
import operator
from .core import Constants
from .core import SimpleConstant
from .exceptions import CandvValueNotFoundError
from ._utils import export
[docs]@export
class VerboseMixin:
"""
Adds ``verbose_name`` and ``help_text`` attributes to constants.
Arguments must be passed as kwargs.
:argument str verbose_name: optional verbose name
:argument str help_text: optional description
**Example**:
.. code-block:: python
class CustomConstant(object):
def __init__(self, arg1, arg2, kwarg1=None):
pass
class VerboseCustomConstant(VerboseMixin, CustomConstant):
def __init__(self, arg1, arg2, kwarg1=None, verbose_name=None, help_text=None):
super().__init__(
arg1,
arg2,
kwarg1=kwarg1,
verbose_name=verbose_name,
help_text=help_text,
)
"""
def __init__(self, *args, **kwargs):
self.verbose_name = kwargs.pop('verbose_name', None)
self.help_text = kwargs.pop('help_text', None)
super().__init__(*args, **kwargs)
[docs] def merge_into_group(self, group):
"""
Overrides :meth:`~candv.base.Constant.merge_into_group` to add
``verbose_name`` with ``help_text`` attributes to the target group.
"""
super().merge_into_group(group)
group.verbose_name = self.verbose_name
group.help_text = self.help_text
[docs] def to_primitive(self, *args, **kwargs):
"""
.. versionchanged:: 1.5.0
The ``context`` param is replaced by ``*args`` and ``**kwargs``.
.. versionadded:: 1.3.0
"""
primitive = super().to_primitive(*args, **kwargs)
primitive.update({
'verbose_name': (
str(self.verbose_name)
if self.verbose_name is not None
else None
),
'help_text': (
str(self.help_text)
if self.help_text is not None
else None
),
})
return primitive
[docs]@export
class VerboseConstant(VerboseMixin, SimpleConstant):
"""
A constant with optional verbose name and optional help text.
:argument str verbose_name: optional verbose name of the constant
:argument str help_text: optional description of the constant
:ivar str verbose_name: verbose name of the constant. Default: ``None``
:ivar str help_text: verbose description of the constant. Default: ``None``
"""
def __init__(self, verbose_name=None, help_text=None):
super().__init__(verbose_name=verbose_name, help_text=help_text)
[docs]@export
class ValueConstant(SimpleConstant):
"""
A constant with ability to hold arbitrary values.
:argument value: a value to attach to constant
:ivar value: constant's value
"""
def __init__(self, value):
super().__init__()
self.value = value
[docs] def merge_into_group(self, group):
"""
Redefines :meth:`~candv.base.Constant.merge_into_group` and adds ``value``
attribute to the target group.
"""
super().merge_into_group(group)
group.value = self.value
[docs] def to_primitive(self, *args, **kwargs):
"""
.. versionchanged:: 1.5.0
The ``context`` param is replaced by ``*args`` and ``**kwargs``.
.. versionadded:: 1.3.0
"""
primitive = super().to_primitive(*args, **kwargs)
value = self.value
if hasattr(value, "isoformat"):
value = value.isoformat()
if hasattr(value, "to_primitive"):
value = value.to_primitive(*args, **kwargs)
elif callable(value):
value = value()
primitive['value'] = value
return primitive
[docs]@export
class VerboseValueConstant(VerboseMixin, ValueConstant):
"""
A constant which can have both verbose name, help text, and a value.
:argument value: a value to attach to the constant
:argument str verbose_name: an optional verbose name of the constant
:argument str help_text: an optional description of the constant
:ivar value: constant's value
:ivar str verbose_name: verbose name of the constant. Default: ``None``
:ivar str help_text: verbose description of the constant. Default: ``None``
"""
def __init__(self, value, verbose_name=None, help_text=None):
super().__init__(value, verbose_name=verbose_name, help_text=help_text)
[docs]@export
class Values(Constants):
"""
A container for :class:`ValueConstant` and its derivatives.
Supports getting and filtering constants by their values plus listing values
of all constants in container.
"""
constant_class = ValueConstant
[docs] @classmethod
def get_by_value(cls, value):
"""
Get a constant by its value.
:param value: value of the constant to look for
:returns: first found constant with given value
:raises CandvValueNotFoundError: if no constant in container has given value
"""
for constant in cls.iterconstants():
if constant.value == value:
return constant
raise CandvValueNotFoundError(
"constant with value \"{0}\" is not present in \"{1}\""
.format(value, cls)
)
[docs] @classmethod
def filter_by_value(cls, value):
"""
Get all constants which have given value.
:param value: value of the constants to look for
:returns: list of all found constants with given value
"""
constants = []
for constant in cls.iterconstants():
if constant.value == value:
constants.append(constant)
return constants
[docs] @classmethod
def values(cls):
"""
List values of all constants in the order they were defined.
:returns: :class:`list` of values
**Example**:
.. code-block:: python
from candv import Values
from candv import ValueConstant
class FOO(Values):
TWO = ValueConstant(2)
ONE = ValueConstant(1)
SOME = ValueConstant("some string")
.. code-block:: python
>>> FOO.values()
[2, 1, 'some string']
.. note::
Overrides :meth:`~candv.base.ConstantsContainer.values` since 1.1.2.
"""
return [
x.value
for x in cls.iterconstants()
]
[docs] @classmethod
def itervalues(cls):
"""
Get an iterator over values of all constants in the order they were defined.
Same as :meth:`values` but returns an interator.
.. note::
Overrides :meth:`~candv.base.ConstantsContainer.itervalues` since 1.1.2.
"""
return map(operator.attrgetter("value"), cls.iterconstants())