{"record":{"id":"a5648fba2cad4ca1","repo":"pandas-dev/pandas","slug":"the-prefix-is-only-supported-by-the-pandas-par","errorCode":null,"errorMessage":"The '@' prefix is only supported by the pandas parser","messagePattern":"The '@' prefix is only supported by the pandas parser","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/eval.py","lineNumber":175,"sourceCode":"    return s\n\n\ndef _check_for_locals(expr: str, stack_level: int, parser: str) -> None:\n    at_top_of_stack = stack_level == 0\n    not_pandas_parser = parser != \"pandas\"\n\n    if not_pandas_parser:\n        msg = \"The '@' prefix is only supported by the pandas parser\"\n    elif at_top_of_stack:\n        msg = (\n            \"The '@' prefix is not allowed in top-level eval calls.\\n\"\n            \"please refer to your variables by name without the '@' prefix.\"\n        )\n\n    if at_top_of_stack or not_pandas_parser:\n        for toknum, tokval in tokenize_string(expr):\n            if toknum == tokenize.OP and tokval == \"@\":\n                raise SyntaxError(msg)\n\n\n@set_module(\"pandas\")\ndef eval(\n    expr: str | BinOp,  # we leave BinOp out of the docstr bc it isn't for users\n    parser: str = \"pandas\",\n    engine: str | None = None,\n    local_dict=None,\n    global_dict=None,\n    resolvers=(),\n    level: int = 0,\n    target=None,\n    inplace: bool = False,\n) -> Any:\n    \"\"\"\n    Evaluate a Python expression as a string using various backends.\n\n    .. warning::","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/computation/eval.py#L157-L193","documentation":"The '@' prefix is a pandas-specific extension that lets an expression string reference a Python local variable; it works by token-rewriting '@x' into an internal sentinel via _replace_locals (expr.py:99) during the pandas preparser pass. When you pass parser='python', that preparser is bypassed (PythonExprVisitor uses identity preparser, expr.py:800), so the raw '@' token is meaningless and _check_for_locals rejects it before parsing. The library throws because the python parser has no mechanism to bind '@' to a stack-frame variable.","triggerScenarios":"Calling pd.eval('a + @b', parser='python') or df.query('col > @threshold', parser='python'). Anything that combines the literal '@' character in the expression string with parser set to a value other than the default 'pandas'.","commonSituations":"Switching parser to 'python' to gain strict Python semantics (e.g. floor division) while keeping existing '@'-prefixed variable references copied from a working df.query call. Copy-pasting query expressions between code paths that use different parsers. User-supplied filter strings that happen to contain '@'.","solutions":["Drop parser='python' and use the default parser='pandas' so the '@' prefix is honored.","Remove the '@' prefix and inject the variable explicitly via local_dict={'b': b}.","If you need python-parser semantics, pre-resolve the variable into the string with an f-string (only for trusted, non-user input)."],"exampleFix":"// before\npd.eval('a + @b', parser='python')\n// after\npd.eval('a + b', parser='python', local_dict={'b': b})","handlingStrategy":"validation","validationCode":"def check_at_prefix(expr: str, parser: str) -> None:\n    import tokenize\n    from pandas.core.computation.parsing import tokenize_string\n    if parser != 'pandas':\n        for toknum, tokval in tokenize_string(expr):\n            if toknum == tokenize.OP and tokval == '@':\n                raise ValueError(\n                    \"'@' prefix requires parser='pandas'; \"\n                    \"remove '@' or switch parser\"\n                )\n\n# call before pd.eval:\ncheck_at_prefix(expr, parser)","typeGuard":"def is_at_free_for_python_parser(expr: str, parser: str) -> bool:\n    return parser == 'pandas' or '@' not in expr","tryCatchPattern":"try:\n    pd.eval(expr, parser=parser)\nexcept SyntaxError as e:\n    if '@' in expr and parser != 'pandas':\n        # retry with pandas parser or strip locals\n        pd.eval(expr, parser='pandas')\n    else:\n        raise","preventionTips":["Standardize on parser='pandas' (the default) across the codebase unless you specifically need python-parser semantics.","When accepting user-supplied filter strings, sanitize or reject '@' unless parser='pandas'.","Keep '@'-prefixed references inside df.query/df.eval, not bare pd.eval with parser='python'."],"tags":["pandas","eval","query","parser","scope"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}