pandas-dev/pandas · error · NotImplementedError

UnaryOp only support invert type ops

Error message

UnaryOp only support invert type ops

What it means

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.

Solutions

  1. Rewrite the predicate to use '~' for negation: store.select('df', where='~(A > 0)').
  2. For unary minus, precompute the negated column and store it as a data_column: df['neg_A'] = -df['A'].
  3. Avoid non-invert unary operators in HDFStore where clauses; filter in pandas instead.

Example fix

// before
store.select('df', where='-A > 1')

// after
df['neg_A'] = -df['A']
store.put('df', df, format='table', data_columns=['neg_A'])
store.select('df', where='neg_A > 1')
Defensive patterns

Strategy: validation

Validate before calling

import re

def where_has_non_invert_unary(where: str) -> bool:
    # detect unary minus directly on an identifier (not folded to constant)
    return bool(re.search(r'(?<![\w\d)])-[A-Za-z_]', where))

assert not where_has_non_invert_unary(where_clause)

Type guard

def is_invert_op(op: str) -> bool:
    return op == '~'

Try / catch

try:
    store.select('df', where='-A > 1')
except NotImplementedError as e:
    if 'UnaryOp only support invert' in str(e):
        df = store.get('df')
        df[-df['A'] > 1]
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/6b4d1a0dafbc4c64. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/computation/pytables.py:429

            else:
                return None
        else:
            self.condition = self.generate(values[0])

        return self


class JointConditionBinOp(ConditionBinOp):
    # error: Signature of "evaluate" incompatible with supertype "BinOp"
    def evaluate(self) -> Self:  # type: ignore[override]
        self.condition = f"({self.lhs.condition} {self.op} {self.rhs.condition})"
        return self


class UnaryOp(ops.UnaryOp):
    def prune(self, klass):
        if self.op != "~":
            raise NotImplementedError("UnaryOp only support invert type ops")

        operand = self.operand
        operand = operand.prune(klass)

        if operand is not None and (
            (issubclass(klass, ConditionBinOp) and operand.condition is not None)
            or (
                not issubclass(klass, ConditionBinOp)
                and issubclass(klass, FilterBinOp)
                and operand.filter is not None
            )
        ):
            return operand.invert()
        return None


class PyTablesExprVisitor(BaseExprVisitor):
    const_type: ClassVar[type[ops.Term]] = Constant

View on GitHub (pinned to 3b7651241d)