A rules engine to clarify your pipelines development
Project description
rulesengine
Is there any developer liking to work with hundreds of chained if/else? If you're one of those this package isn't for you.
A rules engine is a way to structure your code as pipelines. The objective is to create chained modular and reusable rules with a simple structure structure :
- A
filter
: can I do some stuff? - An
action
: I know I can do some stuff so I do it
With a rules engine you have to think your pipeline has stackable modules to generate easily readable pipelines.
Example with some potatoes
Here is an example on how to (try to) eat smashed potatoes:
# How to eat smashed potatoes
rules = RulesEngine()
rules.add(GetPotatoes)
rules.add(CookPotatoes)
rules.add(EatPotatoes)
rules.add(SmashPotatoes)
rules.add(EatSmashedPotatoes)
rules_output = rules.run()
rules_ouput.get("Eaten smashed potatoes portions") # Sorry there is nothing
With a pipeline like this one, you won't eat any smashed potatoes but you'll
still have eaten some potatoes (if GetPotatoes
got you at least one potato).
Let's see the SmashPotatoes
rule to understand:
class SmashPotatoes(Rule):
RULE_NAME = "Smash potatoes"
def filter(self, input_data):
"""
Can I really smash potatoes?
"""
# Get my smashable potatoes
smashable_potatoes = input_data.get("cooked potatoes")
# Have I any smashable potatoes ?
if smashable_potatoes is None or smashable_potatoes < 1:
# There isn't any potato to smash. We won't do any thing...
return False
# YES! We can smash potatoes!!!
return True
def action(self, input_data):
"""
Let's smash potatoes because we can
"""
# Get you potatoes
smashable_potatoes = input_data.get("cooked potatoes")
# Do your job (an other RulesEngine?)
smashed_potatoes_portions = ...
input_data.set("smashed potatoes portions", smashed_potatoes_portions)
input_data.set("cooked potatoes", 0)
In this rule if the filter isn't applied, we won't apply the action :
- No
cooked potatoes
no action and finally nosmashed potatoes portions
- At least 1
cooked potatoes
, the action is performed and we have at least 1smashed potatoes portions
Installation
pip install rulesengine
Documentation & Help
Create a rule
from rulesengine import Rule
class MyRule(Rule):
RULE_NAME = "A minimal rule"
# An execution order (positive or -1). Rules of same level are executed in their
# declaration order. -1 are executed lastly and minimal values are executed firstly
RULE_ORDER = -1
def filter(self, input_data):
"""
Test if you can apply your rule, are all variables initialized?
"""
return True
def action(self, input_data):
"""
Do some stuff
"""
Access data
An object is passed between rules and returned by the RulesEngine.run()
method : RulesData
# Get an element (return None if not initialized)
my_data.get('my element key')
# Set or update an element
my_data.set('my element key', something)
# Delete an element (let's free some memory!)
my_data.delete('my element key')
# Get previously executed rule
my_data.get_previous()
# Set expected next rule
my_data.set_expected_next(MyNextRule.RULE_NAME)
Create pipeline
from rulesengine import RulesEngine
# Initialize the pipeline
rules = RulesEngine()
rules.add(MyRule, forced_order=0) # Will be executed first
rules.add(MyRule) # The same rule again
rules.add(AnOtherRule, previous_rule=MyNextRule.RULE_NAME) # Won't match the previous rule condition
rules.add(AnOtherRule, converter=a_funtion) # Sometime, to reuse rules we need to do extra stuff before the rule
rules_output = rules.run()
Pipelines doesn't have to be run to the end
from rulesengine import RulesCourse
# Run every runnable rules (default)
rules = RulesEngine(rules_course=RulesCourse.non_blocking)
# Stop on the first rules's filter returning False
rules = RulesEngine(rules_course=RulesCourse.block_on_false)
# Stop on the first rules's filter returning True
rules = RulesEngine(rules_course=RulesCourse.block_on_true)
# Raise an error on the first rules's filter returning False
rules = RulesEngine(rules_course=RulesCourse.error_on_false)
Populate the pipeline before execution
# At creation
rules = RulesEngine({
"data_1": 1,
"data_2": list(),
})
# afterward
rules.set(key, value)
Manage errors
There is only one rulesengine error : rulesengine.RulesEngineException
Contributing
As an open source project, rulesengine welcomes contributions of all forms (especially culinary but please don't send any potato, the smashing potato workflow will fail).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file rulesengine-1.0.1.tar.gz
.
File metadata
- Download URL: rulesengine-1.0.1.tar.gz
- Upload date:
- Size: 9.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2a3e801ffef917b323513b3971653b08ed01756e994ae58ddb4c19e33cfb20e2 |
|
MD5 | 163f58bf03eff8e6f3db5106bcd952dd |
|
BLAKE2b-256 | 8925f5bd7da5dfee2e199628c54537235cf6170d78945327ab2e5f9f14f4efc7 |
File details
Details for the file rulesengine-1.0.1-py3-none-any.whl
.
File metadata
- Download URL: rulesengine-1.0.1-py3-none-any.whl
- Upload date:
- Size: 8.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 501a0310f6ee7a1aa9e5df9eab69f6b72316a79fc53c203e256a77fa7c80a45c |
|
MD5 | fed73651343dfdbbde34a646efee62bf |
|
BLAKE2b-256 | d2440410c34b2e9cec7e04aca4804fe795f7cdea39b01b3e60f5534ecd850184 |