Repository: pandas-dev/pandas
File: pandas/core/col.py (Python)

Code before:
        return Expr(lambda df: self._func(df).__le__(other))

    def __lt__(self, other: Any) -> Expr:
        if isinstance(other, Expr):
            return Expr(lambda df: self._func(df).__lt__(other._func(df)))
        return Expr(lambda df: self._func(df).__lt__(other))

    def __eq__(self, other: object) -> Expr:  # type: ignore[override]
        if isinstance(other, Expr):
            return Expr(lambda df: self._func(df).__eq__(other._func(df)))
        return Expr(lambda df: self._func(df).__eq__(other))

    def __ne__(self, other: object) -> Expr:  # type: ignore[override]
        if isinstance(other, Expr):
            return Expr(lambda df: self._func(df).__ne__(other._func(df)))
        return Expr(lambda df: self._func(df).__ne__(other))

    def __mod__(self, other: Any) -> Expr:
        if isinstance(other, Expr):
            return Expr(lambda df: self._func(df).__mod__(other._func(df)))
        return Expr(lambda df: self._func(df).__mod__(other))

    # Everything else

    # Function "pandas.core.col.Expr.str" is not valid as a type
    def __getattr__(self, attr: str, /) -> Any:  # type: ignore[valid-type]
        def func(df: DataFrame, *args: Any, **kwargs: Any) -> Any:
            parsed_args = parse_args(df, *args)
            parsed_kwargs = parse_kwargs(df, **kwargs)
            return getattr(self(df), attr)(*parsed_args, **parsed_kwargs)

        return lambda *args, **kwargs: Expr(lambda df: func(df, *args, **kwargs))


class NamespaceExpr:
    def __init__(self, func: Callable[[DataFrame], Any], namespace: str) -> None:
        self._func = func
        self._namespace = namespace

    def __getattr__(self, attr: str) -> Any:
        if isinstance(getattr(getattr(Series, self._namespace), attr), property):
            return Expr(
                lambda df: getattr(getattr(self._func(df), self._namespace), attr)
            )

        def func(df: DataFrame, *args: Any, **kwargs: Any) -> Any:
            parsed_args = parse_args(df, *args)
            parsed_kwargs = parse_kwargs(df, **kwargs)
            return getattr(getattr(self._func(df), self._namespace), attr)(
                *parsed_args, **parsed_kwargs
            )

Review comment (suggestion):
I think `mypy` will understand better if you move the namespace accessors *after* any annotations that have `str` or `list` 

https://github.com/MarcoGorelli/pandas/blob/9fcaba33e93241145ae464d243e516b5bcd58396/pandas/core/col.py#L43-L66

Code after:
    def __ge__(self, other: Any) -> Expression:
        return self._with_binary_op("__ge__", other)

    def __gt__(self, other: Any) -> Expression:
        return self._with_binary_op("__gt__", other)

    def __le__(self, other: Any) -> Expression:
        return self._with_binary_op("__le__", other)

    def __lt__(self, other: Any) -> Expression:
        return self._with_binary_op("__lt__", other)

    def __eq__(self, other: object) -> Expression:  # type: ignore[override]
        return self._with_binary_op("__eq__", other)

    def __ne__(self, other: object) -> Expression:  # type: ignore[override]
        return self._with_binary_op("__ne__", other)

    def __mod__(self, other: Any) -> Expression:
        return self._with_binary_op("__mod__", other)

    def __rmod__(self, other: Any) -> Expression:
        return self._with_binary_op("__rmod__", other)

    def __array_ufunc__(
        self, ufunc: Callable[..., Any], method: str, *inputs: Any, **kwargs: Any
    ) -> Expression:
        def func(df: DataFrame) -> Any:
            parsed_inputs = _parse_args(df, *inputs)
            parsed_kwargs = _parse_kwargs(df, *kwargs)
            return ufunc(*parsed_inputs, **parsed_kwargs)

        args_str = _pretty_print_args_kwargs(*inputs, **kwargs)
        repr_str = f"{ufunc.__name__}({args_str})"

        return Expression(func, repr_str)

    # Everything else
    def __getattr__(self, attr: str, /) -> Any:
        if attr in Series._accessors:
            return NamespaceExpression(self, attr)

        def func(df: DataFrame, *args: Any, **kwargs: Any) -> Any:
            parsed_args = _parse_args(df, *args)
            parsed_kwargs = _parse_kwargs(df, **kwargs)
            return getattr(self(df), attr)(*parsed_args, **parsed_kwargs)

        def wrapper(*args: Any, **kwargs: Any) -> Expression:
            args_str = _pretty_print_args_kwargs(*args, **kwargs)
            repr_str = f"{self._repr_str}.{attr}({args_str})"