Evaluate rules based on a subject
Project description
Python Simple Rules Engine
Evaluate rules based on a subject.
Install
pip install python_simple_rules_engine
Usage
The package expects a subject and a list of rules.
Each rule must be a class that extends AbstractRule
.
The subject
parameter can be any type of object (Any
)
Basic usage
Rules return a Evaluation
object that should contain a result
property defined by the user.
Also, the user can define the value of the stop
property to determine if the evaluation process should stop or continue.
In this example, the stop
property value does not affect the evaluation process since we are evaluating only one rule.
from python_simple_rules_engine import AbstractRule, Evaluation, run
class FooRule(AbstractRule):
def evaluate(self, subject, previous_evaluation: Evaluation = None) -> Evaluation:
return Evaluation({
'stop': False, # False by default. When set to True, the evaluation process is stopped.
'result': (subject == 'foo') # Any. It should contain the evaluation result defined by the user.
})
evaluation = run('foo', [FooRule()])
print(evaluation.result) # True
print(evaluation.rule) # FooRule instance
Advanced usage
When evaluating multiple rules you can retrieve the historic of rules evaluated for a specific evaluation process by passing the with_history
parameter as True
.
The final Evaluation
object will contain a history
list with evaluations returned by the rules evaluated during the evaluation process.
Check test_evaluation_with_history
method on tests/test_python_simple_rules_engine.py
for a more detailed implementation.
rules = [RuleA(), RuleB(), RuleC()]
# Let's pretend that the final evaluation comes from RuleC()
evaluation = run('C', rules, with_history=True)
print(len(evaluation.history)) # 2
print(evaluation.history[0].rule) # RuleA instance
print(evaluation.history[1].rule) # RuleB instance
Examples
The examples are very simple for demo purposes, but they show the basic features this package comes with.
There is another python rules engine called durable rules that comes with some examples. We will recreate them with this package.
Pattern matching
Find a credit card type based on its number.
Check test_match_example_with_cards
method on tests/test_python_simple_rules_engine.py
for a more detailed implementation.
class Card():
def __init__(self, number):
self.number = number
amex = Card('375678956789765')
visa = Card('4345634566789888')
mastercard = Card('2228345634567898')
class AmexRule(AbstractRule):
def evaluate(self, subject, previous_evaluation: Evaluation = None) -> Evaluation:
card_type = None
if re.match(r"3[47][0-9]{13}", subject.number):
card_type = 'amex'
return Evaluation({'stop': (card_type != None), 'result': card_type})
class VisaRule(AbstractRule):
def evaluate(self, subject, previous_evaluation: Evaluation = None) -> Evaluation:
card_type = None
if re.match(r"4[0-9]{12}([0-9]{3})?", subject.number):
card_type = 'visa'
return Evaluation({'stop': (card_type != None), 'result': card_type})
class MasterCardRule(AbstractRule):
def evaluate(self, subject, previous_evaluation: Evaluation = None) -> Evaluation:
card_type = None
if re.match(r"(5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|2720)[0-9]{12}", subject.number):
card_type = 'mastercard'
return Evaluation({'stop': (card_type != None), 'result': card_type})
# rules order does not affect the result.
rules = [AmexRule(), VisaRule(), MasterCardRule()]
evaluation = run(amex, rules)
print(evaluation.result) # 'amex'
print(evaluation.rule.__class__.__name__) # 'AmexRule'
evaluation = run(visa, rules)
print(evaluation.result) # 'visa'
print(evaluation.rule.__class__.__name__) # 'VisaRule'
evaluation = run(mastercard, rules)
print(evaluation.result) # 'mastercard'
print(evaluation.rule.__class__.__name__) # 'MasterCardRule'
Set of facts
Define the type of an animal based on facts.
In this case, we will compare the current rule result with the previous evaluation result. If they match, we stop the evaluation process.
Check test_facts_example
method on tests/test_python_simple_rules_engine.py
for a more detailed implementation.
class Animal():
def __init__(self, eats, lives, color):
self.eats = eats
self.lives = lives
self.color = color
frog = Animal('flies', 'water', 'green')
bird = Animal('worms', 'nest', 'black')
class EatsRule(AbstractRule):
facts = {'flies': 'frog', 'worms': 'bird'}
def evaluate(self, subject, previous_evaluation: Evaluation = None) -> Evaluation:
previous_result = previous_evaluation.result if previous_evaluation is not None else None
current_result = self.facts[getattr(subject, 'eats')]
return Evaluation({'stop': (previous_result == current_result), 'result': current_result})
class LivesRule(AbstractRule):
facts = {'water': 'frog', 'nest': 'bird'}
def evaluate(self, subject, previous_evaluation: Evaluation = None) -> Evaluation:
previous_result = previous_evaluation.result if previous_evaluation is not None else None
current_result = self.facts[getattr(subject, 'lives')]
return Evaluation({'stop': (previous_result == current_result), 'result': current_result})
class ColorRule(AbstractRule):
facts = {'green': 'frog', 'black': 'bird'}
def evaluate(self, subject, previous_evaluation: Evaluation = None) -> Evaluation:
previous_result = previous_evaluation.result if previous_evaluation is not None else None
current_result = self.facts[getattr(subject, 'color')]
return Evaluation({'stop': (previous_result == current_result), 'result': current_result})
# rules order does not affect the result.
rules = [EatsRule(), ColorRule(), LivesRule()]
evaluation = run(frog, rules)
print(evaluation.result) # 'frog'
evaluation = run(bird, rules)
print(evaluation.result) # 'bird'
License
This project is open-sourced software licensed under the MIT license.
Project details
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 python_simple_rules_engine-1.0.0.tar.gz
.
File metadata
- Download URL: python_simple_rules_engine-1.0.0.tar.gz
- Upload date:
- Size: 5.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.13
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 239f89f312c536e145a8c1149586a76a50b2ae235ef1a7a0d155b643b7492f1e |
|
MD5 | 7afa192afced1c040a22ab399e88cf3a |
|
BLAKE2b-256 | 4c82e17ee2aaca7593cac134f3fe64c2b4657a1e1f6fbe4d342220e0a0ae0406 |
File details
Details for the file python_simple_rules_engine-1.0.0-py3-none-any.whl
.
File metadata
- Download URL: python_simple_rules_engine-1.0.0-py3-none-any.whl
- Upload date:
- Size: 5.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.13
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7de3ce3d615d92424837c9867a10a5652bf829e23da7927ec03575a1842b8b3b |
|
MD5 | f6a6c6bbfa2dd1c95fd2d07bedc8aa97 |
|
BLAKE2b-256 | 69591e818cb3d25c7fd96e35374b4eb6139f5470011ce794ccb8d4c2f5ff0f14 |