This commit is contained in:
2025-09-07 22:09:54 +02:00
parent e1b817252c
commit 2fc0d000b6
7796 changed files with 2159515 additions and 933 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from narwhals._utils import inherit_doc
from narwhals.dtypes import (
Array,
Binary,
Boolean,
Categorical,
Date,
Datetime as NwDatetime,
Decimal,
DType,
Duration as NwDuration,
Enum as NwEnum,
Field,
Float32,
Float64,
FloatType,
Int8,
Int16,
Int32,
Int64,
Int128,
IntegerType,
List,
NestedType,
NumericType,
Object,
SignedIntegerType,
String,
Struct,
Time,
UInt8,
UInt16,
UInt32,
UInt64,
UInt128,
Unknown,
UnsignedIntegerType,
)
if TYPE_CHECKING:
from datetime import timezone
from narwhals.typing import TimeUnit
class Datetime(NwDatetime):
@inherit_doc(NwDatetime)
def __init__(
self, time_unit: TimeUnit = "us", time_zone: str | timezone | None = None
) -> None:
super().__init__(time_unit, time_zone)
def __hash__(self) -> int:
return hash(self.__class__)
class Duration(NwDuration):
@inherit_doc(NwDuration)
def __init__(self, time_unit: TimeUnit = "us") -> None:
super().__init__(time_unit)
def __hash__(self) -> int:
return hash(self.__class__)
class Enum(NwEnum):
"""A fixed categorical encoding of a unique set of strings.
Polars has an Enum data type, while pandas and PyArrow do not.
Examples:
>>> import polars as pl
>>> import narwhals.stable.v1 as nw
>>> data = ["beluga", "narwhal", "orca"]
>>> s_native = pl.Series(data, dtype=pl.Enum(data))
>>> nw.from_native(s_native, series_only=True).dtype
Enum
"""
def __init__(self) -> None:
super(NwEnum, self).__init__()
def __eq__(self, other: DType | type[DType]) -> bool: # type: ignore[override]
if type(other) is type:
return other in {type(self), NwEnum}
return isinstance(other, type(self))
def __hash__(self) -> int: # pragma: no cover
return super(NwEnum, self).__hash__()
def __repr__(self) -> str: # pragma: no cover
return super(NwEnum, self).__repr__()
__all__ = [
"Array",
"Binary",
"Boolean",
"Categorical",
"DType",
"Date",
"Datetime",
"Decimal",
"Duration",
"Enum",
"Field",
"Float32",
"Float64",
"FloatType",
"Int8",
"Int16",
"Int32",
"Int64",
"Int128",
"IntegerType",
"List",
"NestedType",
"NumericType",
"Object",
"SignedIntegerType",
"String",
"Struct",
"Time",
"UInt8",
"UInt16",
"UInt32",
"UInt64",
"UInt128",
"Unknown",
"UnsignedIntegerType",
]

View File

@ -0,0 +1,10 @@
from __future__ import annotations
from narwhals._compliant.typing import CompliantNamespaceT_co
from narwhals._namespace import Namespace as NwNamespace
from narwhals._utils import Version
__all__ = ["Namespace"]
class Namespace(NwNamespace[CompliantNamespaceT_co], version=Version.V1): ...

View File

@ -0,0 +1,156 @@
from __future__ import annotations
import sys
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
import cudf
import dask.dataframe as dd
import ibis
import modin.pandas as mpd
import pandas as pd
import polars as pl
import pyarrow as pa
from typing_extensions import TypeIs
from narwhals.dependencies import (
IMPORT_HOOKS,
get_cudf,
get_dask_dataframe,
get_ibis,
get_modin,
get_numpy,
get_pandas,
get_polars,
get_pyarrow,
is_into_dataframe,
is_into_series,
is_narwhals_dataframe,
is_narwhals_lazyframe,
is_narwhals_series,
is_numpy_array,
is_pandas_index,
)
def is_pandas_dataframe(df: Any) -> TypeIs[pd.DataFrame]:
"""Check whether `df` is a pandas DataFrame without importing pandas."""
return ((pd := get_pandas()) is not None and isinstance(df, pd.DataFrame)) or any(
(mod := sys.modules.get(module_name, None)) is not None
and isinstance(df, mod.pandas.DataFrame)
for module_name in IMPORT_HOOKS
)
def is_pandas_series(ser: Any) -> TypeIs[pd.Series[Any]]:
"""Check whether `ser` is a pandas Series without importing pandas."""
return ((pd := get_pandas()) is not None and isinstance(ser, pd.Series)) or any(
(mod := sys.modules.get(module_name, None)) is not None
and isinstance(ser, mod.pandas.Series)
for module_name in IMPORT_HOOKS
)
def is_modin_dataframe(df: Any) -> TypeIs[mpd.DataFrame]:
"""Check whether `df` is a modin DataFrame without importing modin."""
return (mpd := get_modin()) is not None and isinstance(df, mpd.DataFrame)
def is_modin_series(ser: Any) -> TypeIs[mpd.Series]:
"""Check whether `ser` is a modin Series without importing modin."""
return (mpd := get_modin()) is not None and isinstance(ser, mpd.Series)
def is_cudf_dataframe(df: Any) -> TypeIs[cudf.DataFrame]:
"""Check whether `df` is a cudf DataFrame without importing cudf."""
return (cudf := get_cudf()) is not None and isinstance(df, cudf.DataFrame)
def is_cudf_series(ser: Any) -> TypeIs[cudf.Series[Any]]:
"""Check whether `ser` is a cudf Series without importing cudf."""
return (cudf := get_cudf()) is not None and isinstance(ser, cudf.Series)
def is_dask_dataframe(df: Any) -> TypeIs[dd.DataFrame]:
"""Check whether `df` is a Dask DataFrame without importing Dask."""
return (dd := get_dask_dataframe()) is not None and isinstance(df, dd.DataFrame)
def is_ibis_table(df: Any) -> TypeIs[ibis.Table]:
"""Check whether `df` is a Ibis Table without importing Ibis."""
return (ibis := get_ibis()) is not None and isinstance(df, ibis.expr.types.Table)
def is_polars_dataframe(df: Any) -> TypeIs[pl.DataFrame]:
"""Check whether `df` is a Polars DataFrame without importing Polars."""
return (pl := get_polars()) is not None and isinstance(df, pl.DataFrame)
def is_polars_lazyframe(df: Any) -> TypeIs[pl.LazyFrame]:
"""Check whether `df` is a Polars LazyFrame without importing Polars."""
return (pl := get_polars()) is not None and isinstance(df, pl.LazyFrame)
def is_polars_series(ser: Any) -> TypeIs[pl.Series]:
"""Check whether `ser` is a Polars Series without importing Polars."""
return (pl := get_polars()) is not None and isinstance(ser, pl.Series)
def is_pyarrow_chunked_array(ser: Any) -> TypeIs[pa.ChunkedArray[Any]]:
"""Check whether `ser` is a PyArrow ChunkedArray without importing PyArrow."""
return (pa := get_pyarrow()) is not None and isinstance(ser, pa.ChunkedArray)
def is_pyarrow_table(df: Any) -> TypeIs[pa.Table]:
"""Check whether `df` is a PyArrow Table without importing PyArrow."""
return (pa := get_pyarrow()) is not None and isinstance(df, pa.Table)
def is_pandas_like_dataframe(df: Any) -> bool:
"""Check whether `df` is a pandas-like DataFrame without doing any imports.
By "pandas-like", we mean: pandas, Modin, cuDF.
"""
return is_pandas_dataframe(df) or is_modin_dataframe(df) or is_cudf_dataframe(df)
def is_pandas_like_series(ser: Any) -> bool:
"""Check whether `ser` is a pandas-like Series without doing any imports.
By "pandas-like", we mean: pandas, Modin, cuDF.
"""
return is_pandas_series(ser) or is_modin_series(ser) or is_cudf_series(ser)
__all__ = [
"get_cudf",
"get_ibis",
"get_modin",
"get_numpy",
"get_pandas",
"get_polars",
"get_pyarrow",
"is_cudf_dataframe",
"is_cudf_series",
"is_dask_dataframe",
"is_ibis_table",
"is_into_dataframe",
"is_into_series",
"is_modin_dataframe",
"is_modin_series",
"is_narwhals_dataframe",
"is_narwhals_lazyframe",
"is_narwhals_series",
"is_numpy_array",
"is_pandas_dataframe",
"is_pandas_index",
"is_pandas_like_dataframe",
"is_pandas_like_series",
"is_pandas_series",
"is_polars_dataframe",
"is_polars_lazyframe",
"is_polars_series",
"is_pyarrow_chunked_array",
"is_pyarrow_table",
]

View File

@ -0,0 +1,77 @@
from __future__ import annotations
from narwhals.stable.v1._dtypes import (
Array,
Binary,
Boolean,
Categorical,
Date,
Datetime,
Decimal,
DType,
Duration,
Enum,
Field,
Float32,
Float64,
FloatType,
Int8,
Int16,
Int32,
Int64,
Int128,
IntegerType,
List,
NestedType,
NumericType,
Object,
SignedIntegerType,
String,
Struct,
Time,
UInt8,
UInt16,
UInt32,
UInt64,
UInt128,
Unknown,
UnsignedIntegerType,
)
__all__ = [
"Array",
"Binary",
"Boolean",
"Categorical",
"DType",
"Date",
"Datetime",
"Decimal",
"Duration",
"Enum",
"Field",
"Float32",
"Float64",
"FloatType",
"Int8",
"Int16",
"Int32",
"Int64",
"Int128",
"IntegerType",
"List",
"NestedType",
"NumericType",
"Object",
"SignedIntegerType",
"String",
"Struct",
"Time",
"UInt8",
"UInt16",
"UInt32",
"UInt64",
"UInt128",
"Unknown",
"UnsignedIntegerType",
]

View File

@ -0,0 +1,23 @@
from __future__ import annotations
from narwhals.selectors import (
all,
boolean,
by_dtype,
categorical,
datetime,
matches,
numeric,
string,
)
__all__ = [
"all",
"boolean",
"by_dtype",
"categorical",
"datetime",
"matches",
"numeric",
"string",
]

View File

@ -0,0 +1,192 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Protocol, TypeVar, Union
if TYPE_CHECKING:
import sys
from collections.abc import Iterable, Sized
from narwhals.stable.v1 import DataFrame, LazyFrame
if sys.version_info >= (3, 10):
from typing import TypeAlias
else:
from typing_extensions import TypeAlias
from narwhals.stable.v1 import Expr, Series
# All dataframes supported by Narwhals have a
# `columns` property. Their similarities don't extend
# _that_ much further unfortunately...
class NativeFrame(Protocol):
@property
def columns(self) -> Any: ...
def join(self, *args: Any, **kwargs: Any) -> Any: ...
class NativeDataFrame(Sized, NativeFrame, Protocol): ...
class NativeLazyFrame(NativeFrame, Protocol):
def explain(self, *args: Any, **kwargs: Any) -> Any: ...
class NativeSeries(Sized, Iterable[Any], Protocol):
def filter(self, *args: Any, **kwargs: Any) -> Any: ...
class DataFrameLike(Protocol):
def __dataframe__(self, *args: Any, **kwargs: Any) -> Any: ...
IntoExpr: TypeAlias = Union["Expr", str, "Series[Any]"]
"""Anything which can be converted to an expression.
Use this to mean "either a Narwhals expression, or something
which can be converted into one". For example, `exprs` in `DataFrame.select` is
typed to accept `IntoExpr`, as it can either accept a `nw.Expr`
(e.g. `df.select(nw.col('a'))`) or a string which will be interpreted as a
`nw.Expr`, e.g. `df.select('a')`.
"""
IntoDataFrame: TypeAlias = Union["NativeDataFrame", "DataFrameLike"]
"""Anything which can be converted to a Narwhals DataFrame.
Use this if your function accepts a narwhalifiable object but doesn't care about its backend.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import IntoDataFrame
>>> def agnostic_shape(df_native: IntoDataFrame) -> tuple[int, int]:
... df = nw.from_native(df_native, eager_only=True)
... return df.shape
"""
IntoLazyFrame: TypeAlias = "NativeLazyFrame"
IntoFrame: TypeAlias = Union["IntoDataFrame", "IntoLazyFrame"]
"""Anything which can be converted to a Narwhals DataFrame or LazyFrame.
Use this if your function can accept an object which can be converted to either
`nw.DataFrame` or `nw.LazyFrame` and it doesn't care about its backend.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import IntoFrame
>>> def agnostic_columns(df_native: IntoFrame) -> list[str]:
... df = nw.from_native(df_native)
... return df.collect_schema().names()
"""
Frame: TypeAlias = Union["DataFrame[Any]", "LazyFrame[Any]"]
"""Narwhals DataFrame or Narwhals LazyFrame.
Use this if your function can work with either and your function doesn't care
about its backend.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import Frame
>>> @nw.narwhalify
... def agnostic_columns(df: Frame) -> list[str]:
... return df.columns
"""
IntoSeries: TypeAlias = "NativeSeries"
"""Anything which can be converted to a Narwhals Series.
Use this if your function can accept an object which can be converted to `nw.Series`
and it doesn't care about its backend.
Examples:
>>> from typing import Any
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeries
>>> def agnostic_to_list(s_native: IntoSeries) -> list[Any]:
... s = nw.from_native(s_native)
... return s.to_list()
"""
IntoFrameT = TypeVar("IntoFrameT", bound="IntoFrame")
"""TypeVar bound to object convertible to Narwhals DataFrame or Narwhals LazyFrame.
Use this if your function accepts an object which is convertible to `nw.DataFrame`
or `nw.LazyFrame` and returns an object of the same type.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import IntoFrameT
>>> def agnostic_func(df_native: IntoFrameT) -> IntoFrameT:
... df = nw.from_native(df_native)
... return df.with_columns(c=nw.col("a") + 1).to_native()
"""
IntoDataFrameT = TypeVar("IntoDataFrameT", bound="IntoDataFrame")
"""TypeVar bound to object convertible to Narwhals DataFrame.
Use this if your function accepts an object which can be converted to `nw.DataFrame`
and returns an object of the same class.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import IntoDataFrameT
>>> def agnostic_func(df_native: IntoDataFrameT) -> IntoDataFrameT:
... df = nw.from_native(df_native, eager_only=True)
... return df.with_columns(c=df["a"] + 1).to_native()
"""
IntoLazyFrameT = TypeVar("IntoLazyFrameT", bound="IntoLazyFrame")
FrameT = TypeVar("FrameT", "DataFrame[Any]", "LazyFrame[Any]")
"""TypeVar bound to Narwhals DataFrame or Narwhals LazyFrame.
Use this if your function accepts either `nw.DataFrame` or `nw.LazyFrame` and returns
an object of the same kind.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import FrameT
>>> @nw.narwhalify
... def agnostic_func(df: FrameT) -> FrameT:
... return df.with_columns(c=nw.col("a") + 1)
"""
DataFrameT = TypeVar("DataFrameT", bound="DataFrame[Any]")
"""TypeVar bound to Narwhals DataFrame.
Use this if your function can accept a Narwhals DataFrame and returns a Narwhals
DataFrame backed by the same backend.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import DataFrameT
>>> @nw.narwhalify
>>> def func(df: DataFrameT) -> DataFrameT:
... return df.with_columns(c=df["a"] + 1)
"""
IntoSeriesT = TypeVar("IntoSeriesT", bound="IntoSeries")
"""TypeVar bound to object convertible to Narwhals Series.
Use this if your function accepts an object which can be converted to `nw.Series`
and returns an object of the same class.
Examples:
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> def agnostic_abs(s_native: IntoSeriesT) -> IntoSeriesT:
... s = nw.from_native(s_native, series_only=True)
... return s.abs().to_native()
"""
__all__ = [
"DataFrameT",
"Frame",
"FrameT",
"IntoDataFrame",
"IntoDataFrameT",
"IntoExpr",
"IntoFrame",
"IntoFrameT",
"IntoSeries",
"IntoSeriesT",
]