3. Usage¶
The main idea is that constants
are instances of
Constant
class (or its subclasses) and they are stored
inside subclasses of ConstantsContainer
class which are
called containers
.
Every constant has its own name which is equal to the name of container’s attribure they are assigned to. Every container is a singleton, i.e. you just nedd to define container’s class and use it. You are not permitted to create instances of containers. This is unnecessary. Containers have class methods for accessing constants in different ways.
Constants remember ther order they were defined inside container.
Constants may have custom attributes and methods. Containers may have custom class methods. See customization docs.
Constants may be converted into groups of constants providing ability to create different constant hierarchies (see Hierarchies).
3.1. Simple constants¶
Simple constants are really simple. They look like enumerations:
>>> from candv import SimpleConstant, Constants
>>> class STATUS(Constants):
... SUCCESS = SimpleConstant()
... FAILURE = SimpleConstant()
...
And they can be used just like enumerations. Here STATUS
is a subclass of
candv.Constants
. The latter can contain any instances of
Constant
class or its subclasses. SimpleConstant
is
just an alias to candv.base.Constant
.
Access some constant:
>>> STATUS.SUCCESS
<constant 'STATUS.SUCCESS'>
Access its name:
>>> STATUS.SUCCESS.name
'SUCCESS'
List names of all constants in the container:
>>> STATUS.names()
['SUCCESS', 'FAILURE']
List all constants in the container:
>>> STATUS.constants()
[<constant 'STATUS.SUCCESS'>, <constant 'STATUS.FAILURE'>]
Check whether the container has constant with a given name:
>>> STATUS.contains('SUCCESS')
True
>>> STATUS.contains('XXX')
False
Get constant by name or get a KeyError
:
>>> STATUS.get_by_name('FAILURE')
<constant 'STATUS.FAILURE'>
>>> STATUS.get_by_name('XXX')
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "candv/base.py", line 316, in get_by_name
.format(name, cls.__name__))
KeyError: "Constant with name 'XXX' is not present in 'STATUS'"
3.2. Constants with values¶
Constants with values behave like simple constants, except they can have any object attached to them as a value. It’s something like an ordered dictionary:
>>> from candv import ValueConstant, Values
>>> class TEAMS(Values):
... NONE = ValueConstant(0)
... RED = ValueConstant(1)
... BLUE = ValueConstant(2)
...
Here TEAMS
is a subclass of Values
, which is a more
specialized container than Constants
. As you may guessed,
ValueConstant
is a more specialized constant class than
SimpleConstant
and its instances have own values. Values
and its
subclasses treat as constants only instances of ValueConstant
or its
sublasses:
>>> class INVALID(Values):
... FOO = SimpleConstant()
... BAR = SimpleConstant()
...
Here INVALID
contains 2 instances of SimpleConstant
, which is more
gerenal then ValueConstant
. It’s not an error, but those 2 constants will
be invisible for the container:
>>> INVALID.constants()
[]
Ok, let’s get back to our TEAMS
. You can access values of constants:
>>> TEAMS.RED.value
1
Get constant by its value or get ValueError
:
>>> TEAMS.get_by_value(2)
<constant 'TEAMS.BLUE'>
>>> TEAMS.get_by_value(-1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "candv/__init__.py", line 146, in get_by_value
value, cls.__name__))
ValueError: Value '-1' is not present in 'TEAMS'
List all values inside the container:
>>> TEAMS.values()
[0, 1, 2]
If you have different constants with equal values, it’s OK anyway:
>>> class FOO(Values):
... ATTR1 = ValueConstant('one')
... ATTRX = ValueConstant('x')
... ATTR2 = ValueConstant('two')
... ATTR1_DUB = ValueConstant('one')
...
Here FOO.ATTR1
and FOO.ATTR1_DUB
have identical values. In this case
method get_by_value()
will return first constant with given
value:
>>> FOO.get_by_value('one')
<constant 'FOO.ATTR1'>
If you need to get all constants with same value, use
filter_by_value()
method instead:
>>> FOO.filter_by_value('one')
[<constant 'FOO.ATTR1'>, <constant 'FOO.ATTR1_DUB'>]
3.3. Verbose constants¶
How often do you do things like below?
>>> TYPE_FOO = 'foo'
>>> TYPE_BAR = 'bar'
>>> TYPES = (
... (TYPE_FOO, "Some foo constant"),
... (TYPE_BAR, "Some bar constant"),
... )
This is usually done to add verbose names to constants which you can use somewhere, e.g in HTML template:
<select>
{% for code, name in TYPES %}
<option value='{{ code }}'>{{ name }}</option>
{% endfor %}
</select>
Okay. How about adding help text? Extend tuples? Or maybe create some
TYPES_DESCRIPTIONS
tuple? How far can you go and how ugly can you make it?
Well, spare yourself from headache and use verbose constants
VerboseConstant
and VerboseValueConstant
:
>>> from candv import VerboseConstant, Constants
>>> class TYPES(Constants):
... foo = VerboseConstant("Some foo constant", "help")
... bar = VerboseConstant(verbose_name="Some bar constant",
... help_text="some help")
Here you can access verbose_name
and help_text
as attributes of
constants:
>>> TYPES.foo.verbose_name
'Some foo constant'
>>> TYPES.foo.help_text
'help'
Now you can rewrite your code:
<select>
{% for constant in TYPES.constants() %}
<option value='{{ constant.name }}' title='{{ constant.help_text }}'>{{ constant.verbose_name }}</option>
{% endfor %}
</select>
Same thing with values, just use VerboseValueConstant
:
>>> from candv import VerboseValueConstant, Values
>>> class TYPES(Values):
... FOO = VerboseValueConstant('foo', "Some foo constant", "help")
... BAR = VerboseValueConstant('bar', verbose_name="Some bar constant",
... help_text="some help")
...
>>> TYPES.FOO.value
'foo'
>>> TYPES.FOO.verbose_name
'Some foo constant'
>>> TYPES.FOO.help_text
'help'
Our sample HTML block will look almost the same, except value
attribute:
<select>
{% for constant in TYPES.constants() %}
<option value='{{ constant.value }}' title='{{ constant.help_text }}'>{{ constant.verbose_name }}</option>
{% endfor %}
</select>
3.4. Choices¶
If you are familiar with Django’s field choices
then you may find Choices
container helpful:
>>> class TYPES(Choices):
... FOO = VerboseConstant('Foooo')
... BAR = VerboseConstant('Barrr')
...
It accepts instances of VerboseConstant
class or its subclasses and can
build tuple of tuples with names and verbose names of constants:
>>> TYPES.choices()
(('FOO', 'Foooo'), ('BAR', 'Barrr'))
3.5. Hierarchies¶
candv library supports direct attaching of a group of constants to another constant to create hierarchies. A group can be created from any constant and any container can be used to store children. You may already saw this in introduction, but let’s examine simple example:
>>> from candv import Constants, SimpleConstant
>>> class TREE(Constants):
... LEFT = SimpleConstant().to_group(Constants,
... LEFT=SimpleConstant(),
... RIGHT=SimpleConstant(),
... )
... RIGHT = SimpleConstant().to_group(Constants,
... LEFT=SimpleConstant(),
... RIGHT=SimpleConstant(),
... )
...
Here the key point is to_group()
method which is
avaivable for every constant. It accepts class that will be used to construct
new container and any number of constant instances passed as keywords. You can
access any group as any usual constant and use it as any usual container at the
same time:
>>> TREE.LEFT.LEFT
<constant 'TREE.LEFT.LEFT'>
>>> TREE.RIGHT.names()
['LEFT', 'RIGHT']