{"record":{"id":"02c7712490254a56","repo":"pandas-dev/pandas","slug":"left-hand-side-of-an-assignment-must-be-a-single-r","errorCode":null,"errorMessage":"left hand side of an assignment must be a single resolvable name","messagePattern":"left hand side of an assignment must be a single resolvable name","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/expr.py","lineNumber":637,"sourceCode":"        set the assigner at the top level, must be a Name node which\n        might or might not exist in the resolvers\n\n        \"\"\"\n        if len(node.targets) != 1:\n            raise SyntaxError(\"can only assign a single expression\")\n        if not isinstance(node.targets[0], ast.Name):\n            raise SyntaxError(\"left hand side of an assignment must be a single name\")\n        if self.env.target is None:\n            raise ValueError(\"cannot assign without a target object\")\n\n        try:\n            assigner = self.visit(node.targets[0], **kwargs)\n        except UndefinedVariableError:\n            assigner = node.targets[0].id\n\n        self.assigner = getattr(assigner, \"name\", assigner)\n        if self.assigner is None:\n            raise SyntaxError(\n                \"left hand side of an assignment must be a single resolvable name\"\n            )\n\n        return self.visit(node.value, **kwargs)\n\n    def visit_Attribute(self, node, **kwargs):\n        attr = node.attr\n        value = node.value\n\n        ctx = node.ctx\n        if isinstance(ctx, ast.Load):\n            # resolve the value\n            visited_value = self.visit(value)\n            if hasattr(visited_value, \"value\"):\n                resolved = visited_value.value\n            else:\n                resolved = visited_value(self.env)\n            try:","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/computation/expr.py#L619-L655","documentation":"Raised by visit_Assign() when, after visiting the assignment target, the resolved assigner name is None. This happens when the left-hand side Name resolves to something whose .name attribute is None or which yields no usable name — meaning the lhs is not a single resolvable name. It is a secondary guard after the ast.Name check, covering cases where the Name node exists but does not resolve to a concrete identifier.","triggerScenarios":"Assignment lhs is an ast.Name whose id resolves to an object with name=None, or a corner case where getattr(assigner, 'name', assigner) returns None. Rare in practice; usually preceded by the ast.Name check.","commonSituations":"Edge cases with custom resolvers or scope objects that return Terms with no name; programmatic expression construction that produces malformed Name nodes.","solutions":["Ensure the lhs is a simple, defined column name that pandas can resolve.","Simplify the assignment lhs to a plain identifier string.","If building expressions programmatically, validate that every assignment target is a non-empty name."],"exampleFix":"// before\ndf.eval('@obj = col_a + col_b')  # obj resolves to nameless term\n\n// after\ndf.eval('new_col = col_a + col_b')","handlingStrategy":"validation","validationCode":"import re\ndef lhs_is_resolvable_name(expr: str) -> bool:\n    m = re.match(r'^\\s*([A-Za-z_]\\w*)\\s*=', expr)\n    return bool(m) and m.group(1) != ''\nif not lhs_is_resolvable_name(expr):\n    raise ValueError('Assignment lhs must resolve to a single name')\ndf.eval(expr)","typeGuard":null,"tryCatchPattern":"try:\n    df.eval(expr)\nexcept SyntaxError as e:\n    if 'resolvable name' in str(e):\n        # simplify the lhs\n        ...","preventionTips":["Use a plain column-name identifier on the assignment lhs.","Avoid complex resolver objects that yield nameless terms.","Validate lhs is a single identifier before eval."],"tags":["pandas","eval","assignment","resolver","syntax-error"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}