Evaluation Module¶
Safe expression evaluation for conditions.
ConditionEvaluator¶
Safely evaluates condition expressions against flow context.
ConditionEvaluator
¶
Safely evaluates condition expressions.
Uses AST validation to ensure expressions don't contain dangerous constructs before evaluation.
Example
Initialize evaluator with AST validator.
evaluate
¶
Evaluate a condition expression.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
condition
|
str
|
Python expression string |
required |
context
|
FlowContext
|
Current flow context |
required |
Returns:
| Type | Description |
|---|---|
bool
|
Boolean result of evaluation |
Raises:
| Type | Description |
|---|---|
ConditionEvaluationError
|
If condition is unsafe or invalid |
is_safe
¶
Check if a condition is safe to evaluate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
condition
|
str
|
Python expression string |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if condition passes safety validation |
validate
¶
Validate a condition and return any errors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
condition
|
str
|
Python expression string |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
List of validation errors (empty if valid) |
SafeASTValidator¶
Validates Python AST for safe expressions only.
SafeASTValidator
¶
Bases: NodeVisitor
Validates that an AST only contains safe nodes.
Prevents code injection by rejecting: - Function calls - Imports - Attribute assignment - Lambda/comprehensions - Any assignment operations
Example
validator = SafeASTValidator()
# Safe expression
tree = ast.parse("x > 5 and y == 'test'", mode='eval')
assert validator.validate(tree)
# Unsafe expression (function call)
tree = ast.parse("len(items) > 0", mode='eval')
assert not validator.validate(tree)
print(validator.errors) # ["Disallowed node type: Call"]
Initialize validator with empty error list.
validate
¶
Validate entire AST tree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
node
|
AST
|
Root AST node to validate |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if all nodes are safe, False otherwise |
get_errors
¶
Get list of validation errors.
Returns:
| Type | Description |
|---|---|
list[str]
|
List of error messages |
Allowed Expression Constructs¶
Comparison Operators¶
| Operator | Example |
|---|---|
== |
context.data.status == 'active' |
!= |
context.data.status != 'deleted' |
< |
context.data.count < 100 |
<= |
context.data.count <= 100 |
> |
context.data.count > 0 |
>= |
context.data.count >= 10 |
Boolean Operators¶
| Operator | Example |
|---|---|
and |
a == 1 and b == 2 |
or |
status == 'a' or status == 'b' |
not |
not is_disabled |
Identity and Membership¶
| Operator | Example |
|---|---|
is |
value is None |
is not |
value is not None |
in |
status in ['active', 'pending'] |
not in |
role not in ['guest'] |
Attribute and Subscript Access¶
context.data.user.name # Attribute access
context.data.items[0] # Index access
context.data["key"] # Key access
Literals¶
True, False, None # Boolean and None
42, 3.14, -1 # Numbers
"string", 'string' # Strings
[1, 2, 3] # Lists
("a", "b") # Tuples
{"key": "value"} # Dicts
Disallowed Constructs¶
These are blocked for security:
| Construct | Example | Reason |
|---|---|---|
| Function calls | len(x) |
Code execution |
| Imports | import os |
Module access |
| Assignments | x = 1 |
State mutation |
| Lambda | lambda: x |
Code execution |
| Comprehensions | [x for x in y] |
Complex logic |
Usage Examples¶
Basic Evaluation¶
from flowengine import ConditionEvaluator, FlowContext
evaluator = ConditionEvaluator()
context = FlowContext()
context.set("status", "active")
context.set("count", 42)
# Evaluate conditions
result = evaluator.evaluate(
"context.data.status == 'active'",
context
)
print(result) # True
result = evaluator.evaluate(
"context.data.count > 100",
context
)
print(result) # False
Safety Validation¶
evaluator = ConditionEvaluator()
# Check if safe
print(evaluator.is_safe("context.data.x == 1")) # True
print(evaluator.is_safe("len(context.data.x)")) # False
# Get validation errors
errors = evaluator.validate("import os")
print(errors) # ["Import statements are not allowed"]
AST Validation¶
import ast
from flowengine import SafeASTValidator
# Parse expression
tree = ast.parse("x == 1 and y > 2", mode="eval")
# Validate
validator = SafeASTValidator()
is_safe = validator.validate(tree)
errors = validator.get_errors()
if not is_safe:
print("Validation errors:", errors)