A lightweight, optionally typed expression language with a custom grammar for matching arbitrary Python objects.
npx @tessl/cli install tessl/pypi-rule-engine@4.5.0A lightweight, optionally typed expression language with a custom grammar for matching arbitrary Python objects. Rule Engine provides a powerful system for evaluating custom expressions against Python data structures with type safety, error handling, and extensibility.
pip install rule-engineimport rule_engineCommon import pattern for main classes:
from rule_engine import Rule, Context, DataTypeAll functionality is available from the main module:
from rule_engine import (
Rule, Context, DataType,
resolve_attribute, resolve_item, type_resolver_from_dict,
EngineError, RuleSyntaxError, EvaluationError
)import rule_engine
# Basic rule creation and evaluation
rule = rule_engine.Rule('first_name == "Luke" and age > 18')
data = {'first_name': 'Luke', 'last_name': 'Skywalker', 'age': 25}
# Check if data matches the rule
if rule.matches(data):
print("Match found!")
# Filter a collection of objects
people = [
{'first_name': 'Luke', 'age': 25},
{'first_name': 'Leia', 'age': 25},
{'first_name': 'Han', 'age': 32}
]
adults = list(rule.filter(people))
print(f"Found {len(adults)} adults")
# Using typed context for type safety
context = rule_engine.Context(
type_resolver=rule_engine.type_resolver_from_dict({
'first_name': rule_engine.DataType.STRING,
'age': rule_engine.DataType.FLOAT
})
)
typed_rule = rule_engine.Rule('first_name + " is " + str(age)', context=context)
result = typed_rule.evaluate(data)
print(result) # "Luke is 25"Rule Engine uses a multi-layered architecture:
The design enables flexible symbol resolution, optional type safety, thread safety, and extensibility for custom contexts and resolvers.
The fundamental rule evaluation system including rule creation, matching, filtering, and expression evaluation. These operations form the foundation of the rule engine's functionality.
class Rule:
def __init__(self, rule_text: str, context: Context = None): ...
def matches(self, thing, **kwargs) -> bool: ...
def filter(self, things, **kwargs): ...
def evaluate(self, thing, **kwargs): ...
@property
def text(self) -> str: ...
@property
def context(self) -> Context: ...Context management system for controlling how symbols are resolved and type checking is performed. Includes custom resolver functions and type validation.
class Context:
def __init__(self, type_resolver=None, resolver=None, default_value=None): ...
def resolve(self, name: str, object_instance=None): ...
def resolve_attribute(thing, name: str): ...
def resolve_item(thing, name: str): ...
def type_resolver_from_dict(dictionary: dict): ...Comprehensive type system with DataType constants for all supported data types, type checking utilities, and type coercion functions.
class DataType:
ARRAY: DataType
BYTES: DataType
BOOLEAN: DataType
DATETIME: DataType
FLOAT: DataType
FUNCTION: DataType
MAPPING: DataType
NULL: DataType
SET: DataType
STRING: DataType
TIMEDELTA: DataType
UNDEFINED: DataType
@classmethod
def from_name(cls, name: str): ...
@classmethod
def from_type(cls, python_type): ...
@classmethod
def from_value(cls, python_value): ...
@classmethod
def is_compatible(cls, dt1, dt2) -> bool: ...Hierarchical exception system covering syntax errors, evaluation errors, type mismatches, and symbol resolution failures with detailed error information and suggestions.
class EngineError(Exception): ...
class EvaluationError(EngineError): ...
class RuleSyntaxError(EngineError): ...
class SymbolResolutionError(EvaluationError): ...
class AttributeResolutionError(EvaluationError): ...Rule Engine supports a rich expression language with:
Rule Engine is designed to be thread-safe. Rule objects can be shared across threads, and evaluation operations are safe for concurrent use. Context objects and type resolvers are also thread-safe.
Rule Engine includes an interactive debug REPL for experimentation:
python -m rule_engine.debug_replThe REPL provides: