Package: python-simple-rules-engine
Python Simple Rules EngineEvaluate rules based on a subject.Installpipinstallpython_simple_rules_engineUsageThe package expects a subject and a list of rules.Each rule must be a class that extendsAbstractRule.Thesubjectparameter can be any type of object (Any)Basic usageRules return aEvaluationobject that should contain aresultproperty defined by the user.Also, the user can define the value of thestopproperty to determine if the evaluation process should stop or continue.In this example, thestopproperty value does not affect the evaluation process since we are evaluating only one rule.frompython_simple_rules_engineimportAbstractRule,Evaluation,runclassFooRule(AbstractRule):defevaluate(self,subject,previous_evaluation:Evaluation=None)->Evaluation:returnEvaluation({'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)# Trueprint(evaluation.rule)# FooRule instanceAdvanced usageWhen evaluating multiple rules you can retrieve the historic of rules evaluated for a specific evaluation process by passing thewith_historyparameter asTrue.The finalEvaluationobject will contain ahistorylist with evaluations returned by the rules evaluated during the evaluation process.Checktest_evaluation_with_historymethod ontests/test_python_simple_rules_engine.pyfor 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))# 2print(evaluation.history[0].rule)# RuleA instanceprint(evaluation.history[1].rule)# RuleB instanceExamplesThe examples are very simple for demo purposes, but they show the basic features this package comes with.There is another python rules engine calleddurable rulesthat comes with some examples. We will recreate them with this package.Pattern matchingFind a credit card type based on its number.Checktest_match_example_with_cardsmethod ontests/test_python_simple_rules_engine.pyfor a more detailed implementation.classCard():def__init__(self,number):self.number=numberamex=Card('375678956789765')visa=Card('4345634566789888')mastercard=Card('2228345634567898')classAmexRule(AbstractRule):defevaluate(self,subject,previous_evaluation:Evaluation=None)->Evaluation:card_type=Noneifre.match(r"3[47][0-9]{13}",subject.number):card_type='amex'returnEvaluation({'stop':(card_type!=None),'result':card_type})classVisaRule(AbstractRule):defevaluate(self,subject,previous_evaluation:Evaluation=None)->Evaluation:card_type=Noneifre.match(r"4[0-9]{12}([0-9]{3})?",subject.number):card_type='visa'returnEvaluation({'stop':(card_type!=None),'result':card_type})classMasterCardRule(AbstractRule):defevaluate(self,subject,previous_evaluation:Evaluation=None)->Evaluation:card_type=Noneifre.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'returnEvaluation({'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 factsDefine 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.Checktest_facts_examplemethod ontests/test_python_simple_rules_engine.pyfor a more detailed implementation.classAnimal():def__init__(self,eats,lives,color):self.eats=eatsself.lives=livesself.color=colorfrog=Animal('flies','water','green')bird=Animal('worms','nest','black')classEatsRule(AbstractRule):facts={'flies':'frog','worms':'bird'}defevaluate(self,subject,previous_evaluation:Evaluation=None)->Evaluation:previous_result=previous_evaluation.resultifprevious_evaluationisnotNoneelseNonecurrent_result=self.facts[getattr(subject,'eats')]returnEvaluation({'stop':(previous_result==current_result),'result':current_result})classLivesRule(AbstractRule):facts={'water':'frog','nest':'bird'}defevaluate(self,subject,previous_evaluation:Evaluation=None)->Evaluation:previous_result=previous_evaluation.resultifprevious_evaluationisnotNoneelseNonecurrent_result=self.facts[getattr(subject,'lives')]returnEvaluation({'stop':(previous_result==current_result),'result':current_result})classColorRule(AbstractRule):facts={'green':'frog','black':'bird'}defevaluate(self,subject,previous_evaluation:Evaluation=None)->Evaluation:previous_result=previous_evaluation.resultifprevious_evaluationisnotNoneelseNonecurrent_result=self.facts[getattr(subject,'color')]returnEvaluation({'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'LicenseThis project is open-sourced software licensed under theMIT license.Icons made byGregor Cresnarfromwww.flaticon.com