An expression evaluation engine for Python applications that makes complex logical expressions readable and maintainable.
- Business rules
- Data validation
- Authorisation checks
- Data filtering
- Formulas and calculations
Given context data like this:
---
project:
status: review
signoffs:
- user:
name: Alice Chen
role: Audit
timestamp: '2025-10-07T10:30:00Z'
- user:
name: Bob Smith
role: Audit
timestamp: '2025-10-07T14:20:00Z'
- user:
name: Carol Wong
role: Audit
timestamp: '2025-10-08T09:15:00Z'
- user:
name: Dave Johnson
role: Legal
timestamp: '2025-10-07T16:45:00Z'
documents:
- name: contract.pdf
verified: true
- name: financials.xlsx
verified: true
- name: legal_review.docx
verified: trueInstead of writing an expression like this:
// Complex JavaScript approach
audit_signoffs.filter((signoff) => {
return signoff.user.role == 'Audit' && new Date(signoff.timestamp) < new Date()
}).length >= 3
&& 'status' in project
&& project.status == 'review'
&& documents.filter((doc) => doc.verified).length === documents.lengthYour users can express the business rules like this:
// dilemma expression language
at least 3 of signoffs matches | user.role == 'Audit' and timestamp is $past |
and project has 'status' and project.status == 'review'
and all of documents matches | verified == true |For array operations, instead of complex function calls:
count_of(orders, `status == 'pending'`) >= 3 and any_of(orders, `total > 1000`)User can enjoy a more natural language:
at least 3 of orders matches |status == 'pending'| and any of orders matches |total > 1000|- Secure evaluation - No arbitrary code execution, only safe expressions
- Rich data access - Navigate nested dictionaries and lists with ease
- Date/time operations - Natural language date comparisons
- Multiple resolvers - JsonPath, JQ, and basic dictionary lookup
- Performance optimized - Compile expressions once, evaluate many times
- Type safe - Built-in type checking and validation
pip install dilemmafrom dilemma import evaluate
# Basic arithmetic and logic
result = evaluate("2 * (3 + 4)") # Returns 14
result = evaluate("age >= 18 and status == 'active'", {"age": 25, "status": "active"})
# Natural language array operations
result = evaluate("at least 2 of users matches | status == 'active' |", context)
result = evaluate("none of orders matches | amount > 1000 |", context)
# Date operations
result = evaluate("user.last_login upcoming within 7 days", context)
result = evaluate("subscription.end_date is $future", context)
# Complex data access
result = evaluate("user.permissions contains 'admin'", context)
result = evaluate("`[.users[] | select(.active == true) | .name] | length` > 0", context)All Language Features. Extensive Examples.
# Dot notation for nested objects
"user.profile.settings.theme == 'dark'"
# Natural possessive syntax
"user's subscription's status == 'premium'"
# Array/list access
"users[0].name == 'Alice'"
# Check membership
"'admin' in user.roles"
"user.permissions contains 'read'"
# Check property existence
" user has 'address' and 'Mesters Vig' in user.address"Dilemma provides intuitive sugar syntax for common array operations:
# Quantity-based checks
"at least 3 of orders matches | status == 'shipped' |"
"at most 2 of users matches | role == 'admin' |"
"exactly 1 of servers matches | status == 'maintenance' |"
# Existence checks
"any of products matches | price > 100 |"
"all of users matches | email_verified == true |"
"none of alerts matches | severity == 'critical' |"
# Combined with other operations
"at least 5 of reviews matches | rating >= 4 | and user.subscription is $active"
"any of files matches |name like '*.pdf'| and all of files matches |size < 10000000|"# Relative time checks
"user.created_at upcoming within 30 days"
"order.shipped_date older than 1 week"
# State comparisons
"subscription.expires is $future"
"last_backup is $past"
"meeting.date is $today"
# Date comparisons
"start_date before end_date"
"event.date same_day_as $now"For complex data manipulation, use JQ expressions in backticks:
# Filter and transform arrays - working with provided context
evaluate('`[.users[] | select(.active == true) | .name]`', context)
# Mathematical operations on arrays
evaluate('`[.sales[].amount] | add` > 10000', context)
# Complex conditionals
evaluate('`[.products[] | select(.price > 100 and .category == "electronics")] | length` > 1', context)For repeated evaluations, compile expressions once:
from dilemma import compile_expression
# Compile once - including array sugar syntax
eligibility_check = compile_expression(
"user.age >= 18 and user.subscription.active and at least 1 of user.orders matches | status == 'completed' |"
)
# Evaluate many times with different contexts
for user_data in users:
if eligibility_check.evaluate(user_data):
# send_premium_content(user_data)
passIf evaluating multiple expressions against the same data, use ProcessedContent instead of passing in a dictionary of values. This saves the json dump/load cycle that Dilemma uses to sanitize data.
from dilemma import evaluate, ProcessedContext
# Sample data
data = {
"users": [
{"name": "Alice", "age": 30, "active": True},
{"name": "Bob", "age": 25, "active": False},
{"name": "Charlie", "age": 35, "active": True}
],
"threshold": 28
}
# Process the data once for safety and optimization
context = ProcessedContext(data)
# Evaluate multiple expressions efficiently
expressions = [
"users[0].name == 'Alice'", # True
"users[1].age < threshold", # True
"users[2].active", # True
"any_of(users, `active`)" # True
]
for expr in expressions:
result = evaluate(expr, context)
print(f"{expr} = {result}")Dilemma provides clear, actionable error messages:
try:
result = evaluate("user.invalidfield == 'test'", context)
except VariableError as e:
print(f"Expression error: {e}")
# Suggests available fields and common fixes- Form validation rules -
"email like '*@*' and age >= 13" - Business logic -
"order.total > 100 and customer.tier == 'premium'" - Access control -
"user.roles contains 'admin' or resource.owner == user.id" - Data filtering -
"created_at upcoming within 24 hours and status == 'pending'" - Workflow conditions -
"approval.status == 'approved' and budget.remaining >= cost" - Quality assurance -
"all of tests match |status == 'passed'| and none of builds match |errors > 0|" - Inventory management -
"at least 10 of products match |stock > 0| and any of suppliers match |delivery_time < 3|" - Security monitoring -
"none of login_attempts match |failed_count > 5| and all of sessions match |encrypted == true|"
- ✅ No arbitrary Python code execution
- ✅ No access to imports or builtins
- ✅ Sandboxed evaluation environment
- ✅ Input validation and sanitization
- ✅ Memory and complexity limits
MIT License - see LICENSE file for details.