{"record":{"id":"65f07ed9f466e0f9","repo":"pandas-dev/pandas","slug":"multi-line-expressions-are-only-valid-if-all-expre","errorCode":null,"errorMessage":"Multi-line expressions are only valid if all expressions contain an assignment","messagePattern":"Multi-line expressions are only valid if all expressions contain an assignment","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/eval.py","lineNumber":404,"sourceCode":"                )\n            )\n        ):\n            warnings.warn(\n                \"Engine has switched to 'python' because numexpr does not support \"\n                \"extension array dtypes. Please set your engine to python manually.\",\n                RuntimeWarning,\n                stacklevel=find_stack_level(),\n            )\n            engine = \"python\"\n\n        # construct the engine and evaluate the parsed expression\n        eng = ENGINES[engine]\n        eng_inst = eng(parsed_expr)\n        ret = eng_inst.evaluate()\n\n        if parsed_expr.assigner is None:\n            if multi_line:\n                raise ValueError(\n                    \"Multi-line expressions are only valid \"\n                    \"if all expressions contain an assignment\"\n                )\n            if inplace:\n                raise ValueError(\"Cannot operate inplace if there is no assignment\")\n\n        # assign if needed\n        assigner = parsed_expr.assigner\n        if env.target is not None and assigner is not None:\n            target_modified = True\n\n            # if returning a copy, copy only on the first assignment\n            if not inplace and first_expr:\n                try:\n                    target = env.target\n                    if isinstance(target, NDFrame):\n                        target = target.copy(deep=False)\n                    else:","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/computation/eval.py#L386-L422","documentation":"When a multi-line expression is allowed (target supplied), every sub-expression must be an assignment because the loop in eval.py:361 assigns sequentially and only the final return value is non-None. If any line is a bare expression (parsed_expr.assigner is None at eval.py:402), there is no column to assign and no meaningful return, so pandas raises. This keeps multi-line semantics unambiguous.","triggerScenarios":"df.eval('a = b + 1\\nb + 2') — the second line has no '='. Any multi-line df.eval string where at least one line is a pure expression rather than an assignment.","commonSituations":"Appending a final 'return' line to a sequence of assignments expecting it to be yielded. Mixing query-style filters with column assignments in one string.","solutions":["Make every line an assignment, e.g. df.eval('a = b + 1\\nc = b + 2').","Move the bare expression into a separate, single-line df.eval/df.query call.","Capture the bare line's result by assigning it to a new column."],"exampleFix":"// before\ndf.eval('a = b + 1\\nb + 2')\n// after\ndf.eval('a = b + 1\\nc = b + 2')","handlingStrategy":"validation","validationCode":"def validate_multiline_all_assigned(expr: str) -> None:\n    import ast\n    for line in (l for l in expr.splitlines() if l.strip()):\n        tree = ast.parse(line, mode='exec')\n        if not any(isinstance(n, ast.Assign) for n in tree.body):\n            raise ValueError(\n                f'Every multi-line expression must assign; offending line: {line!r}'\n            )\n\nvalidate_multiline_all_assigned(multiline_expr)","typeGuard":"import ast\n\ndef all_lines_assign(expr: str) -> bool:\n    return all(\n        any(isinstance(n, ast.Assign) for n in ast.parse(l, mode='exec').body)\n        for l in (s for s in expr.splitlines() if s.strip())\n    )","tryCatchPattern":"try:\n    df.eval(expr)\nexcept ValueError as e:\n    if 'must contain an assignment' in str(e):\n        # split assignment lines from any bare expression and handle separately\n        ...\n    raise","preventionTips":["Author multi-line eval strings with one assignment per line.","Run a quick ast.parse check on each line when generating strings programmatically.","Avoid appending a 'return' line to assignment blocks."],"tags":["pandas","eval","multi-line","assignment"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}