skip to navigation
skip to content

tri.token 1.0.1

tri.token provides enriched enum functionality

tri.token
=========

tri.token provides enriched enum functionality. tri.token enum structures are declared using:

- TokenAttribute: overridable attribute definitions with support for dynamic values.
- Token: holds TokenAttributes objects.
- TokenContainer: holds Token objects.

In other words: a Token is an enum which has TokenInstance members. Token instances are declared within TokenContainer(s).


Basic usage
-----------

.. code:: python

from tri.token import Token, TokenAttribute, TokenContainer, PRESENT


class Taste(Token):
name = TokenAttribute()
display_name = TokenAttribute(value=lambda **kwargs: kwargs['name'].upper() + '!!')
opinion = TokenAttribute()


class Tastes(TokenContainer):
vanilla = Taste()
pecan_nut = Taste(display_name="pecan nutz", opinion="Tasty")


# A TokenContainer is a collection of Token objects.
assert Tastes.vanilla in Tastes

# The order of Token objects in a TokenContainer is by order of declaration.
assert list(Tastes) == [Tastes.vanilla, Tastes.pecan_nut]
assert list(Tastes) != [Tastes.pecan_nut, Tastes.vanilla]

# Magic for 'name' TokenAttribute. It is set automatically from the token declaration within it's container.
assert Tastes.vanilla.name == "vanilla"

# A TokenAttribute will have a None value if not set during Token instantiation.
assert Tastes.vanilla.opinion is None

# A TokenAttribute can have a dynamic value, derived from the invocation to the callable
# set as 'value' in the TokenAttribute definition
# (see declaration of 'display_name' TokenAttribute further up in the code).

# The real value of the token attribute will be the return value of an invocation to said callable.
# The invocation will receive the values of all other token attributes passed as keyword arguments.
assert Tastes.vanilla.display_name == "VANILLA!!"

# TokenAttribute dynamic value behavior is overridden/not used if value is set explicitly during Token instantiation.
assert Tastes.pecan_nut.display_name == "pecan nutz"

# A TokenContainer can be rendered as csv, excel, rst etc
assert """\
+--------------+---------+
| display_name | opinion |
+==============+=========+
| VANILLA!! | |
+--------------+---------+
| pecan nutz | Tasty |
+--------------+---------+\
""" == Tastes.to_rst(['display_name', 'opinion'])


Optional token attributes
-------------------------

.. code:: python

# A TokenAttribute may be declared as having optional dynamic values.
# That is, we want these dynamic attributes to be evaluated sometimes, but not always.
# In the example below, we want some superheroes to have homes, but not others.

SUPERHERO_HOMES = {'superman': 'Fortress of Solitude',
'batman': 'Batcave'}


class Superhero(Token):
name = TokenAttribute()
home = TokenAttribute(optional_value=lambda name, **_: SUPERHERO_HOMES[name])


# The PRESENT special value is used during Token instantiation to decide what
# optional token attributes should be evaluated.
class Superheroes(TokenContainer):
batman = Superhero(home=PRESENT)
hawkman = Superhero()
wonder_woman = Superhero(home='Themyscira')

# Batman has a home, but poor Hawkman does not.
assert Superheroes.batman.home == 'Batcave'
assert Superheroes.hawkman.home is None

# Just as with dynamic attributes, the logic for TokenAttribute optional dynamic values is overridden
if value is set explicitly during Token instantiation.
assert Superheroes.wonder_woman.home = 'Themyscira'

# As a shortcut, PRESENT for specific optional token attributes may be assigned to
# variables, and used in declarations, for enhanced readability.
# This is useful when one has tokens with many attributes declared using dynamic values,
# but we don't want all of them to be evaluated in all tokens.
home = PRESENT('home')

class Superheroes(TokenContainer):
batman = Superhero(home)
hawkman = Superhero()

# Again, Batman has a home, but poor Hawkman does not.
assert Superheroes.batman.home == 'Batcave'
assert Superheroes.hawkman.home is None


TokenAttribute inheritance
--------------------------

.. code:: python

class FooToken(Token):
foo = TokenAttribute(value=lambda **kwargs: 'foo_value')

class BarToken(Token):
bar = TokenAttribute()

class FieToken(FooToken, BarToken):
fie = TokenAttribute()

class FooBarFieTokenContainer(TokenContainer):
t = FieToken(fie=3)

assert dict(FooBarFieTokenContainer.t) == {'foo': 'foo_value', 'bar': None, 'name': 't', 'fie': 3}


TokenAttribute container inheritance
------------------------------------

.. code:: python

class MyToken(Token):

name = TokenAttribute()
stuff = TokenAttribute()


class MyTokens(TokenContainer):

foo = MyToken(stuff='Hello')
bar = MyToken(stuff='World')

assert MyTokens.foo in MyTokens

class MoreTokens(MyTokens):
boink = MyToken(stuff='Other Stuff')

assert MyTokens.foo in MoreTokens

assert list(MoreTokens) == [MyTokens.foo, MyTokens.bar, MoreTokens.boink]
assert MoreTokens.foo is MyTokens.foo


For more tri.token examples, please have a look at the contents of tests/test_tokens.py in the installation directory.

.. _test_tokens: tests/test_tokens.py


Running tests
-------------

You need tox installed then just `make test`.


License
-------

BSD


Documentation
-------------

http://tritoken.readthedocs.org.


Changelog
=========

1.0.1 (2017-04-05)
~~~~~~~~~~~~~~~~~~

* Changed metaclass handling to make PyCharm understand it


1.0.0 (2016-09-27)
~~~~~~~~~~~~~~~~~~

* First released version on github

* Added documentation

* Cleanup of build machinery


0.6.0 (2016-04-11)
~~~~~~~~~~~~~~~~~~

* Added documentation generation sort customisation

* Added python 3 support


0.5.0 (2016-02-01)
~~~~~~~~~~~~~~~~~~

* Move dependency tri.cache.memoize from requirements.txt to test_requirements.txt. It is only used
for regression testing.  
File Type Py Version Uploaded on Size
tri.token-1.0.1.tar.gz (md5) Source 2017-04-12 8KB