A high-performance rules engine for Python - evaluate data against configurable rules and get clear verdicts
Project description
pylitmus
A high-performance rules engine for Python. Like a litmus test for your data - evaluate against configurable rules and get clear verdicts.
Features
- YAML/JSON rule definitions - Business-friendly rule configuration
- Hot-reload - Rules can be updated without restart
- Multiple storage backends - Memory, database, file
- Caching - Redis and in-memory caching support
- Multiple scoring strategies - Sum, weighted, max
- Flask integration - Easy integration with Flask apps
- 18 built-in operators - Comparison, collection, string, null, temporal
- Extensible - Custom evaluators and strategies
Installation
pip install pylitmus
# With database support
pip install pylitmus[database]
# With Redis caching
pip install pylitmus[redis]
# With Flask integration
pip install pylitmus[flask]
# All extras
pip install pylitmus[all]
Quick Start
from pylitmus import create_engine, Rule, Severity
# Create engine with inline rules
engine = create_engine(rules=[
Rule(
code='AMT_001',
name='High Amount',
description='Flag high amounts',
category='AMOUNT',
severity=Severity.HIGH,
score=60,
enabled=True,
conditions={'field': 'amount', 'operator': 'greater_than', 'value': 5000}
)
])
# Evaluate data
result = engine.evaluate({'amount': 6000})
print(f"Score: {result.total_score}") # 60
print(f"Decision: {result.decision}") # FLAG
print(f"Triggered: {[r.rule_code for r in result.triggered_rules]}") # ['AMT_001']
YAML Rules
Define rules in YAML files for easy management:
# rules.yaml
rules:
- code: "AMT_001"
name: "High Amount"
description: "Flag transactions over $5000"
category: "AMOUNT"
severity: "HIGH"
score: 60
enabled: true
conditions:
field: "amount"
operator: "greater_than"
value: 5000
- code: "RISK_001"
name: "High Risk Country"
description: "Flag transactions from high-risk countries"
category: "RISK"
severity: "CRITICAL"
score: 80
enabled: true
conditions:
field: "country"
operator: "in"
value: ["XX", "YY", "ZZ"]
Load rules from file:
engine = create_engine(
storage_backend='file',
rules_file='rules.yaml'
)
Composite Conditions
Combine conditions with AND/OR logic:
conditions:
all: # AND
- field: "amount"
operator: "greater_than"
value: 1000
- any: # OR
- field: "is_new_customer"
operator: "equals"
value: true
- field: "country"
operator: "in"
value: ["NG", "KE", "GH"]
Or use the alternative format:
conditions:
type: "AND"
conditions:
- field: "amount"
operator: "greater_than"
value: 1000
- field: "is_international"
operator: "equals"
value: true
Available Operators
| Category | Operators |
|---|---|
| Comparison | equals, not_equals, greater_than, greater_than_or_equal, less_than, less_than_or_equal, between |
| Collection | in, not_in, contains, not_contains |
| String | starts_with, ends_with, matches_regex |
| Null | is_null, is_not_null |
| Temporal | within_days, before, after |
Scoring Strategies
Sum Strategy (Default)
Adds up all triggered rule scores, capped at 100.
engine = create_engine(scoring_strategy='sum')
Weighted Strategy
Uses severity-based weights (LOW=1, MEDIUM=2, HIGH=3, CRITICAL=4).
engine = create_engine(scoring_strategy='weighted')
Max Strategy
Takes the highest score from triggered rules.
engine = create_engine(scoring_strategy='max')
Decision Thresholds
Customize decision boundaries:
engine = create_engine(
decision_thresholds={
'approve': 30, # Score < 30 = APPROVE
'review': 70 # Score 30-70 = REVIEW, >= 70 = FLAG
}
)
Storage Backends
In-Memory
engine = create_engine(storage_backend='memory', rules=[...])
File-Based
engine = create_engine(
storage_backend='file',
rules_file='rules.yaml' # or rules.json
)
Database
engine = create_engine(
storage_backend='database',
database_url='postgresql://localhost/mydb'
)
Caching
Memory Cache
engine = create_engine(
cache_backend='memory',
cache_ttl=300 # 5 minutes
)
Redis Cache
engine = create_engine(
cache_backend='redis',
cache_url='redis://localhost:6379/0',
cache_ttl=600
)
No Cache
engine = create_engine(cache_backend='none')
Flask Integration
from flask import Flask
from pylitmus.integrations.flask import CmapRulesEngine, get_engine
app = Flask(__name__)
app.config['CMAP_RULES_FILE'] = 'rules.yaml'
rules_engine = CmapRulesEngine(app)
@app.route('/evaluate', methods=['POST'])
def evaluate():
data = request.json
engine = get_engine()
result = engine.evaluate(data)
return {
'score': result.total_score,
'decision': result.decision,
'triggered_rules': [r.rule_code for r in result.triggered_rules]
}
Nested Field Access
Access nested data using dot notation:
data = {
'transaction': {
'amount': 6000,
'merchant': {
'category': 'electronics'
}
}
}
# Rule condition
conditions:
field: "transaction.merchant.category"
operator: "equals"
value: "electronics"
Pattern Matching
Advanced pattern matching capabilities:
from pylitmus import EnhancedPatternEngine
pattern_engine = EnhancedPatternEngine()
# Regex matching
pattern_engine.add_pattern('email', r'^[\w.-]+@[\w.-]+\.\w+$', 'regex')
# Fuzzy matching
pattern_engine.add_pattern('name', 'John Smith', 'fuzzy', threshold=0.8)
# Range matching
pattern_engine.add_pattern('age', {'min': 18, 'max': 65}, 'range')
# Check matches
result = pattern_engine.match_all({
'email': 'user@example.com',
'name': 'Jon Smith',
'age': 25
})
API Reference
create_engine()
def create_engine(
storage_backend: str = 'memory',
database_url: str = None,
rules_file: str = None,
rules: List[Rule] = None,
repository: RuleRepository = None,
cache_backend: str = 'memory',
cache_url: str = None,
cache_ttl: int = 300,
scoring_strategy: str = 'sum',
decision_thresholds: Dict[str, int] = None,
) -> RuleEngine
RuleEngine.evaluate()
def evaluate(
self,
data: Dict[str, Any],
context: Dict[str, Any] = None,
filters: Dict[str, Any] = None
) -> AssessmentResult
AssessmentResult
@dataclass
class AssessmentResult:
total_score: int # Total calculated score
decision: str # APPROVE, REVIEW, or FLAG
triggered_rules: List[RuleResult] # Rules that matched
processing_time_ms: float # Processing time in ms
Full Example
from pylitmus import (
create_engine,
Rule,
Severity,
InMemoryRuleRepository,
WeightedStrategy,
)
# Define rules
rules = [
Rule(
code='AMT_HIGH',
name='High Amount',
description='Flag high-value transactions',
category='AMOUNT',
severity=Severity.HIGH,
score=60,
enabled=True,
conditions={'field': 'amount', 'operator': 'greater_than', 'value': 5000}
),
Rule(
code='NEW_CUSTOMER',
name='New Customer',
description='Flag new customer transactions',
category='CUSTOMER',
severity=Severity.MEDIUM,
score=30,
enabled=True,
conditions={'field': 'is_new_customer', 'operator': 'equals', 'value': True}
),
Rule(
code='INTL_TXN',
name='International Transaction',
description='Flag international transactions',
category='GEOGRAPHY',
severity=Severity.LOW,
score=20,
enabled=True,
conditions={'field': 'is_international', 'operator': 'equals', 'value': True}
),
]
# Create engine with weighted scoring
engine = create_engine(
rules=rules,
scoring_strategy='weighted',
decision_thresholds={'approve': 25, 'review': 60}
)
# Evaluate transaction
result = engine.evaluate({
'amount': 6000,
'is_new_customer': True,
'is_international': False
})
print(f"Total Score: {result.total_score}")
print(f"Decision: {result.decision}")
print(f"Triggered Rules: {[r.rule_code for r in result.triggered_rules]}")
print(f"Processing Time: {result.processing_time_ms:.2f}ms")
Documentation
License
MIT License - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pylitmus-1.1.0.tar.gz.
File metadata
- Download URL: pylitmus-1.1.0.tar.gz
- Upload date:
- Size: 53.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f282c469f51e23807bb050f183f941947451298715b2f5e9abc2c915b23d182
|
|
| MD5 |
b7b493ce33cf36e5c4d40519c008f9b3
|
|
| BLAKE2b-256 |
a9b0b89df08837e4e3073df1c150c32d0e6e0edc919b19eb05b4ca6346b3bb82
|
File details
Details for the file pylitmus-1.1.0-py3-none-any.whl.
File metadata
- Download URL: pylitmus-1.1.0-py3-none-any.whl
- Upload date:
- Size: 34.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e25a24b30634077d0ec67ebbab8fa7b61305625a33245e4d71ec290e0fdbe3ed
|
|
| MD5 |
524b47c0a32c95307b9686d06ce8c0cd
|
|
| BLAKE2b-256 |
3aa710992b7b800638ba26af0c3c2bec81e00feb792e994be9d6997b27e47972
|