Files
2025-09-07 22:09:54 +02:00

84 lines
2.9 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING, Any, Callable
from ibis.expr.datatypes import Timestamp
from narwhals._sql.expr_str import SQLExprStringNamespace
from narwhals._utils import _is_naive_format, not_implemented
if TYPE_CHECKING:
import ibis.expr.types as ir
from typing_extensions import TypeAlias
from narwhals._ibis.expr import IbisExpr
IntoStringValue: TypeAlias = "str | ir.StringValue"
class IbisExprStringNamespace(SQLExprStringNamespace["IbisExpr"]):
def strip_chars(self, characters: str | None) -> IbisExpr:
if characters is not None:
msg = "Ibis does not support `characters` argument in `str.strip_chars`"
raise NotImplementedError(msg)
return self.compliant._with_callable(lambda expr: expr.strip())
def _replace_all(
self, pattern: IntoStringValue, value: IntoStringValue
) -> Callable[..., ir.StringValue]:
def fn(expr: ir.StringColumn) -> ir.StringValue:
return expr.re_replace(pattern, value)
return fn
def _replace_all_literal(
self, pattern: IntoStringValue, value: IntoStringValue
) -> Callable[..., ir.StringValue]:
def fn(expr: ir.StringColumn) -> ir.StringValue:
return expr.replace(pattern, value) # pyright: ignore[reportArgumentType]
return fn
def replace_all(
self, pattern: str, value: str | IbisExpr, *, literal: bool
) -> IbisExpr:
fn = self._replace_all_literal if literal else self._replace_all
if isinstance(value, str):
return self.compliant._with_callable(fn(pattern, value))
return self.compliant._with_elementwise(
lambda expr, value: fn(pattern, value)(expr), value=value
)
def _to_datetime(self, format: str) -> Callable[..., ir.TimestampValue]:
def fn(expr: ir.StringColumn) -> ir.TimestampValue:
return expr.as_timestamp(format)
return fn
def _to_datetime_naive(self, format: str) -> Callable[..., ir.TimestampValue]:
def fn(expr: ir.StringColumn) -> ir.TimestampValue:
dtype: Any = Timestamp(timezone=None)
return expr.as_timestamp(format).cast(dtype)
return fn
def to_datetime(self, format: str | None) -> IbisExpr:
if format is None:
msg = "Cannot infer format with Ibis backend"
raise NotImplementedError(msg)
fn = self._to_datetime_naive if _is_naive_format(format) else self._to_datetime
return self.compliant._with_callable(fn(format))
def to_date(self, format: str | None) -> IbisExpr:
if format is None:
msg = "Cannot infer format with Ibis backend"
raise NotImplementedError(msg)
def fn(expr: ir.StringColumn) -> ir.DateValue:
return expr.as_date(format)
return self.compliant._with_callable(fn)
replace = not_implemented()