{"record":{"id":"6b4d1a0dafbc4c64","repo":"pandas-dev/pandas","slug":"unaryop-only-support-invert-type-ops","errorCode":null,"errorMessage":"UnaryOp only support invert type ops","messagePattern":"UnaryOp only support invert type ops","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/pytables.py","lineNumber":429,"sourceCode":"            else:\n                return None\n        else:\n            self.condition = self.generate(values[0])\n\n        return self\n\n\nclass JointConditionBinOp(ConditionBinOp):\n    # error: Signature of \"evaluate\" incompatible with supertype \"BinOp\"\n    def evaluate(self) -> Self:  # type: ignore[override]\n        self.condition = f\"({self.lhs.condition} {self.op} {self.rhs.condition})\"\n        return self\n\n\nclass UnaryOp(ops.UnaryOp):\n    def prune(self, klass):\n        if self.op != \"~\":\n            raise NotImplementedError(\"UnaryOp only support invert type ops\")\n\n        operand = self.operand\n        operand = operand.prune(klass)\n\n        if operand is not None and (\n            (issubclass(klass, ConditionBinOp) and operand.condition is not None)\n            or (\n                not issubclass(klass, ConditionBinOp)\n                and issubclass(klass, FilterBinOp)\n                and operand.filter is not None\n            )\n        ):\n            return operand.invert()\n        return None\n\n\nclass PyTablesExprVisitor(BaseExprVisitor):\n    const_type: ClassVar[type[ops.Term]] = Constant","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/computation/pytables.py#L411-L447","documentation":"Raised in the PyTables UnaryOp.prune when self.op is not '~'. The HDFStore where-clause evaluator only supports the bitwise-invert unary operator '~' (and ast.Not is mapped to '~' in visit_UnaryOp). Other unary forms such as unary minus '-' are handled earlier (USub returns a constant) and 'not' is mapped, so reaching this branch implies an unsupported unary operator slipped through, e.g. a constructed UnaryOp('+', ...) or 'not' that bypassed the mapping.","triggerScenarios":"store.select('df', where='-A > 1') where '-' is not folded into a constant by visit_UnaryOp (e.g. operand is non-numeric). Programmatic construction of a pytables UnaryOp with an operator other than '~'. Internal calls passing 'not' or '+' into prune.","commonSituations":"Using unary minus on a non-numeric column inside a where clause. Custom subclasses of the PyTables visitor that emit UnaryOp nodes with non-invert ops. AST rewriting that loses the USub folding.","solutions":["Rewrite the predicate to use '~' for negation: store.select('df', where='~(A > 0)').","For unary minus, precompute the negated column and store it as a data_column: df['neg_A'] = -df['A'].","Avoid non-invert unary operators in HDFStore where clauses; filter in pandas instead."],"exampleFix":"// before\nstore.select('df', where='-A > 1')\n\n// after\ndf['neg_A'] = -df['A']\nstore.put('df', df, format='table', data_columns=['neg_A'])\nstore.select('df', where='neg_A > 1')","handlingStrategy":"validation","validationCode":"import re\n\ndef where_has_non_invert_unary(where: str) -> bool:\n    # detect unary minus directly on an identifier (not folded to constant)\n    return bool(re.search(r'(?<![\\w\\d)])-[A-Za-z_]', where))\n\nassert not where_has_non_invert_unary(where_clause)","typeGuard":"def is_invert_op(op: str) -> bool:\n    return op == '~'","tryCatchPattern":"try:\n    store.select('df', where='-A > 1')\nexcept NotImplementedError as e:\n    if 'UnaryOp only support invert' in str(e):\n        df = store.get('df')\n        df[-df['A'] > 1]\n    else:\n        raise","preventionTips":["Use only '~' as a unary operator in HDFStore where clauses.","Precompute negated columns and store them as data_columns.","Filter in pandas for unary-minus predicates."],"tags":["pandas","hdfstore","pytables","unary-operator","where"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}