Source code for pqfilt._operators

"""Operator validation and application utilities."""

from __future__ import annotations

SUPPORTED_OPERATORS: tuple[str, ...] = (
    ">",
    ">=",
    "<",
    "<=",
    "==",
    "!=",
    "in",
    "not in",
    "is null",
    "is not null",
)


[docs] def validate_operator(op: str, col: str | None = None) -> None: """Validate that *op* is a supported filter operator. Parameters ---------- op : str Operator string. col : str, optional Column name for error-message context. Raises ------ ValueError If *op* is not in ``SUPPORTED_OPERATORS``. """ if op not in SUPPORTED_OPERATORS: ctx = f" for column '{col}'" if col else "" raise ValueError( f"Unsupported operator '{op}'{ctx}. " f"Supported: {', '.join(repr(o) for o in SUPPORTED_OPERATORS)}" )
def to_numeric_if_possible(value_str: str) -> int | float | bool | str: """Convert *value_str* to ``bool``, ``int``, or ``float`` if possible. Bool recognition is attempted **before** numeric coercion so that ``"True"`` / ``"False"`` (case-insensitive) become Python ``bool`` values rather than strings. This is required to avoid type mismatches when filtering boolean columns via pyarrow predicate pushdown. Prefers direct integer parsing. Floats with an integer value are also returned as ``int`` for compatibility with existing filter syntax. Examples -------- >>> to_numeric_if_possible("True") True >>> to_numeric_if_possible("false") False >>> to_numeric_if_possible("42") 42 >>> to_numeric_if_possible("3.14") 3.14 >>> to_numeric_if_possible("foo") 'foo' """ # Bool must be checked before float because float("True") raises ValueError, # but we want explicit bool semantics, not accidental numeric coercion. if value_str.lower() == "true": return True if value_str.lower() == "false": return False try: return int(value_str) except ValueError: pass try: numeric_val = float(value_str) except ValueError: return value_str if numeric_val.is_integer(): return int(numeric_val) return numeric_val