Skip to main content

This is an expression language python package.

Project description

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 
&& 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 has `user.role == 'Audit' and timestamp is $past`
    and project.status == 'review'
    and all of documents has `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 has `status == 'pending'` and any of orders has `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 has `status == 'active'`", context)
result = evaluate("none of orders has `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'"

Natural Language Array Operations

Dilemma provides intuitive sugar syntax for common array operations:

# Quantity-based checks
"at least 3 of orders has `status == 'shipped'`"
"at most 2 of users has `role == 'admin'`"
"exactly 1 of servers has `status == 'maintenance'`"

# Existence checks
"any of products has `price > 100`"
"all of users has `email_verified == true`"
"none of alerts has `severity == 'critical'`"

# Combined with other operations
"at least 5 of reviews has `rating >= 4` and user.subscription is $active"
"any of files has `name like '*.pdf'` and all of files has `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

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 has `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

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 has \status == 'passed'` and none of builds has `errors > 0`"`
  • Inventory management - "at least 10 of products has \stock > 0` and any of suppliers has `delivery_time < 3`"`
  • Security monitoring - "none of login_attempts has \failed_count > 5` and all of sessions has `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

License

MIT License - see LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dilemma-0.5.0.tar.gz (156.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dilemma-0.5.0-py3-none-any.whl (39.9 kB view details)

Uploaded Python 3

File details

Details for the file dilemma-0.5.0.tar.gz.

File metadata

  • Download URL: dilemma-0.5.0.tar.gz
  • Upload date:
  • Size: 156.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dilemma-0.5.0.tar.gz
Algorithm Hash digest
SHA256 4a1fb5467d48794951d2726a8f4924de77cda94a7e5ee2024815e9b00e9fe1e4
MD5 bd8a809e295f5f5e497c55d98c035330
BLAKE2b-256 65108dab61975280fb0319642f3596e80c0a242f7097dd3be1f8c984f7ecde73

See more details on using hashes here.

Provenance

The following attestation bundles were made for dilemma-0.5.0.tar.gz:

Publisher: publish.yml on patrickcd/dilemma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dilemma-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: dilemma-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 39.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dilemma-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ad7c6133cd9f7d350f9225a4805c074a07a35418aa7d5582ef3180ea2533b604
MD5 0d7b0f7d9e7338409030be8b3e852591
BLAKE2b-256 6e0327dff53b5065ce2b792141e4aa4d891ad0386f26db77d4a125b812eee86f

See more details on using hashes here.

Provenance

The following attestation bundles were made for dilemma-0.5.0-py3-none-any.whl:

Publisher: publish.yml on patrickcd/dilemma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page