Chainee is a simple chaining tool for your predicates.
Chain any number of predicates as deep as you want, and visualize it.
pip install --user chainee
Everything is based on P
object (from chainee import P
), you simply wrap your predicates with P
and start chaining it. E.g:
from chainee import P
def validate_name_length(name):
"""Check that name has at least 4 characters"""
return len(name) > 3
def validate_name_lower(name):
"""Make sure that name is in lower case"""
return name.islower()
chain = P(validate_name_length) & P(validate_name_lower)
print(chain("yaroslav")) # True
As you can see, it's very easy and readable.
You can achieve any nesting level, the following is possible:
chain = ~((P(validate_name_length) & ~P(validate_name_lower)) | (P(validate_name_length) & P(validate_name_lower)))
You have a few operators you can use, &
(and), |
(or) and ~
(not).
Basically that's all Chainee gets you, which is quite enough.
You can build a tree from your chain. Let's build a tree for the chain above:
>>> print(chain)
InvertedUnion(union=UnionOr(lhs=UnionAnd(lhs=Predicate(func=<function validate_name_length at 0x10fa4f160>, description='Check that name has at least 4 characters'), rhs=InvertedPredicate(func=<function validate_name_lower at 0x10fbcb8b0>, description='Make sure that name is in lower case')), rhs=UnionAnd(lhs=Predicate(func=<function validate_name_length at 0x10fa4f160>, description='Check that name has at least 4 characters'), rhs=Predicate(func=<function validate_name_lower at 0x10fbcb8b0>, description='Make sure that name is in lower case'))))
# note that doc strings copied into description
Now, lets build an actual tree:
>>> tree = chain.to_tree()
>>> print(tree)
NOT
└── OR
├── AND
│ ├── Predicate(validate_name_lower)
│ └── Predicate(validate_name_length)
└── AND
├── NOT Predicate(validate_name_lower)
└── Predicate(validate_name_length)
You can convert it into a picture as well:
>>> tree.to_picture("tree.png")