Limited Evaluator (leval)
leval is a Python library that provides a safe and limited evaluator for untrusted Python expressions, aiming to prevent arbitrary code execution while allowing controlled calculations. It is currently at version 1.3.0 and actively maintained, with recent updates focusing on feature enhancements and internal improvements.
Common errors
-
ModuleNotFoundError: No module named 'leval'
cause The 'leval' library is not installed in the current Python environment.fixRun `pip install leval` to install the library. -
leval.exceptions.UndefinedNameError: Undefined name 'my_variable'
cause An expression attempts to use a variable name that was not provided in the evaluation context (e.g., `**context`, `globals`, or `locals`).fixEnsure all variables used in the expression are passed into the `evaluate` function's `**context` (or `globals`/`locals`) dictionary. -
leval.exceptions.InvalidSyntaxError: Invalid syntax in expression '...'
cause The provided expression string contains a Python syntax error (e.g., unmatched parentheses, incorrect operator usage).fixReview the expression string for correct Python syntax. `leval` expressions are standard Python syntax. -
leval.exceptions.InvalidAttributeError: Object of type <class 'str'> has no attribute 'non_existent_method'
cause The expression attempts to access an attribute or call a method on an object that does not possess it (e.g., `my_string.non_existent_method()`).fixVerify that the objects in your context have the attributes/methods you are trying to access. This often indicates a typo or misunderstanding of the object's API.
Warnings
- gotcha The default behavior of `is` and `is not` operators was changed in v1.2.0 to be 'loose', meaning expressions like `0 is False` or `'' is None` might evaluate to `True`.
- breaking In v1.2.0, a new specific exception type, `leval.exceptions.InvalidAttributeError`, was introduced for attempts to access non-existent attributes. Previously, this might have raised a generic `AttributeError`.
- gotcha `leval` is designed as a *limited* evaluator, not a full sandbox. While it blocks many dangerous operations, careful control of the `globals` and `locals` context is crucial to prevent unintended side effects or exposure of sensitive objects.
Install
-
pip install leval
Imports
- evaluate
from leval.simple import evaluate
- Leval
from leval.universal import Leval
Quickstart
from leval.simple import evaluate
# Basic evaluation with context
expression_1 = "x * (y + 2)"
context_1 = {"x": 5, "y": 3}
result_1 = evaluate(expression_1, **context_1)
print(f"'{expression_1}' with context {context_1} evaluates to: {result_1}")
# Evaluation with string methods and built-in functions
expression_2 = "s.upper() + ' WORLD!' if len(s) > 5 else s.lower()"
context_2 = {"s": "hello"}
result_2 = evaluate(expression_2, **context_2)
print(f"'{expression_2}' with context {context_2} evaluates to: {result_2}")
# Explicitly opting out of loose 'is/is not' behavior introduced in v1.2.0
# For example, '0 is False' would evaluate to True with default 'loose_is_is_not=True'
expression_3 = "my_value is None"
context_3 = {"my_value": 0}
result_3_loose = evaluate(expression_3, **context_3)
result_3_strict = evaluate(expression_3, loose_is_is_not=False, **context_3)
print(f"'{expression_3}' (0 is None) with loose_is_is_not (default): {result_3_loose}")
print(f"'{expression_3}' (0 is None) with loose_is_is_not=False: {result_3_strict}")