simpleeval

A single-file Python library for safely evaluating user-supplied expressions without exposing full eval() access.

Library
PyPI
v1.0.7
611stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
60/100Good
Development Activity56
Maintenance36
Community68
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture80
Code Quality85
Innovation70
Learning Curve55

simpleeval (Simple Eval) is a lightweight Python library for evaluating expressions typed by end users — alarm-volume formulas, spreadsheet-style calculations, or web app formula fields — without handing them the full power, and danger, of Python’s built-in eval(). It parses expressions with Python’s own ast module and walks the resulting tree using an explicit whitelist of operators, functions, and names, so nothing runs that hasn’t been deliberately permitted.

The library ships as a single file that can be pip-installed or simply dropped into a project, and its defaults are deliberately conservative: string length, exponent size, and shift operations are all capped to make denial-of-service expressions impractical. Callers can extend it with custom functions, dynamic name lookups backed by a database or cache, and compound-type support via the EvalWithCompoundTypes subclass, while staying inside a sandboxed evaluation model.

What You Get

  • A SimpleEval class for repeated evaluation of many expressions with shared, reusable state
  • A simple_eval() convenience function for one-off expression evaluation
  • A whitelisted operator table covering arithmetic, comparison, bitwise, and shift operations, each swappable or removable
  • Built-in DoS protections: MAX_STRING_LENGTH, MAX_POWER, MAX_SHIFT, and MAX_COMPREHENSION_LENGTH guard against runaway expressions
  • EvalWithCompoundTypes for expressions that need to build lists, dicts, tuples, and sets

Common Use Cases

  • User-configurable formulas - letting end users define alarm thresholds, pricing rules, or scoring logic without exposing raw eval()
  • Web form calculators - evaluating spreadsheet-like formulas submitted through a web UI, server-side, without needing a JS-only sandbox
  • Templating and rules engines - powering conditional logic in low-code tools where end users write short expressions
  • Config-driven business rules - reading expressions from a database or config file and evaluating them against a custom name resolver

Under The Hood

Architecture The library is a single module (simpleeval.py) organized around one core class, SimpleEval, which owns three swappable dicts — operators, functions, and names — and a recursive _eval() dispatcher that pattern-matches on ast node types (ast.BinOp, ast.Compare, ast.IfExp, ast.Call, and so on) and routes each to a dedicated handler. Names can be a plain dict or a callable, enabling dynamic resolution (database lookups, computed values) without subclassing. EvalWithCompoundTypes extends SimpleEval to add List/Dict/Tuple/Set node handling, kept separate so the base class’s attack surface stays minimal by default. A small set of module-level exception classes (NameNotDefined, FunctionNotDefined, NumberTooHigh, IterableTooLong) give callers precise, catchable failure modes rather than raw Python exceptions leaking through.

Tech Stack Pure Python with zero runtime dependencies (dependencies = [] in pyproject.toml), built entirely on the standard library’s ast and operator modules. Packaging uses hatchling with a single-file wheel target. The dev toolchain runs on uv, with ruff for linting/formatting and mypy for type checking; the project targets Python 3.9 through 3.14 plus PyPy 3.9/3.10, reflected in a partial but present set of type annotations (e.g. dict[type | None, set]) on newer code paths.

Code Quality Test coverage is extensive and unusually security-focused: alongside standard operator/function/name tests, a dedicated test_security.py exercises MRO breakout attempts, __builtins__ access, function-globals breakouts, module-access breakouts, and string-format exploits — the kind of adversarial cases a sandboxing library needs to defend explicitly. CI (GitHub Actions) runs the full matrix across Ubuntu and Windows, across all supported CPython and PyPy versions, plus a separate lint job running ruff and a dist build/check. Naming and structure are consistent throughout, and exceptions are typed and specific rather than generic.

What Makes It Unique Rather than trying to blacklist dangerous constructs from a full eval(), simpleeval inverts the model: it only implements handlers for a small, explicit whitelist of AST node types, so anything not explicitly supported simply isn’t reachable, closing off entire classes of sandbox-escape bugs by construction rather than by patching known exploits. Combined with built-in resource-exhaustion limits (max string length, max power, max shift) tuned from real-world abuse cases, it targets a narrow, well-understood threat model — untrusted expression strings, not untrusted Python code — and does that one job with a very small, auditable surface area.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search