This document tracks the compliance of this Python CEL implementation with the Common Expression Language (CEL) specification.
- Implementation: Based on
celv0.11.1 Rust crate (formerly cel-interpreter) - Estimated Compliance: ~80% of CEL specification features.
- Test Coverage: 300+ tests across 16+ test files including comprehensive CLI testing and upstream improvement detection
| Feature | Severity | Impact | Workaround Available | Upstream Priority |
|---|---|---|---|---|
| OR operator behavior | ๐ข LOW | โ FIXED v0.11.1 - now CEL-compliant (rejects mixed types) | Use boolean operands only | RESOLVED |
| String utility functions | ๐ก MEDIUM | Limited string processing capabilities | Use Python context functions | HIGH |
Type introspection (type()) |
๐ก MEDIUM | No runtime type checking | Use Python type checking | HIGH |
| Mixed int/uint arithmetic | ๐ก MEDIUM | Manual type conversion needed | Use explicit casting | MEDIUM |
| Mixed-type arithmetic in macros | ๐ก MEDIUM | Type coercion issues in collections | Ensure type consistency | MEDIUM |
| Bytes concatenation | ๐ข LOW | Cannot concatenate byte arrays | Convert through string | LOW |
Math functions (ceil, floor) |
๐ข LOW | No mathematical utilities | Use Python context functions | LOW |
Collection aggregation (sum, fold, reduce) |
๐ข LOW | No aggregation functions | Use Python context functions | LOW |
| Optional values | ๐ข LOW | No optional chaining syntax | Use has() checks |
FUTURE |
Legend: ๐ด High Impact | ๐ก Medium Impact | ๐ข Low Impact
๐ See the complete Type System documentation for detailed CEL โ Python type mappings, map type constraints, and examples.
This implementation correctly follows the CEL specification where maps can have heterogeneous values at runtime while maintaining key type restrictions.
| CEL Operation | Result Type | Example | Python Result | Notes |
|---|---|---|---|---|
int + int |
int |
1 + 2 |
3 |
โ Works |
uint + uint |
int |
1u + 2u |
3 |
โ Works |
double + double |
float |
1.5 + 2.5 |
4.0 |
โ Works |
int + double |
float |
1 + 2.0 |
3.0 |
double(1) + 2.0 |
double + int |
float |
1.5 + 2 |
3.5 |
1.5 + double(2) |
int / int |
int |
10 / 2 |
5 |
โ Works |
uint % uint |
int |
10u % 3u |
1 |
โ Works |
string + string |
str |
"hello" + " world" |
"hello world" |
โ Works |
| CEL Operation | CEL Spec Result | Our Result | Python Result | Notes |
|---|---|---|---|---|
true && false |
bool (false) |
bool |
False |
โ Correct |
true || false |
bool (true) |
bool |
True |
โ Correct |
!true |
bool (false) |
bool |
False |
โ Correct |
42 || false |
bool (true) |
int |
42 |
|
0 && true |
bool (false) |
bool |
False |
โ Correct (0 is falsy) |
'' && true |
bool (false) |
bool |
False |
โ Correct (empty string falsy) |
- Integers: Full support for 64-bit signed integers (
int) - Unsigned Integers: Support for 64-bit unsigned integers (
uint) withusuffix - Floats: IEEE 64-bit double precision floating-point
- Booleans: Standard true/false values
- Strings: Unicode string support with concatenation
- Bytes: Byte sequence support (no concatenation)
- Null: Proper null handling as
None - Lists: Ordered collections with indexing and size operations
- Maps: Key-value dictionaries with restricted key types (int, uint, bool, string) and mixed value types (fully CEL compliant)
- Timestamps: Full datetime support with timezone awareness
- Durations: Time span support via timedelta
+(addition) - Integers, floats, strings-(subtraction) - Integers, floats*(multiplication) - Integers, floats/(division) - Integers, floats%(remainder/modulo) - Integers only
==(equal) - All types!=(not equal) - All types<,>,<=,>=- Numbers, strings (lexicographic)
&&(logical AND) - With short-circuit evaluationโ ๏ธ Requires boolean operands in v0.11.1+||(logical OR) - With short-circuit evaluationโ ๏ธ Partially improved in v0.11.1 - some mixed-type coercion removed!(logical NOT) - Boolean negation
?:(ternary conditional) - Conditional expressions[](indexing) - Lists and maps only (string indexing not supported).(member access) - Object property access
| Function | Signature | Purpose | Python Result | Status |
|---|---|---|---|---|
size() |
size(collection) -> int |
Get collection/string length | int |
โ Working |
string() |
string(value) -> string |
Convert to string | str |
โ Working |
bytes() |
bytes(value) -> bytes |
Convert to bytes | bytes |
โ Working |
int() |
int(value) -> int |
Convert to signed integer | int |
โ Working |
uint() |
uint(value) -> uint |
Convert to unsigned integer | int |
โ Working |
double() |
double(value) -> double |
Convert to double | float |
โ Working |
timestamp() |
timestamp(string) -> timestamp |
Parse timestamp | datetime.datetime |
โ Working |
duration() |
duration(string) -> duration |
Parse duration | datetime.timedelta |
โ Working |
has() |
has(field) -> bool |
Check field presence | bool |
โ Working |
matches() |
string.matches(pattern) -> bool |
Regex matching | bool |
โ Working |
min() |
min(list) -> value |
Find minimum value | Various | โ Working |
max() |
max(list) -> value |
Find maximum value | Various | โ Working |
sum() |
sum(list) -> number |
Sum numeric values | N/A | โ NOT AVAILABLE |
- contains():
"hello".contains("ell")โTrue - startsWith():
"hello".startsWith("he")โTrue - endsWith():
"hello".endsWith("lo")โTrue - matches():
"hello world".matches(".*world")โTrue - String concatenation:
"hello" + " world"โ"hello world" - String size:
size("hello")โ5
- String indexing:
"hello"[1]is NOT supported (returns "No such key" error) - Workaround: Use
substring()function (when available) or Python context functions
- all():
[1,2,3].all(x, x > 0)โTrue - exists():
[1,2,3].exists(x, x == 2)โTrue - filter():
[1,2,3].filter(x, x > 1)โ[2.0, 3.0](with type coercion) - map(): Limited due to type system restrictions
โ ๏ธ PARTIAL (requires type-compatible operations)
- fold():
[1,2,3].fold(0, sum, sum + x)- Collection aggregation โ NOT AVAILABLE - reduce():
reduce([1,2,3], 0, sum + x)- Reduction operations โ NOT AVAILABLE
- Type conversion: Seamless Python โ CEL type mapping
- Context variables: Access Python objects in expressions
- Custom functions: Call Python functions from CEL expressions
- Error handling: Proper exception propagation
- Performance: Efficient evaluation for frequent operations
This section focuses on what you need to know to use CEL effectively in your applications.
Using cel.stdlib (Recommended)
This library provides Python implementations of missing CEL functions:
from cel import Context, evaluate
from cel.stdlib import add_stdlib_to_context
# Add all standard library functions at once
context = Context()
add_stdlib_to_context(context)
# substring() is now available as a function (not a method)
result = evaluate('substring("hello world", 0, 5)', context) # โ "hello"
result = evaluate('substring("hello world", 6)', context) # โ "world"
# Note: Use function syntax, not method syntax
# โ
substring("hello", 2, 4) - correct
# โ "hello".substring(2, 4) - not supportedUsing Custom Python Functions
You can also add your own custom functions:
from cel import Context, evaluate
# Add custom functions for missing CEL features
context = Context()
context.add_function("lower", str.lower)
context.add_function("upper", str.upper)
context.add_function("find", str.find)
# Add variables to the context
context.add_variable("name", "ALICE")
context.add_variable("text", "hello world")
# Use Python functions in CEL expressions
result = evaluate('lower(name)', context) # โ "alice"
result = evaluate('find(text, "world")', context) # โ 6from cel import evaluate
# โ
SAFE: Explicit type conversions for mixed arithmetic
result = evaluate("int(value) + 1", {"value": "42"}) # โ 43
# โ ๏ธ RISKY: Mixed int/uint arithmetic - use explicit conversion
# evaluate("1 + 2u") # This will fail
result = evaluate("1 + int(2u)") # โ 3 (safe alternative)
# โ
SAFE: Use has() checks for optional fields
safe_expr = 'has(user.profile) && user.profile.verified'
result = evaluate(safe_expr, {"user": {}}) # โ False (graceful handling)from cel import evaluate
def safe_evaluate(expression, context):
"""Wrapper for production CEL evaluation with proper error handling."""
try:
return evaluate(expression, context)
except ValueError as e:
# Parse/syntax errors - log and return safe default
print(f"CEL syntax error: {e}")
return False # Fail-safe default
except RuntimeError as e:
# Undefined variables/functions - log and return safe default
print(f"CEL runtime error: {e}")
return False # Fail-safe default
except TypeError as e:
# Type mismatches - log and return safe default
print(f"CEL type error: {e}")
return False # Fail-safe default
# Usage in access control (always fail-safe)
policy_expr = "user.verified && user.role == 'admin'"
user_context = {"user": {"verified": True, "role": "admin"}}
access_granted = safe_evaluate(policy_expr, user_context)Use these features with confidence in production:
- Core data types: int, float, bool, string, bytes, lists, maps
- Arithmetic:
+,-,*,/,%(watch mixed types) - Comparisons:
==,!=,<,>,<=,>= - Logical operations:
&&,!(avoid||return values) - String operations:
contains(),startsWith(),endsWith(),matches() - Collection operations:
size(),has(), indexing with[] - Macros:
all(),exists(),filter()(ensure type consistency) - Type conversions:
string(),int(),double(),bytes() - Date/time:
timestamp(),duration()with proper ISO formats
This section covers upstream work, detection strategies, and contribution opportunities.
- Status: Not implemented in cel v0.11.1
- Detection: โ Comprehensive detection for all missing functions
- Missing functions:
lowerAscii()- lowercase conversionupperAscii()- uppercase conversionindexOf(substring)- find position in stringslastIndexOf(substring)- find last occurrencesubstring(start, end)- extract substringreplace(old, new)- replace substringssplit(delimiter)- split into listjoin(delimiter, list)- join list to string
Example of missing functionality:
// Should work but doesn't:
"Hello".lowerAscii() // case conversion
"hello world".indexOf("world") // substring search
"hello,world".split(",") // string splitting
Impact: Medium - useful for string processing Recommendation: Contribute to cel crate upstream
- Status: Partially supported
- Detection: โ Comprehensive detection for mixed operations
- CEL Spec: Supports both
intanduinttypes withusuffix (1u,42u) - Our Implementation:
- โ
Unsigned literals work:
1u,42uโ Pythonint - โ
Pure unsigned arithmetic:
1u + 2uโ3 - โ Mixed arithmetic fails:
1 + 2uthrows "Unsupported binary operator"
- โ
Unsigned literals work:
- Workaround: Use explicit conversion:
uint(1) + 2uorint(2u) + 1 - Impact: Medium - requires careful type management in expressions
- Status: Not implemented in cel v0.11.1, but foundation exists
- Detection: โ Full detection with expected behavior tests
- Missing function:
type(value) -> string - CEL Spec: Should return runtime type as string
- Example:
type(42)should return"int" - Our Implementation: Throws "Undeclared reference to 'type'"
- Recent Progress: Upstream has introduced comprehensive type system infrastructure
- Impact: Medium - useful for dynamic type checking
- Recommendation: This function may be available in future releases
- Status: Type coercion issues in collection operations
- Problem:
[1,2,3].map(x, x * 2)fails with "Unsupported binary operator 'mul': Int(1), Float(2.0)" - Impact: Medium - affects advanced collection processing
- Workaround: Ensure type consistency in macro expressions
- Recommendation: Better type coercion in cel crate
- Status: Not implemented in cel v0.11.1
- CEL Spec:
b'hello' + b'world'should returnb'helloworld' - Our Implementation: Throws "Unsupported binary operator" error
- Workaround:
bytes(string(part1) + string(part2)) - Impact: Low - rarely used in practice
- Detection: โ Full detection for all missing functions Missing functions:
- Math:
ceil(),floor(),round()- Mathematical functions - Collection:
fold(),reduce()- Collection aggregation functions - Collection: Enhanced
inoperator behaviors - URL/IP:
isURL(),isIP()- Validation functions (available in some CEL implementations)
- Detection: โ Full detection with expected behavior tests Missing features:
optional.of(value)- create optionaloptional.orValue(default)- unwrap with default?suffix for optional chaining
Recent Progress: Upstream has introduced optional type infrastructure, suggesting these features may be implemented in future releases.
- Detection: โ We monitor for when this behavior gets fixed upstream
- Status: JavaScript-like behavior instead of CEL spec compliance
- Upstream Priority: CRITICAL - This affects specification conformance
- Our Implementation: Performs Python-like truthiness evaluation
- CEL Spec: May have different rules for type coercion
- Example: Empty strings, zero values treated as falsy
- Impact: Low - generally intuitive behavior
The underlying cel-rust implementation continues to evolve with improvements that will benefit this Python wrapper:
- Type Introspection: Infrastructure being developed for the missing
type()function - Better Type Checking: More precise type information and operation support detection
- Optional Types: Foundation exists for safer null handling with optional values
- Improved Error Messages: Enhanced type information in error reporting
// May be available in future releases
type(42) // โ "int"
type("hello") // โ "string"
type([1, 2, 3]) // โ "list"
// Optional value handling
optional.of(value) // Create optional value
value.orValue(default) // Unwrap with default
field?.subfield?.property // Optional chaining
- Backward Compatibility: All improvements maintain API stability
- Transparent Upgrades: New features will be additive, not breaking
- Better Standard Library: Infrastructure exists for implementing missing string functions
- CEL Spec Alignment: Closer alignment with official CEL specification
- Expression parsing: Efficiently handled by Rust cel crate
- Type conversion: Optimized Python โ Rust boundaries
- Memory usage: Reasonable for typical use cases
- Evaluation speed: Microsecond-level evaluation times
- Large list/dict conversions: Handles 10,000+ elements
- Nested structure traversal: Deep object access
- String processing: Unicode-safe operations
- Mixed-type arithmetic: Efficient numeric operations
| Feature | Status | Python Behavior | Notes |
|---|---|---|---|
| Parse errors | โ Supported | Raises ValueError |
All syntax errors handled gracefully |
| Runtime errors | โ Supported | Raises RuntimeError |
Undefined variables/functions, function execution errors |
| Type errors | โ Supported | Raises TypeError |
Type mismatch detection |
| Undefined variables | โ Supported | Raises RuntimeError |
Clear error messages |
All malformed syntax is now handled gracefully with proper Python exceptions:
Malformed syntax that raises ValueError:
- Unclosed quotes:
'timestamp("2024-01-01T00:00:00Z") - Mixed quotes:
"hello'or'hello" - Unmatched brackets/parentheses in complex expressions
Examples of safe error handling:
from cel import evaluate
# All of these now raise clean ValueError exceptions:
try:
evaluate("'unclosed quote", {})
except ValueError as e:
print(f"Parse error: {e}")
try:
evaluate('"mixed quotes\'', {})
except ValueError as e:
print(f"Parse error: {e}")Consistent Behavior:
Both the CLI tool and the core evaluate() function now handle all malformed input consistently by raising appropriate Python exceptions instead of panicking.
| Category | File | Test Count | Coverage Level |
|---|---|---|---|
| Basic Operations | test_basics.py | 42 | โ Comprehensive |
| Arithmetic | test_arithmetic.py | 31 | โ Comprehensive |
| Type Conversion | test_types.py | 23 | โ Comprehensive |
| Datetime | test_datetime.py | 25 | โ Comprehensive |
| Context | test_context.py | 11 | โ Good |
| Logical Operators | test_logical_operators.py | 12 | โ Good |
| Parser Errors | test_parser_errors.py | 10 | โ Good |
| Performance | test_performance_verification.py | 6 | โ Basic |
| Documentation | test_documentation.py | 10 | โ Good |
| Functions | test_functions.py | 2 | |
| Edge Cases | test_edge_cases.py | 1 |
- String method testing: Limited to basic operations
- Parser error recovery: All malformed input now handled gracefully
- Boundary value testing: Some edge cases not covered
- Unicode/encoding edge cases: Basic coverage only
-
String utility functions - โ Detection Ready (
test_upstream_detection.py)- Functions:
lowerAscii,upperAscii,indexOf,lastIndexOf,substring,replace,split,join - Impact: MEDIUM - Widely used in string processing applications
- Contribution path: cel crate standard library expansion
- Functions:
-
OR operator CEL spec compliance - โ Detection Ready
- Issue: Returns original values instead of booleans
- Impact: HIGH - Breaks specification conformance
- Contribution path: Core logical operation fixes
-
Type introspection function - โ Detection Ready (
test_upstream_detection.py)- Function:
type()for runtime type checking - Impact: MEDIUM - Useful for dynamic expressions
- Contribution path: Leverage existing type system infrastructure
- Function:
-
Mixed-type arithmetic in macros - โ Detection Ready
- Issue: Type coercion problems in collection operations
- Impact: MEDIUM - Affects advanced collection processing
- Contribution path: Macro type system improvements
-
Mixed int/uint arithmetic
- Issue:
1 + 2uoperations fail - Impact: MEDIUM - Requires careful type management
- Contribution path: Arithmetic type coercion enhancements
- Issue:
-
Collection aggregation functions - โ Detection Ready
- Functions:
sum(),fold(),reduce() - Impact: LOW - Can be implemented via Python context
- Contribution path: Standard library expansion
- Functions:
-
Math functions - โ Detection Ready
- Functions:
ceil,floor,round - Impact: LOW - Can be implemented via Python context
- Contribution path: Standard library expansion
- Functions:
-
Optional value handling - โ Detection Ready
- Features:
optional.of(),.orValue(),?chaining - Impact: LOW - Alternative patterns exist
- Contribution path: Type system extensions
- Features:
- Enhanced error handling - Better Python exception mapping and messages
- Performance benchmarking - Systematic performance testing and optimization
- Comprehensive testing - Cover newly discovered working features
- Local utility functions - Implement missing string functions via Python context
- Migration guides - Help users transition from other CEL implementations
- Best practices documentation - Safe patterns and workarounds
- โ Monitoring system active - All issues have upstream detection
- ๐ Priority: OR operator fix - Most critical specification compliance issue
- ๐ Priority: String utilities - High-value, lower-risk contribution opportunity
- ๐ Engage upstream - Discuss contribution strategy with cel crate maintainers
When adding new features or fixing compliance issues:
- Check CEL specification at https://github.com/google/cel-spec
- Add comprehensive tests for both positive and negative cases
- Document behavior especially if it differs from spec
- Update this compliance document with changes
- Consider upstream contributions to cel crate
- CEL Specification: https://github.com/google/cel-spec
- cel crate: https://crates.io/crates/cel
- CEL Language Definition: https://github.com/google/cel-spec/blob/master/doc/langdef.md
- CEL Homepage: https://cel.dev/