traversalkit.condition

The module provides condition descriptors of routes.

Condition

class traversalkit.condition.Condition

Base class for condition.

The class provides implementation of some syntactic sugar:

>>> Condition() & Condition()
And(Condition(), Condition())

>>> Condition() | Condition()
Or(Condition(), Condition())

>>> ~Condition()
Not(Condition())

Derived class should only override __call__() method.

__call__(route)

Test route against the condition.

Parameters:route (Route) – Route to test.
Returns:The result of test, i.e. True if given route complies the condition, or False otherwise.
Return type:bool
Raises:NotImplementedError – If not overridden.

And

class traversalkit.condition.And(left, rigth)

Utility class to concatenate wrapped conditions by logical AND.

It does not have to be used directly. Use & operator instead:

>>> Condition() & Condition()
And(Condition(), Condition())
Parameters:

Or

class traversalkit.condition.Or(left, rigth)

Utility class to concatenate wrapped conditions by logical OR.

It does not have to be used directly. Use | operator instead:

>>> Condition() | Condition()
Or(Condition(), Condition())
Parameters:

Not

class traversalkit.condition.Not(condition)

Utility class to negate wrapped condition.

It does not have to be used directly. Use ~ operator instead:

>>> ~Condition()
Not(Condition())
Parameters:condition (Condition) – Condition to negate.

Under

class traversalkit.condition.Under(*parents)

Test that route contains specified parents.

Parameters:*parents (Resource,str) –

List of resource classes or resource names.

The following example describes simple blog with two sections of posts: published ones and drafts. Published post can contain comments section, but draft cannot. This restriction is done using Under condition negated by Not (i.e. ~ operator).

>>> from traversalkit import Resource, DEC_ID

>>> class Blog(Resource):
...     ''' Blog root resource '''

>>> @Blog.mount('posts')   # Published posts can contain comments
... @Blog.mount('drafts')  # Draft posts cannot contain comments
... class Posts(Resource):
...     ''' Blog posts collection '''

>>> @Posts.mount_set(DEC_ID, metaname='post_id')
... class Post(Resource):
...     ''' Blog post '''

>>> @Post.mount('comments', complies=~Under('drafts'))
... class Comments(Resource):  #     ^^^^^^^^^^^^^^^^
...     ''' Comments collection '''

>>> blog = Blog()
>>> blog['posts']['1']['comments']
<Comments: /posts/1/comments/>

>>> blog['drafts']['2']['comments']  # DOCTEST: +ellipsis
Traceback (most recent call last):
...
KeyError: ('comments', '/drafts/2/')

>>> for route in Blog.routes():
...     print(route)
<Route: />
<Route: /drafts/>
<Route: /drafts/{post_id}/>
<Route: /posts/>
<Route: /posts/{post_id}/>
<Route: /posts/{post_id}/comments/>

Recursion

class traversalkit.condition.Recursion(maxdepth)

Test that route does not go deeper than specified recursion depth.

Parameters:maxdepth (int) – Maximum recursion depth.

The following example describes categories tree. Where collection resource Categories contains item resource Category, which again contains collection Categories. To restrict this endless route Recursion condition is used with maximum depth of 2.

>>> from traversalkit import Resource, DEC_ID

>>> class Categories(Resource):
...     ''' Categories collection '''

>>> @Categories.mount_set(DEC_ID, metaname='category_id')
... class Category(Resource):
...     ''' Category resource '''

>>> Category.mount(
...     'categories', Categories,
...     complies=Recursion(maxdepth=2),
...     #        ^^^^^^^^^^^^^^^^^^^^^
... )   # DOCTEST: +ellipsis
<class ...

>>> tree = Categories()
>>> tree['1']['categories']['2']
<Category: /1/categories/2/>

>>> tree['1']['categories']['2']['categories']  # DOCTEST: +ellipsis
Traceback (most recent call last):
...
KeyError: ('categories', '/1/categories/2/')

>>> for route in Categories.routes():
...     print(route)
<Route: />
<Route: /{category_id}/>
<Route: /{category_id}/categories/>
<Route: /{category_id}/categories/{category_id}/>