Library for generating python-expressions
Project description
uneval
Uneval is a small library for working with python-expressions.
It makes working with expressions more intuitive than ast-objects and safer than working on strings.
You may use it to dynamically generate code, write macros or implement domain specific languages,
It also provides a shorthand (F.x) for code that heavily uses anonymous functions.
Installation
Make sure to install pip then run:
pip install uneval
Usage
Functionality
# Factory to create an expression
expr(obj: str | ast.AST | Expression) -> Expression
# Create variable x as an Expression
var(x: str) -> Expression[ast.Name]
var.x
# Evaluate an expression
evaluate(expr: str | Expression | ast.AST, **vars) -> Any
# Compile an expression
compiled(expr: str | Expression | ast.AST | CodeType) -> CodeType
# Create anonymous function (lambda) with parameter x and expression as body
F.x(expr: str | Expression | ast.AST) -> Callable[[Any], Any]
# Convert expression to abstract syntax tree node
to_ast(expr: Expression | ast.AST) -> ast.AST
Example
import ast
from uneval import var, evaluate, F
>>> square_x = expr("x * x")
>>> square_x = var.x * var.x # alternative way of writing expressions
>>> evaluate(square_x, x=3)
9
>>> square = F.x(square_x)
>>> square(3)
9
>>> str(square_x)
'x * x'
>>> to_ast(square_x)
ast.BinOp(ast.Name(id="x", ctx=ast.Load()), ast.Mult(), ast.Name(id="x", ctx=ast.Load()))
Building blocks
| Factory | Example | Result |
|---|---|---|
expr |
expr("a + 3") |
a + 3 |
var |
var('a') or var.a (shortcut) |
a |
if_ |
if_(var.x >= 0, var.x, -var.x) |
x if x >= 0 else -x |
for_ |
for_(var.x**2, (var.x, range(5))) |
(x**2 for x in range(5)) |
lambda_ |
lambda_([var.x], var.x * var.x) |
lambda x: x * x |
and_, or_ |
and_(var.x >= 10, var.x <= 15) |
x >= 10 and x <= 15 |
not_, in_ |
not_(in_(var.x, {1, 2, 3})) |
not x in {1, 2, 3} |
fstr, fmt |
fstr("sin(", var.a, ") is ", fmt(var.sin(q.a), ".3")) |
f'sin({a}) is {sin(a):.3}' |
Keeping track of context
Note that expressions don't capture context. In this case scoped can be used instead.
x = 5
# This raises an AttributeError
evaluate(var.x + 3)
# Pass any context variables along that you need.
evaluate(var.x + 3, x=x) # => 8
# Use scoped to capture the surrounding context (including x)
evaluate(scoped(var.x + 3)) # => 8
This also applies to modules:
import math
x = 2
evaluate(var.math.sqrt(var.x), x=x, math=math) # => 1.4
evaluate(scoped(var.math.sqrt(var.x))) # => 1.4
Similar libraries
Libraries that implement something similar:
- Macropy has quasiquote.
- SymPy - Symbolic manipulation, but its representation is different from Python.
- Polars - Writing
col.xcreates something like thisExpression-object.
Other:
- Fixing lambda - A blog post about alternative lambda syntaxes.
- Mini-lambda - Packages to "fix" lambda.
- Meta - A few utils to work on AST's.
- latexify and pytexit - Convert python to LaTeX.
- numexpr and aesara / pytensor - Fast evaluation of numerical expressions.
Useful references:
- python macros use cases - Stack-overflow discussion.
- Green tree snakes - Unofficial documentation of AST nodes.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uneval-0.2.0-py3-none-any.whl.
File metadata
- Download URL: uneval-0.2.0-py3-none-any.whl
- Upload date:
- Size: 14.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a576bdc898c254950803d74c1cb0c104b0a41c43328dc6ea9880c37c9baa25b
|
|
| MD5 |
97da318d5e7d206081fc1424ac77149d
|
|
| BLAKE2b-256 |
6bec68bb458bf505cd03a1dbb5e1659b805d28e29f19110816125212b9846b08
|