Fast, Safe, and Expressive evaluation of Google's Common Expression Language (CEL) in Python, powered by Rust.
The Common Expression Language (CEL) is a non-Turing complete language designed for simplicity, speed, and safety. This Python package wraps the Rust implementation cel-interpreter v0.10.0, providing microsecond-level expression evaluation with seamless Python integration.
- π‘οΈ Policy Enforcement: Define access control rules that can be updated without code changes
- βοΈ Configuration Validation: Validate complex settings with declarative rules
- π Data Transformation: Transform and filter data with safe, portable expressions
- π Business Rules: Implement decision logic that business users can understand
- π Query Filtering: Build dynamic filters for databases and APIs
- π― Feature Flags: Create sophisticated feature toggle conditions
pip install common-expression-languageOr using uv:
uv add common-expression-languageAfter installation, both the Python library and the cel command-line tool will be available.
π Full Documentation: https://python-common-expression-language.readthedocs.io/
Python values are prepared explicitly and installed into a reusable native context:
import cel
context = cel.Context()
context.add_variable("age", cel.prepare(25))
result = cel.evaluate("age >= 18", context) # True
context.add_variable(
"user",
cel.prepare({"role": "admin"}),
)
context.add_variable(
"permissions",
cel.prepare(["read", "write", "delete"]),
)
result = cel.evaluate(
'user.role == "admin" && "write" in permissions',
context,
) # True# Simple evaluation
cel '1 + 2' # 3
# With context
cel 'age >= 18' --context '{"age": 25}' # true
# Interactive REPL
cel --interactivePrepare large values outside the hot path. Prepared values are immutable snapshots and can be shared by multiple contexts. Installing a retained prepared value only clones a shared handle:
import cel
data = {
"objects": [
{"active": i % 2 == 0, "score": i, "profile": {"enabled": True}} for i in range(500)
]
}
prepared = cel.prepare(data)
context = cel.Context()
program = cel.compile("data.objects[3].profile.enabled")
for _ in range(100_000):
context.add_variable("data", prepared)
result = program.execute(context)Retain prepared objects used for frequent replacement. If a context owns the final reference to a large prepared value, replacing or dropping it may recursively free the value and therefore take time proportional to its size. Returning a large map/list or passing one to a Python callback is also proportional to that result or argument size.
import cel
from cel import Context, evaluate
def calculate_discount(price, rate):
return price * rate
context = Context()
context.add_function("calculate_discount", calculate_discount)
context.add_variable("price", cel.prepare(100))
result = evaluate("price - calculate_discount(price, 0.1)", context) # 90.0import cel
from cel import evaluate, Context
# Access control policy
policy = """
user.role == "admin" ||
(resource.owner == user.id && current_hour >= 9 && current_hour <= 17)
"""
context = Context()
context.add_variable("user", cel.prepare({"id": "alice", "role": "user"}))
context.add_variable("resource", cel.prepare({"owner": "alice"}))
context.add_variable("current_hour", cel.prepare(14))
access_granted = evaluate(policy, context) # True- β Fast Evaluation: Microsecond-level expression evaluation via Rust
- β Rich Type System: Integers, floats, strings, lists, maps, timestamps, durations
- β Python Integration: Seamless type conversion and custom function support
- β CLI Tools: Interactive REPL and batch processing capabilities
- β Safety First: Non-Turing complete, safe for untrusted expressions
π Complete documentation available at: https://python-common-expression-language.readthedocs.io/
To build and serve the documentation locally:
# Install documentation dependencies
uv sync --group docs
# Build the documentation
uv run --group docs mkdocs build
# Serve locally with live reload
uv run --group docs mkdocs serveThe documentation will be available at http://localhost:8000
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=cel
# Test all documentation examples (embedded code + standalone files)
uv run --group docs pytest tests/test_docs.py -v# Install development dependencies
uv sync --dev
# Build the package
uv run maturin develop
# Run tests
uv run pytestContributions are welcome! Please see our documentation for:
- CEL compliance status
- Development setup and guidelines
- Areas where help is needed
This project is licensed under the same terms as the original cel-interpreter crate.