Fhernd

rule.py

Feb 21st, 2026
8,281
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 1.89 KB | Source Code | 0 0
  1. import functools
  2. import operator
  3. import inspect
  4. from typing import Callable, Any, Dict, List
  5.  
  6.  
  7. class Rule:
  8.     def __init__(self, func: Callable[[Dict[str, Any]], bool], name: str = None):
  9.         self.func = func
  10.         self.name = name or func.__name__
  11.  
  12.     def __call__(self, context: Dict[str, Any]) -> bool:
  13.         return self.func(context)
  14.  
  15.     def __and__(self, other: "Rule") -> "Rule":
  16.         return Rule(lambda ctx: self(ctx) and other(ctx),
  17.                     name=f"({self.name} AND {other.name})")
  18.  
  19.     def __or__(self, other: "Rule") -> "Rule":
  20.         return Rule(lambda ctx: self(ctx) or other(ctx),
  21.                     name=f"({self.name} OR {other.name})")
  22.  
  23.     def __invert__(self) -> "Rule":
  24.         return Rule(lambda ctx: not self(ctx),
  25.                     name=f"(NOT {self.name})")
  26.  
  27.  
  28. class RuleEngine:
  29.     def __init__(self):
  30.         self.rules: List[Rule] = []
  31.  
  32.     def register(self, rule: Rule):
  33.         self.rules.append(rule)
  34.  
  35.     def evaluate(self, context: Dict[str, Any]) -> Dict[str, bool]:
  36.         results = {}
  37.         for rule in self.rules:
  38.             try:
  39.                 results[rule.name] = rule(context)
  40.             except Exception as e:
  41.                 results[rule.name] = False
  42.         return results
  43.  
  44.  
  45. def auto_rule(fn):
  46.     sig = inspect.signature(fn)
  47.     def wrapper(ctx):
  48.         bound = {k: ctx.get(k) for k in sig.parameters}
  49.         return fn(**bound)
  50.     return Rule(wrapper, name=fn.__name__)
  51.  
  52.  
  53. @auto_rule
  54. def is_adult(age):
  55.     return age >= 18
  56.  
  57.  
  58. @auto_rule
  59. def high_income(income):
  60.     return income > 5000
  61.  
  62.  
  63. @auto_rule
  64. def country_allowed(country):
  65.     return country in {"CL", "MX", "CO"}
  66.  
  67.  
  68. engine = RuleEngine()
  69. engine.register(is_adult & high_income | country_allowed)
  70. engine.register(~high_income & is_adult)
  71.  
  72. context = {"age": 25, "income": 3000, "country": "CL"}
  73. print(engine.evaluate(context))
Advertisement