Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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))
Advertisement