Skip to main content

Dilemma Expression Language

CI codecov PyPI version Python 3.12+

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

Why Dilemma?

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: true

Instead 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.length

Your 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|

Features

  • 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

Quick Start

pip install dilemma
from 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)

Language Features

All Language Features. Extensive Examples.

Data Access Patterns

# 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"

Natural Language Array Operations

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|"

Date and Time Operations

# 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"

Advanced JQ Integration

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)

Performance Optimization

Same expression, multiple contexts

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)
        pass

Same data, multiple expressions

If 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}")

Error Handling

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

Use Cases

  • 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|"

Safety & Security

  • ✅ No arbitrary Python code execution
  • ✅ No access to imports or builtins
  • ✅ Sandboxed evaluation environment
  • ✅ Input validation and sanitization
  • ✅ Memory and complexity limits

Sponsors

RiskNodes AIRM Agentic Intelligence Risk Management

License

MIT License - see LICENSE file for details.

Metadata

Release files for dilemma 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dilemma 0.7.0
File Size Uploaded
dilemma-0.7.0.tar.gz 163.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dilemma 0.7.0
File Interpreter ABI Platform
dilemma-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 204.4 kB

Release files / dilemma-0.7.0.tar.gz

Download URL dilemma-0.7.0.tar.gz
Size 163.4 kB
Tags Source
SHA-256 checksum
How to use checksums
581170fa003af69c865dd3b27bfe58a296b67fc1317f9441262b8c8d00e3a873
BLAKE2b-256 checksum
How to use checksums
af3073f319017665d4028569415c2c223992f9413f487fc6c36052ce7126780f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.

Transparency log

Release files / dilemma-0.7.0-py3-none-any.whl

Download URL dilemma-0.7.0-py3-none-any.whl
Size 41.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7aac83471d787e720b59237702e84268b1e8894a77095001896da345bf55e62c
BLAKE2b-256 checksum
How to use checksums
4ad6cc354a58cb05d64bd88f2f5b23d80c30cde687dca0114263429cd09561d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.5.0

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page