pandas-dev/pandas · error · SyntaxError
The '@' prefix is not allowed in top-level eval calls. pleas
Error message
The '@' prefix is not allowed in top-level eval calls. please refer to your variables by name without the '@' prefix.
What it means
The '@' prefix resolves caller locals by walking up the call stack inside ensure_scope. A bare top-level pd.eval call (level=0, at_top_of_stack) has no enclosing DataFrame method frame to harvest locals from, so pandas refuses rather than silently resolving to the wrong scope. The fix the message points to is to reference variables by name (relying on local_dict/globals) or to use a DataFrame.eval/query call whose frame provides the scope.
Source
Thrown at pandas/core/computation/eval.py:175
return s
def _check_for_locals(expr: str, stack_level: int, parser: str) -> None:
at_top_of_stack = stack_level == 0
not_pandas_parser = parser != "pandas"
if not_pandas_parser:
msg = "The '@' prefix is only supported by the pandas parser"
elif at_top_of_stack:
msg = (
"The '@' prefix is not allowed in top-level eval calls.\n"
"please refer to your variables by name without the '@' prefix."
)
if at_top_of_stack or not_pandas_parser:
for toknum, tokval in tokenize_string(expr):
if toknum == tokenize.OP and tokval == "@":
raise SyntaxError(msg)
@set_module("pandas")
def eval(
expr: str | BinOp, # we leave BinOp out of the docstr bc it isn't for users
parser: str = "pandas",
engine: str | None = None,
local_dict=None,
global_dict=None,
resolvers=(),
level: int = 0,
target=None,
inplace: bool = False,
) -> Any:
"""
Evaluate a Python expression as a string using various backends.
.. warning::View on GitHub (pinned to 71959b8cb9)
Solutions
- Use DataFrame.eval or DataFrame.query instead of pd.eval, so the calling frame supplies the locals scope.
- Drop the '@' and pass the variable through local_dict, e.g. pd.eval('x + 1', local_dict={'x': x}).
- If you must call pd.eval from a wrapper, forward level appropriately so stack walking reaches your caller's frame.
Example fix
// before
result = pd.eval('@x + 1')
// after
result = pd.eval('x + 1', local_dict={'x': x}) Defensive patterns
Strategy: validation
Validate before calling
def check_top_level_at(expr: str, level: int) -> None:
import tokenize
from pandas.core.computation.parsing import tokenize_string
if level == 0:
for toknum, tokval in tokenize_string(expr):
if toknum == tokenize.OP and tokval == '@':
raise ValueError(
"'@' is disallowed in top-level pd.eval; "
"use df.query/df.eval or pass local_dict"
)
check_top_level_at(expr, level=0) Type guard
def is_safe_for_top_eval(expr: str) -> bool:
return '@' not in expr Try / catch
try:
pd.eval(expr)
except SyntaxError as e:
if '@' in expr:
# resolve locals explicitly and retry
pd.eval(expr.replace('@', ''), local_dict=locals())
else:
raise Prevention
- Never embed '@' in expressions passed to pd.eval at module/script level.
- Forward explicit local_dict instead of relying on '@' scope capture.
- Reserve '@' usage for df.query and df.eval where the calling frame is meaningful.
When it happens
Trigger: pd.eval('@x + 1') called directly at module level, in a script, or in any frame where level resolves to 0 (the default level kwarg). Any direct pd.eval invocation that embeds a local-variable reference with '@'.
Common situations: Promoting a df.query('@threshold > col') snippet to a standalone pd.eval call without a DataFrame context. Notebooks where users expect @ to work like IPython magic. Calling pd.eval inside a helper but forgetting to forward level.
Related errors
- The '@' prefix is only supported by the pandas parser
- expr must be a string to be evaluated, {type(expr)} given
- multi-line expressions are only valid in the context of data
- Multi-line expressions are only valid if all expressions con
- Cannot operate inplace if there is no assignment
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/3ae9cc93364f6012.
Report an issue: GitHub.