Skip to content

expression

expression ¤

AST-restricted Python expression compiler.

Lambda-rule triggers are written as short Python-syntax expressions ("(torque > 75) & (state == 'run')"). To run them safely we parse with :func:ast.parse in mode="eval" and walk the tree, rejecting any node that is not on a small allowlist.

Operator gotcha: Python's bitwise & / | (the vectorized ones pandas understands) bind tighter than comparison operators, so you must wrap each comparison in parentheses: "(x > 1) & (y < 0)" — not "x > 1 & y < 0". This matches the convention used by pandas.eval and DataFrame.query.

Why an AST whitelist over pandas.eval or polars.expr?

  • Full control over error messages.
  • Reliable Int64 / nullable-bool handling.
  • Zero extra dependencies — stdlib :mod:ast only.
  • The whitelist refuses dunders, attribute access (except the .isin([...]) method), imports, comprehensions, and any function call outside of abs, min, max — so an LLM-proposed expression cannot exfiltrate or mutate state.
  • Python's and / or / not / in are not element-wise on columns; they are rejected at compile time with a hint to &, |, ~ and .isin(...).

UnsafeExpression ¤

Bases: ValueError

Raised when a trigger expression contains a disallowed AST node.

compile_expression ¤

compile_expression(
    expression: str,
) -> Callable[[pd.DataFrame], pd.Series]

Compile a trigger expression to a vectorized boolean mask function.

Python's and / or / not / in, chained comparisons and min / max over columns are rejected here, with a hint to the element-wise &, |, ~ and column.isin([...]).

Parameters:

Name Type Description Default
expression str

The trigger, e.g. "(torque > 75) & (state == 'run')".

required

Returns:

Type Description
Callable[[DataFrame], Series]

A callable that takes a DataFrame and returns a boolean Series

Callable[[DataFrame], Series]

aligned with its rows (missing -> False).

Raises:

Type Description
UnsafeExpression

For disallowed or non-element-wise syntax. The callable raises :class:~ts_shape.errors.ColumnNotFoundError for a name that is not a column and ValueError when the result is not boolean.