# -*- coding: utf-8 -*-
"""
This module provides ready-to-use classes for constructing custom constants.
"""
from candv.base import (Constant as SimpleConstant,
ConstantsContainer as _BaseContainer)
[docs]class VerboseMixin(object):
"""
Provides support of verbose names and help texts. Must be placed at the
left side of non-mixin base classes due to Python's MRO. Arguments must be
passed as kwargs.
:argument str verbose_name: optional verbose name
:argument str help_text: optional description
**Example**::
class Foo(object):
def __init__(self, arg1, arg2, kwarg1=None):
pass
class Bar(VerboseMixin, Foo):
def __init__(self, arg1, arg2, verbose_name=None, help_text=None, kwarg1=None):
super(Bar, self).__init__(arg1, arg2, verbose_name=verbose_name, help_text=help_text, kwarg1=kwarg1)
"""
def __init__(self, *args, **kwargs):
self.verbose_name = kwargs.pop('verbose_name', None)
self.help_text = kwargs.pop('help_text', None)
super(VerboseMixin, self).__init__(*args, **kwargs)
[docs] def merge_into_group(self, group):
"""
Redefines :meth:`~candv.base.Constant.merge_into_group` and adds
``verbose_name`` and ``help_text`` attributes to the target group.
"""
super(VerboseMixin, self).merge_into_group(group)
group.verbose_name = self.verbose_name
group.help_text = self.help_text
[docs]class VerboseConstant(VerboseMixin, SimpleConstant):
"""
Constant with optional verbose name and optional description.
: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(VerboseConstant, self).__init__(verbose_name=verbose_name,
help_text=help_text)
[docs]class Constants(_BaseContainer):
"""
Simple container for any :class:`~candv.base.Constant` or it's subclass.
This container can be used as enumeration.
**Example**::
>>> from candv import Constants, SimpleConstant
>>> class USER_ROLES(Constants):
... ADMIN = SimpleConstant()
... ANONYMOUS = SimpleConstant()
...
>>> USER_ROLES.ADMIN
<constant 'USER_ROLES.ADMIN'>
>>> USER_ROLES.get_by_name('ANONYMOUS')
<constant 'USER_ROLES.ANONYMOUS'>
"""
#: Set :class:`~candv.base.Constant` as top-level class for this container.
#: See :attr:`~candv.base.ConstantsContainer.constant_class`.
constant_class = SimpleConstant
[docs]class ValueConstant(SimpleConstant):
"""
Extended version of :class:`SimpleConstant` which provides support for
storing values of constants.
:argument value: a value to attach to constant
:ivar value: constant's value
"""
def __init__(self, value):
super(ValueConstant, self).__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(ValueConstant, self).merge_into_group(group)
group.value = self.value
[docs]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: optional verbose name of the constant
:argument str help_text: 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(VerboseValueConstant, self).__init__(value,
verbose_name=verbose_name,
help_text=help_text)
[docs]class Values(_BaseContainer):
"""
Constants container which supports getting and filtering constants by their
values, listing values of all constants in container.
"""
#: Set :class:`ValueConstant` as top-level class for this container.
#: See :attr:`~candv.base.ConstantsContainer.constant_class`.
constant_class = ValueConstant
@classmethod
[docs] def get_by_value(cls, value):
"""
Get constant by its value.
:param value: value of the constant to look for
:returns: first found constant with given value
:raises ValueError: if no constant in container has given value
"""
for constant in cls.iterconstants():
if constant.value == value:
return constant
raise ValueError("Value '{0}' is not present in '{1}'".format(
value, cls.__name__))
@classmethod
[docs] 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
@classmethod
[docs] def values(cls):
"""
List values of all constants in the order they were defined.
:returns: :class:`list` of values
**Example**::
>>> from candv import Values, ValueConstant
>>> class FOO(Values):
... TWO = ValueConstant(2)
... ONE = ValueConstant(1)
... SOME = ValueConstant("some string")
...
>>> FOO.values()
[2, 1, 'some string']
"""
return [x.value for x in cls.iterconstants()]
@classmethod
[docs] def itervalues(cls):
"""
Same as :meth:`values` but returns an interator.
"""
for constant in cls.iterconstants():
yield constant.value
[docs]class Choices(_BaseContainer):
"""
Container of instances of :class:`VerboseConstant` and it's subclasses.
Provides support for building `Django-compatible <https://docs.djangoproject.com/en/1.6/ref/models/fields/#choices>`_
choices.
"""
#: Set :class:`VerboseConstant` as top-level class for this container.
#: See :attr:`~candv.base.ConstantsContainer.constant_class`.
constant_class = VerboseConstant
@classmethod
[docs] def choices(cls):
"""
Get a tuple of tuples representing constant's name and its verbose name.
:returns: a tuple of constant's names and their verbose names in order
they were defined.
**Example**::
>>> from candv import Choices, VerboseConstant
>>> class FOO(Choices):
... ONE = VerboseConstant("first", help_text="first choice")
... FOUR = VerboseConstant("fourth")
... THREE = VerboseConstant("third")
...
>>> FOO.choices()
(('ONE', 'first'), ('FOUR', 'fourth'), ('THREE', 'third'))
>>> FOO.get_by_name('ONE').help_text
'first choice'
"""
return tuple((name, x.verbose_name) for name, x in cls.items())