1. Dive in

How often do you need to define names which can be treated as constants? How about grouping them into something integral? What about giving names and descriptions for your constants? Attaching values to them? Do you need to find constants by their names or values? What about combining groups of constants into an hierarchy? And finally, how do you imagine documenting process of this all?

1.1. Simple example

Well, if you have ever asked yourself one of these questions, this library may answer you. Just look:

>>> from candv import Constants, SimpleConstant
>>> class BAR(Constants):
...     """
...     This is an example container of named constants.
...     """
...     ONE = SimpleConstant()
...     TWO = SimpleConstant()
...     NINE = SimpleConstant()

Let’s see some stuff. What’s BAR?

>>> BAR
<constants container 'BAR'>
>>> BAR.name
>>> BAR.full_name

What constants does it have? What’s their order?

>>> BAR.names()
['ONE', 'TWO', 'NINE']

What are those constants?

>>> BAR.constants()
[<constant 'BAR.ONE'>, <constant 'BAR.TWO'>, <constant 'BAR.NINE'>]
>>> BAR.items()
[('ONE', <constant 'BAR.ONE'>), ('TWO', <constant 'BAR.TWO'>), ('NINE', <constant 'BAR.NINE'>)]

How much constants are there in the container?

>>> len(BAR)

Does BAR have a constant named ONE?

>>> BAR.has_name('ONE')
>>> 'ONE' in BAR

How to get a constant by name?

>>> BAR['TWO']
<constant 'BAR.TWO'>

How to get a constant by name with fallback to default value?

>>> BAR.get('XXX', default=123)

How to access a single constant?

<constant 'BAR.ONE'>

What attributes does it have?

>>> BAR.ONE.name
>>> BAR.ONE.full_name
>>> BAR.ONE.container
<constants container 'BAR'>

1.2. Complex example

Was it too simple for you? Watchout:

>>> from candv import (
...     Constants, Values, SimpleConstant, VerboseConstant, ValueConstant,
...     VerboseValueConstant,
... )
>>> class FOO(Constants):
...     """
...     Example container of constants which shows the diversity of the library.
...     """
...     #: just a named constant
...     ONE = SimpleConstant()
...     #: named constant with verbose name
...     BAR = VerboseConstant("bar constant")
...     #: named constant with verbose name and description
...     BAZ = VerboseConstant(verbose_name="baz constant",
...                           help_text="description of baz constant")
...     #: named constant with value
...     QUX = ValueConstant(4)
...     #: another named constant with another value (list)
...     SOME = ValueConstant(['1', 4, True])
...     #: yet another named constant with another value, verbose name and description
...     SOME_VERBOSE = VerboseValueConstant("some value",
...                                         "some string",
...                                         "this is just some string")
...     #: named group of constants with values
...     GROUP = SimpleConstant().to_group(Values,
...         SIX=ValueConstant(6),
...         SEVEN=ValueConstant("S373N"),
...     )
...     #: subgroup with name, value and verbose name
...     MEGAGROUP = VerboseValueConstant(
...         value=100500,
...         verbose_name="megagroup"
...     ).to_group(Values,
...         HEY=ValueConstant(1),
...         #: group inside another group. How deep can you go?
...         YAY=ValueConstant(2).to_group(Constants,
...             OK=SimpleConstant(),
...             ERROR=SimpleConstant(),
...         ),
...     )

Whew! This looks like a big mess, but it shows all tasty things in one place. If you need something simple, you can have it.

Let’s try to investigate this example.

At first, what do we have?

>>> FOO
<constants container 'FOO'>
>>> FOO.name
>>> FOO.full_name

What’s inside?

>>> FOO.names()

What are all these things?

>>> FOO.constants()
[<constant 'FOO.ONE'>, <constant 'FOO.BAR'>, <constant 'FOO.BAZ'>, <constant 'FOO.QUX'>, <constant 'FOO.SOME'>, <constant 'FOO.SOME_VERBOSE'>, <constants group 'FOO.GROUP'>, <constants group 'FOO.MEGAGROUP'>]

Okay, we’ve seen SimpleConstant in action. What is VerboseConstant?

<constant 'FOO.BAZ'>
>>> FOO.BAZ.name
>>> FOO.BAZ.full_name
>>> FOO.BAZ.verbose_name
'baz constant'
>>> FOO.BAZ.help_text
'description of baz constant'

Yes, verbose constants can carry name and description for humans.

What about ValueConstant?

<constant 'FOO.QUX'>
>>> FOO.QUX.name
>>> FOO.QUX.full_name
>>> FOO.QUX.value

How about adding verbosity to values?

<constant 'FOO.SOME_VERBOSE'>
'some value'
>>> FOO.SOME_VERBOSE.verbose_name
'some string'
>>> FOO.SOME_VERBOSE.help_text
'this is just some string'

What is a group?

<constants group 'FOO.GROUP'>
>>> FOO.GROUP.name
>>> FOO.GROUP.full_name

It’s a constant!

>>> FOO.GROUP.constant_class
<class 'candv.ValueConstant'>
>>> FOO.GROUP.names()
['SIX', 'SEVEN']
>>> FOO.GROUP.constants()
[<constant 'FOO.GROUP.SIX'>, <constant 'FOO.GROUP.SEVEN'>]
>>> FOO.GROUP.values()
[6, 'S373N']
>>> FOO.GROUP.get_by_value(6)
<constant 'FOO.GROUP.SIX'>

And it’s a container! Groups, like photons, have dual nature: they are both constants and containers according to your needs.

Can we attach values and other stuff to groups? Surely!

>>> FOO.MEGAGROUP.verbose_name
>>> FOO.MEGAGROUP.names()
['HEY', 'YAY']

Can groups contain nested groups? Yes, they can:

<constants group 'FOO.MEGAGROUP.YAY'>
>>> FOO.MEGAGROUP.YAY.full_name
['OK', 'ERROR']

Visit hierarchies section for more info about groups.

1.3. Any real examples?

Yeah. There are some real public examples. See some examples.

In most cases you will be satisfied with standard facilities of the libraries. But you are not limited. You can create your own containers and constants. Examples mentioned above also may help you with this.

And of course, instead of a thousand words you can dig around tests.


By the way, verbose names taste more sweet if you use verboselib for I18N (or any other suitable for you mechanism).