import functools
import operator
import inspect
from typing import Callable, Any, Dict, List
class Rule:
def __init__(self, func: Callable[[Dict[str, Any]], bool], name: str = None):
self.func = func
self.name = name or func.__name__
def __call__(self, context: Dict[str, Any]) -> bool:
return self.func(context)
def __and__(self, other: "Rule") -> "Rule":
return Rule(lambda ctx: self(ctx) and other(ctx),
name=f"({self.name} AND {other.name})")
def __or__(self, other: "Rule") -> "Rule":
return Rule(lambda ctx: self(ctx) or other(ctx),
name=f"({self.name} OR {other.name})")
def __invert__(self) -> "Rule":
return Rule(lambda ctx: not self(ctx),
name=f"(NOT {self.name})")
class RuleEngine:
def __init__(self):
self.rules: List[Rule] = []
def register(self, rule: Rule):
self.rules.append(rule)
def evaluate(self, context: Dict[str, Any]) -> Dict[str, bool]:
results = {}
for rule in self.rules:
try:
results[rule.name] = rule(context)
except Exception as e:
results[rule.name] = False
return results
def auto_rule(fn):
sig = inspect.signature(fn)
def wrapper(ctx):
bound = {k: ctx.get(k) for k in sig.parameters}
return fn(**bound)
return Rule(wrapper, name=fn.__name__)
@auto_rule
def is_adult(age):
return age >= 18
@auto_rule
def high_income(income):
return income > 5000
@auto_rule
def country_allowed(country):
return country in {"CL", "MX", "CO"}
engine = RuleEngine()
engine.register(is_adult & high_income | country_allowed)
engine.register(~high_income & is_adult)
context = {"age": 25, "income": 3000, "country": "CL"}
print(engine.evaluate(context))
Comments
0 B
|👍
/👎
0 B
|👍
/👎