Skip to content

Commit

Permalink
Return Fired rules actions results.
Browse files Browse the repository at this point in the history
  • Loading branch information
slitayem committed Apr 18, 2016
1 parent 6c79036 commit cca9e16
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 4 deletions.
2 changes: 2 additions & 0 deletions business_rules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
__version__ = '1.0.1'

from .engine import run_all
from .engine import run_all_with_results
from .utils import export_rule_data

# Appease pyflakes by "using" these exports
assert run_all
assert run_all_with_results
assert export_rule_data
60 changes: 56 additions & 4 deletions business_rules/engine.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from .fields import FIELD_NO_INPUT


def run_all(rule_list,
defined_variables,
defined_actions,
stop_on_first_trigger=False):

rule_was_triggered = False
for rule in rule_list:
result = run(rule, defined_variables, defined_actions)
Expand All @@ -14,6 +14,40 @@ def run_all(rule_list,
return True
return rule_was_triggered


def run_all_with_results(rule_list, defined_variables, defined_actions,
stop_on_first_trigger=False):
'''Run all Rules and return the rules actions results
Returns:
rule_results(list): list of dictionaries. Each dictionary is a rule
actions' results
'''
rule_results = []
for rule in rule_list:
actionsResults = run_and_get_results(rule, defined_variables,
defined_actions)
if actionsResults:
rule_results.append(actionsResults)
if stop_on_first_trigger:
return rule_results
return rule_results


def run_and_get_results(rule, defined_variables, defined_actions):
'''Run the rule and get the action returned result
Attributes:
rule(dict): the rule dictionary
defined_variables(BaseVariables): the defined set of variables object
defined_actions(BaseActions): the actions object
'''
actions_results = {}
conditions, actions = rule.get('conditions'), rule.get('actions')
if conditions and actions:
rule_triggered = check_conditions_recursively(conditions, defined_variables)
if rule_triggered:
actions_results = do_actions(actions, defined_actions)
return actions_results

def run(rule, defined_variables, defined_actions):
conditions, actions = rule['conditions'], rule['actions']
rule_triggered = check_conditions_recursively(conditions, defined_variables)
Expand Down Expand Up @@ -68,6 +102,7 @@ def fallback(*args, **kwargs):
val = method()
return method.field_type(val)


def _do_operator_comparison(operator_type, operator_name, comparison_value):
""" Finds the method on the given operator_type and compares it to the
given comparison_value.
Expand All @@ -86,11 +121,28 @@ def fallback(*args, **kwargs):


def do_actions(actions, defined_actions):
''' Run the actions
Attributes:
actions(list): list of dictionaries of actions. e.g: [
{ "name": "put_on_sale",
"params": {"sale_percentage": 0.25},
}
]
Returns:
actionsResults(dict): Dictionary of actions results
e.g: {"put_on_sale: [product1, product2, ...]}
'''
actions_results = {}
for action in actions:
method_name = action['name']

def fallback(*args, **kwargs):
raise AssertionError("Action {0} is not defined in class {1}"\
.format(method_name, defined_actions.__class__.__name__))
raise AssertionError(
"Action {0} is not defined in class {1}".format(method_name,
defined_actions.__class__.__name__))

params = action.get('params') or {}
method = getattr(defined_actions, method_name, fallback)
method(**params)
actions_results[method_name] = method(**params)
return {method_name: result for method_name, result in
actions_results.iteritems() if result}
61 changes: 61 additions & 0 deletions tests/test_get_actions_results.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from business_rules.actions import BaseActions, rule_action
from business_rules.fields import FIELD_TEXT
from business_rules.variables import BaseVariables, boolean_rule_variable
from business_rules.engine import run_all_with_results
from . import TestCase


class ActionsResultsClassTests(TestCase):
""" Test methods on getting fired rules actions results
"""
def test_get_actions_results(self):
class SomeVariables(BaseVariables):
@boolean_rule_variable
def this_is_rule_1(self):
return True

@boolean_rule_variable
def this_is_rule_2(self):
return False

class SomeActions(BaseActions):

@rule_action(params={'foo':FIELD_TEXT})
def some_action_1(self, foo):
return foo

@rule_action(params={'foobar':FIELD_TEXT})
def some_action_2(self, foobar):
return foobar

@rule_action()
def some_action_3(self):
pass

rule1 = {'conditions': {'all': [
{
'name': 'this_is_rule_1',
'value': True,
'operator': 'is_true'
}]},
'actions': [
{'name': 'some_action_1',
'params': {'foo': 'fooValue'}
}]}
rule2 = {'conditions': {'all': [
{
'name': 'this_is_rule_2',
'value': True,
'operator': 'is_false'
}]},
'actions': [
{'name': 'some_action_2',
'params': {'foobar': 'foobarValue'}
},
{'name': 'some_action_3'
}]}

variables = SomeVariables()
actions = SomeActions()
result = run_all_with_results([rule1, rule2], variables, actions)
self.assertEqual(result, [{'some_action_1': 'fooValue'}, {'some_action_2': 'foobarValue'}])

0 comments on commit cca9e16

Please sign in to comment.