Skip to content

narwhals.typing

Narwhals comes fully statically typed. In addition to nw.DataFrame, nw.Expr, nw.Series, nw.LazyFrame, we also provide the following type hints:

DataFrameT

A TypeVar bound to nw.DataFrame. Use this when you have a function which accepts a nw.DataFrame and returns a nw.DataFrame backed by the same backend, for example:

import narwhals as nw
from narwhals.typing import DataFrameT


@nw.narwhalify
def func(df: DataFrameT) -> DataFrameT:
    return df.with_columns(c=df["a"] + 1)

Frame

Either a nw.DataFrame or nw.LazyFrame. Use this if your function can work on either and your function doesn't care about its backend, for example:

import narwhals as nw
from narwhals.typing import Frame


@nw.narwhalify
def func(df: Frame) -> list[str]:
    return df.columns

FrameT

A TypeVar bound to Frame. Use this if your function accepts either nw.DataFrame or nw.LazyFrame and returns an object backed by the same backend, for example:

import narwhals as nw
from narwhals.typing import FrameT


@nw.narwhalify
def func(df: FrameT) -> FrameT:
    return df.with_columns(c=nw.col("a") + 1)

IntoDataFrame

An object which can be converted to nw.DataFrame (e.g. pd.DataFrame, pl.DataFrame). Use this if your function accepts a narwhalifiable object but doesn't care about its backend:

from __future__ import annotations

import narwhals as nw
from narwhals.typing import IntoDataFrame


def func(df_native: IntoDataFrame) -> tuple[int, int]:
    df = nw.from_native(df_native, eager_only=True)
    return df.shape

IntoDataFrameT

A TypeVar bound to IntoDataFrame. Use this if your function accepts a function which can be converted to nw.DataFrame and returns an object of the same class:

import narwhals as nw
from narwhals.typing import IntoDataFrameT


def func(df_native: IntoDataFrameT) -> IntoDataFrameT:
    df = nw.from_native(df_native, eager_only=True)
    return nw.to_native(df.with_columns(c=df["a"] + 1))

IntoExpr

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').

IntoFrame

An object which can be converted to nw.DataFrame or nw.LazyFrame (e.g. pd.DataFrame, pl.DataFrame, pl.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:

import narwhals as nw
from narwhals.typing import IntoFrame


def func(df_native: IntoFrame) -> list[str]:
    df = nw.from_native(df_native)
    return df.columns

IntoFrameT

A TypeVar bound to IntoFrame. 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:

import narwhals as nw
from narwhals.typing import IntoFrameT


def func(df_native: IntoFrameT) -> IntoFrameT:
    df = nw.from_native(df_native)
    return nw.to_native(df.with_columns(c=nw.col("a") + 1))

nw.narwhalify, or nw.from_native?

Although the former is more readable, the latter is better at preserving type hints.

Here's an example:

import polars as pl
import narwhals as nw
from narwhals.typing import IntoDataFrameT, DataFrameT

df = pl.DataFrame({"a": [1, 2, 3]})


def func(df: IntoDataFrameT) -> IntoDataFrameT:
    df = nw.from_native(df, eager_only=True)
    return nw.to_native(df.select(b=nw.col("a")))


reveal_type(func(df))


@nw.narwhalify(strict=True)
def func_2(df: DataFrameT) -> DataFrameT:
    return df.select(b=nw.col("a"))


reveal_type(func_2(df))

Running mypy on it gives:

$ mypy f.py 
f.py:11: note: Revealed type is "polars.dataframe.frame.DataFrame"
f.py:17: note: Revealed type is "Any"
Success: no issues found in 1 source file

In the first case, mypy can infer that df is a polars.DataFrame. In the second case, it can't.

If you want to make the most out of type hints and preserve them as much as possible, we recommend nw.from_native and nw.to_native - otherwise, nw.narwhalify. Type hints will still be respected inside the function body if you type the arguments.