{"record":{"id":"f2bb8fcae06d8e74","repo":"pandas-dev/pandas","slug":"invalid-attribute-context-type-ctx-name","errorCode":null,"errorMessage":"Invalid Attribute context {type(ctx).__name__}","messagePattern":"Invalid Attribute context (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/expr.py","lineNumber":665,"sourceCode":"        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:\n                v = getattr(resolved, attr)\n                name = self.env.add_tmp(v)\n                return self.term_type(name, self.env)\n            except AttributeError:\n                # something like datetime.datetime where scope is overridden\n                if isinstance(value, ast.Name) and value.id == attr:\n                    return resolved\n                raise\n\n        raise ValueError(f\"Invalid Attribute context {type(ctx).__name__}\")\n\n    def visit_Call(self, node, side=None, **kwargs):\n        if isinstance(node.func, ast.Attribute) and node.func.attr != \"__call__\":\n            res = self.visit_Attribute(node.func)\n        elif not isinstance(node.func, ast.Name):\n            raise TypeError(\"Only named functions are supported\")\n        else:\n            try:\n                res = self.visit(node.func)\n            except UndefinedVariableError:\n                # Check if this is a supported function name\n                try:\n                    res = FuncNode(node.func.id)\n                except ValueError:\n                    # Raise original error\n                    raise\n\n        if res is None:","sourceCodeStart":647,"sourceCodeEnd":683,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/computation/expr.py#L647-L683","documentation":"visit_Attribute (expr.py:643) only handles ast.Load context — i.e. reading an attribute like df.col. Any other context (ast.Store for assignment targets, ast.Del for deletion) is meaningless inside an eval expression and falls through to raise ValueError naming the context class. In practice the visit_Assign check for ast.Name usually catches attribute-LHS first, so this fires for unusual attribute-in-store-context AST shapes.","triggerScenarios":"An attribute access appearing in a Store or Del AST context inside the expression tree — typically from hand-built AST or from preprocessing that produces non-Load attribute nodes.","commonSituations":"Internal tooling that constructs AST nodes directly. Parsers/preparsers that change node contexts. Very rarely reachable from user strings because earlier checks reject attribute assignment.","solutions":["Rewrite so attributes are only read, never assigned/deleted inside eval.","Do attribute assignment in plain Python outside the eval string.","If building AST programmatically, ensure Attribute nodes use ast.Load."],"exampleFix":"// before\n# attribute in a store context (rare, usually hand-built AST)\n// after\n# assign to a plain name and set the attribute in Python:\ndf.eval('tmp = a + b')\ndf.obj.tmp = df['tmp']","handlingStrategy":"validation","validationCode":"import ast\n\ndef validate_attribute_load_only(expr: str) -> None:\n    for node in ast.walk(ast.parse(expr, mode='eval')):\n        if isinstance(node, ast.Attribute) and not isinstance(node.ctx, ast.Load):\n            raise ValueError(\n                f'attribute in {type(node.ctx).__name__} context not supported'\n            )\n\nvalidate_attribute_load_only(expr)","typeGuard":"import ast\n\ndef attributes_are_load_only(expr: str) -> bool:\n    return all(\n        isinstance(n.ctx, ast.Load)\n        for n in ast.walk(ast.parse(expr, mode='eval'))\n        if isinstance(n, ast.Attribute)\n    )","tryCatchPattern":"try:\n    df.eval(expr)\nexcept ValueError as e:\n    if 'Invalid Attribute context' in str(e):\n        # move attribute assignment out of eval into Python\n        setattr(obj, attr, value)\n    raise","preventionTips":["Use attributes only for reads inside eval expressions.","Do attribute writes via the object API in plain Python.","If constructing AST, set Attribute.ctx to ast.Load."],"tags":["pandas","eval","attribute","ast-context"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}