U
     )3gžÜ ã                   @  sn  d dl mZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlm	Z	 d d	lm
Z
 d d
lmZ d dlmZ er¬d dlmZ d dlmZ d dlmZ ddddœdd„ZG dd„ dƒZe
dedZG dd„ dee ƒZG dd„ dee ƒZG dd„ dee ƒZG dd„ dee ƒZddd œd!d"„Zd#dd$œd%d&„Zdd'œd(d)„Zdd'œd*d+„Zd,dd-œd.d/„Z d,dd-œd0d1„Z!d,dd-œd2d3„Z"d,dd-œd4d5„Z#d6dd7œd8d9„Z$d6dd7œd:d;„Z%d6dd7œd<d=„Z&G d>d?„ d?ƒZ'G d@dA„ dAeƒZ(d6d?dBœdCdD„Z)d6dd7œdEdF„Z*dXddHddIœdJdK„Z+d6dd7œdLdM„Z,d6dd7œdNdO„Z-dPdQdRœd6dSd,dTddUœdVdW„Z.dgZ/dGS )Yé    )Úannotations)ÚTYPE_CHECKING)ÚAny)ÚCallable)ÚGeneric)ÚIterable)ÚLiteral)ÚSequence)ÚTypeVar)Úis_numpy_array)Úflatten)ÚSelf)ÚDType)ÚIntoExprÚExprr   )ÚexprÚotherÚreturnc                 C  s4   ddl m} t|tƒr | | ¡S t||ƒr0|jS |S )Nr   )ÚSeries)Znarwhals.seriesr   Ú
isinstancer   Ú_callZ_compliant_series)r   r   r   © r   ú1/tmp/pip-unpacked-wheel-hfsjijke/narwhals/expr.pyÚextract_compliant   s    


r   c                	   @  s¼  e Zd Zdddœdd„Zddœdd	„Zd
ddœdd„Zdddddœdd„Zddddœdd„Zdddœdd„Zdddœdd„Z	dddœdd„Z
dddœdd „Zdddœd!d"„Zdddœd#d$„Zdddœd%d&„Zdddœd'd(„Zdddœd)d*„Zdddœd+d,„Zdddœd-d.„Zdddœd/d0„Zdddœd1d2„Zdddœd3d4„Zdddœd5d6„Zdddœd7d8„Zdddœd9d:„Zdddœd;d<„Zdddœd=d>„Zdddœd?d@„ZdddœdAdB„ZdddœdCdD„ZdddœdEdF„ZdddœdGdH„ZddœdIdJ„Z ddœdKdL„Z!ddœdMdN„Z"ddœdOdP„Z#dQdRœdSddTœdUdV„Z$d dœdWdX„Z%ddœdYdZ„Z&ddœd[d\„Z'ddœd]d^„Z(ddœd_d`„Z)dadbœdcdddœdedf„Z*ddœdgdh„Z+ddœdidj„Z,ddœdkdl„Z-dSddmœdndo„Z.dpdpdddqœdrds„Z/dadadtœdcdcdduœdvdw„Z0dÅddd
ddyœdzd{„Z1dddœd|d}„Z2ddd~œdd€„Z3ddœdd‚„Z4ddœdƒd„„Z5ddd…œd†d‡„Z6ddœdˆd‰„Z7dÆdŠdadŠd‹œddŒddcdŒddŽœdd„Z8d‘dd’œd“d”„Z9ddœd•d–„Z:ddœd—d˜„Z;ddœd™dš„Z<ddœd›dœ„Z=ddœddž„Z>dŸd dd¡œd¢d£„Z?dÇdSddmœd¥d¦„Z@dÈdSddmœd§d¨„ZAdÉdSddªœd«d¬„ZBddœd­d®„ZCdÊddSdSdd¯œd°d±„ZDdËd²d²dd³œd´dµ„ZEddd¶œd·d¸„ZFeGdd¹d¶œdºd»„ƒZHeGdd¼d¶œd½d¾„ƒZIeGdd¿d¶œdÀdÁ„ƒZJeGddÂd¶œdÃdÄ„ƒZKdŠS )Ìr   úCallable[[Any], Any]ÚNone©Úcallr   c                 C  s
   || _ d S ©N©r   ©Úselfr   r   r   r   Ú__init__!   s    zExpr.__init__r   ©r   c                   s   ˆ   ‡ fdd„¡S )Nc                   s   ˆ   | ¡ ¡  ¡ S r   )r   ÚabsÚsum©Úplx©r!   r   r   Ú<lambda>(   ó    z$Expr._taxicab_norm.<locals>.<lambda>©Ú	__class__r(   r   r(   r   Ú_taxicab_norm%   s    zExpr._taxicab_normÚstr)Únamer   c                   s   ˆ  ‡ ‡fdd„¡S )u¶  
        Rename the expression.

        Arguments:
            name: The new name.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 2], "b": [4, 5]})
            >>> df_pl = pl.DataFrame({"a": [1, 2], "b": [4, 5]})
            >>> df_pa = pa.table({"a": [1, 2], "b": [4, 5]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select((nw.col("b") + 10).alias("c"))

            We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                c
            0  14
            1  15
            >>> func(df_pl)
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ c   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 14  â”‚
            â”‚ 15  â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            c: int64
            ----
            c: [[14,15]]

        c                   s   ˆ  | ¡ ˆ ¡S r   )r   Úaliasr&   ©r/   r!   r   r   r)   X   r*   zExpr.alias.<locals>.<lambda>r+   )r!   r/   r   r1   r   r0   +   s    -z
Expr.aliaszCallable[[Any], Self]r   )ÚfunctionÚargsÚkwargsr   c                 O  s   || f|ž|ŽS )u¹  
        Pipe function call.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> data = {"a": [1, 2, 3, 4]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Lets define a library-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").pipe(lambda x: x + 1))

            We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a
            0  2
            1  3
            2  4
            3  5
            >>> func(df_pl)
            shape: (4, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 2   â”‚
            â”‚ 3   â”‚
            â”‚ 4   â”‚
            â”‚ 5   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[2,3,4,5]]
        r   )r!   r2   r3   r4   r   r   r   ÚpipeZ   s    .z	Expr.pipezDType | type[DType])r!   Údtyper   c                   s   ˆ  ‡ ‡fdd„¡S )uh  
        Redefine an object's data type.

        Arguments:
            dtype: Data type that the object will be cast into.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> from datetime import date
            >>> df_pd = pd.DataFrame({"foo": [1, 2, 3], "bar": [6.0, 7.0, 8.0]})
            >>> df_pl = pl.DataFrame({"foo": [1, 2, 3], "bar": [6.0, 7.0, 8.0]})
            >>> df_pa = pa.table({"foo": [1, 2, 3], "bar": [6.0, 7.0, 8.0]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(
            ...         nw.col("foo").cast(nw.Float32), nw.col("bar").cast(nw.UInt8)
            ...     )

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               foo  bar
            0  1.0    6
            1  2.0    7
            2  3.0    8
            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ foo â”† bar â”‚
            â”‚ --- â”† --- â”‚
            â”‚ f32 â”† u8  â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 1.0 â”† 6   â”‚
            â”‚ 2.0 â”† 7   â”‚
            â”‚ 3.0 â”† 8   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            foo: float
            bar: uint8
            ----
            foo: [[1,2,3]]
            bar: [[6,7,8]]
        c                   s   ˆ  | ¡ ˆ ¡S r   )r   Úcastr&   ©r6   r!   r   r   r)   ¾   r*   zExpr.cast.<locals>.<lambda>r+   )r!   r6   r   r8   r   r7   Š   s    3ÿz	Expr.castÚobject)r   r   c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__eq__r   r&   ©r   r!   r   r   r)   Ä   r*   zExpr.__eq__.<locals>.<lambda>r+   ©r!   r   r   r;   r   r:   Â   s    ÿzExpr.__eq__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__ne__r   r&   r;   r   r   r)   É   r*   zExpr.__ne__.<locals>.<lambda>r+   r<   r   r;   r   r=   Ç   s    ÿzExpr.__ne__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__and__r   r&   r;   r   r   r)   Î   r*   zExpr.__and__.<locals>.<lambda>r+   r<   r   r;   r   r>   Ì   s    ÿzExpr.__and__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__rand__r   r&   r;   r   r   r)   Ó   r*   zExpr.__rand__.<locals>.<lambda>r+   r<   r   r;   r   r?   Ñ   s    ÿzExpr.__rand__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__or__r   r&   r;   r   r   r)   Ø   r*   zExpr.__or__.<locals>.<lambda>r+   r<   r   r;   r   r@   Ö   s    ÿzExpr.__or__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__ror__r   r&   r;   r   r   r)   Ý   r*   zExpr.__ror__.<locals>.<lambda>r+   r<   r   r;   r   rA   Û   s    ÿzExpr.__ror__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__add__r   r&   r;   r   r   r)   â   r*   zExpr.__add__.<locals>.<lambda>r+   r<   r   r;   r   rB   à   s    ÿzExpr.__add__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__radd__r   r&   r;   r   r   r)   ç   r*   zExpr.__radd__.<locals>.<lambda>r+   r<   r   r;   r   rC   å   s    ÿzExpr.__radd__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__sub__r   r&   r;   r   r   r)   ì   r*   zExpr.__sub__.<locals>.<lambda>r+   r<   r   r;   r   rD   ê   s    ÿzExpr.__sub__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__rsub__r   r&   r;   r   r   r)   ñ   r*   zExpr.__rsub__.<locals>.<lambda>r+   r<   r   r;   r   rE   ï   s    ÿzExpr.__rsub__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__truediv__r   r&   r;   r   r   r)   ö   r*   z"Expr.__truediv__.<locals>.<lambda>r+   r<   r   r;   r   rF   ô   s    ÿzExpr.__truediv__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__rtruediv__r   r&   r;   r   r   r)   û   r*   z#Expr.__rtruediv__.<locals>.<lambda>r+   r<   r   r;   r   rG   ù   s    ÿzExpr.__rtruediv__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__mul__r   r&   r;   r   r   r)      r*   zExpr.__mul__.<locals>.<lambda>r+   r<   r   r;   r   rH   þ   s    ÿzExpr.__mul__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__rmul__r   r&   r;   r   r   r)     r*   zExpr.__rmul__.<locals>.<lambda>r+   r<   r   r;   r   rI     s    ÿzExpr.__rmul__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__le__r   r&   r;   r   r   r)   
  r*   zExpr.__le__.<locals>.<lambda>r+   r<   r   r;   r   rJ     s    ÿzExpr.__le__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__lt__r   r&   r;   r   r   r)     r*   zExpr.__lt__.<locals>.<lambda>r+   r<   r   r;   r   rK     s    ÿzExpr.__lt__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__gt__r   r&   r;   r   r   r)     r*   zExpr.__gt__.<locals>.<lambda>r+   r<   r   r;   r   rL     s    ÿzExpr.__gt__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__ge__r   r&   r;   r   r   r)     r*   zExpr.__ge__.<locals>.<lambda>r+   r<   r   r;   r   rM     s    ÿzExpr.__ge__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__pow__r   r&   r;   r   r   r)     r*   zExpr.__pow__.<locals>.<lambda>r+   r<   r   r;   r   rN     s    ÿzExpr.__pow__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__rpow__r   r&   r;   r   r   r)   #  r*   zExpr.__rpow__.<locals>.<lambda>r+   r<   r   r;   r   rO   !  s    ÿzExpr.__rpow__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__floordiv__r   r&   r;   r   r   r)   (  r*   z#Expr.__floordiv__.<locals>.<lambda>r+   r<   r   r;   r   rP   &  s    ÿzExpr.__floordiv__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__rfloordiv__r   r&   r;   r   r   r)   -  r*   z$Expr.__rfloordiv__.<locals>.<lambda>r+   r<   r   r;   r   rQ   +  s    ÿzExpr.__rfloordiv__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__mod__r   r&   r;   r   r   r)   2  r*   zExpr.__mod__.<locals>.<lambda>r+   r<   r   r;   r   rR   0  s    ÿzExpr.__mod__c                   s   ˆ  ‡ ‡fdd„¡S )Nc                   s   ˆ  | ¡ t| ˆ ƒ¡S r   )r   Ú__rmod__r   r&   r;   r   r   r)   7  r*   zExpr.__rmod__.<locals>.<lambda>r+   r<   r   r;   r   rS   5  s    ÿzExpr.__rmod__c                   s   ˆ   ‡ fdd„¡S )Nc                   s   ˆ   | ¡ ¡ S r   )r   Ú
__invert__r&   r(   r   r   r)   <  r*   z!Expr.__invert__.<locals>.<lambda>r+   r(   r   r(   r   rT   ;  s    zExpr.__invert__c                   s   ˆ   ‡ fdd„¡S )uF  
        Return whether any of the values in the column are `True`

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [True, False], "b": [True, True]})
            >>> df_pl = pl.DataFrame({"a": [True, False], "b": [True, True]})
            >>> df_pa = pa.table({"a": [True, False], "b": [True, True]})

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").any())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                  a     b
            0  True  True
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”
            â”‚ a    â”† b    â”‚
            â”‚ ---  â”† ---  â”‚
            â”‚ bool â”† bool â”‚
            â•žâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•¡
            â”‚ true â”† true â”‚
            â””â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: bool
            b: bool
            ----
            a: [[true]]
            b: [[true]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úanyr&   r(   r   r   r)   g  r*   zExpr.any.<locals>.<lambda>r+   r(   r   r(   r   rU   >  s    )zExpr.anyc                   s   ˆ   ‡ fdd„¡S )uS  
        Return whether all values in the column are `True`.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [True, False], "b": [True, True]})
            >>> df_pl = pl.DataFrame({"a": [True, False], "b": [True, True]})
            >>> df_pa = pa.table({"a": [True, False], "b": [True, True]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").all())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                   a     b
            0  False  True
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”
            â”‚ a     â”† b    â”‚
            â”‚ ---   â”† ---  â”‚
            â”‚ bool  â”† bool â”‚
            â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•¡
            â”‚ false â”† true â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: bool
            b: bool
            ----
            a: [[false]]
            b: [[true]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úallr&   r(   r   r   r)   ’  r*   zExpr.all.<locals>.<lambda>r+   r(   r   r(   r   rV   i  s    )zExpr.allc                   s   ˆ   ‡ fdd„¡S )uî  
        Get mean value.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [-1, 0, 1], "b": [2, 4, 6]})
            >>> df_pl = pl.DataFrame({"a": [-1, 0, 1], "b": [2, 4, 6]})
            >>> df_pa = pa.table({"a": [-1, 0, 1], "b": [2, 4, 6]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").mean())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                 a    b
            0  0.0  4.0
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ f64 â”† f64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 0.0 â”† 4.0 â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: double
            b: double
            ----
            a: [[0]]
            b: [[4]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úmeanr&   r(   r   r   r)   ½  r*   zExpr.mean.<locals>.<lambda>r+   r(   r   r(   r   rW   ”  s    )z	Expr.meané   ©ÚddofÚint)rZ   r   c                  s   ˆ  ‡ ‡fdd„¡S )u–  
        Get standard deviation.

        Arguments:
            ddof: â€œDelta Degrees of Freedomâ€: the divisor used in the calculation is N - ddof,
                     where N represents the number of elements. By default ddof is 1.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [20, 25, 60], "b": [1.5, 1, -1.4]})
            >>> df_pl = pl.DataFrame({"a": [20, 25, 60], "b": [1.5, 1, -1.4]})
            >>> df_pa = pa.table({"a": [20, 25, 60], "b": [1.5, 1, -1.4]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").std(ddof=0))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                      a         b
            0  17.79513  1.265789
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a        â”† b        â”‚
            â”‚ ---      â”† ---      â”‚
            â”‚ f64      â”† f64      â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 17.79513 â”† 1.265789 â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: double
            b: double
            ----
            a: [[17.795130420052185]]
            b: [[1.2657891697365016]]

        c                   s   ˆ  | ¡jˆ dS )NrY   )r   Ústdr&   ©rZ   r!   r   r   r)   í  r*   zExpr.std.<locals>.<lambda>r+   )r!   rZ   r   r]   r   r\   ¿  s    .zExpr.stdc                   s   ˆ   ‡ fdd„¡S )ué  
        Return the sum value.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [5, 10], "b": [50, 100]})
            >>> df_pl = pl.DataFrame({"a": [5, 10], "b": [50, 100]})
            >>> df_pa = pa.table({"a": [5, 10], "b": [50, 100]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").sum())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                a    b
            0  15  150
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† i64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 15  â”† 150 â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[15]]
            b: [[150]]
        c                   s   ˆ   | ¡ ¡ S r   )r   r%   r&   r(   r   r   r)     r*   zExpr.sum.<locals>.<lambda>r+   r(   r   r(   r   r%   ï  s    )zExpr.sumc                   s   ˆ   ‡ fdd„¡S )uç  
        Returns the minimum value(s) from a column(s).

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 2], "b": [4, 3]})
            >>> df_pl = pl.DataFrame({"a": [1, 2], "b": [4, 3]})
            >>> df_pa = pa.table({"a": [1, 2], "b": [4, 3]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.min("a", "b"))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a  b
            0  1  3
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† i64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 1   â”† 3   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[1]]
            b: [[3]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úminr&   r(   r   r   r)   C  r*   zExpr.min.<locals>.<lambda>r+   r(   r   r(   r   r^     s    )zExpr.minc                   s   ˆ   ‡ fdd„¡S )uÿ  
        Returns the maximum value(s) from a column(s).

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [10, 20], "b": [50, 100]})
            >>> df_pl = pl.DataFrame({"a": [10, 20], "b": [50, 100]})
            >>> df_pa = pa.table({"a": [10, 20], "b": [50, 100]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.max("a", "b"))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                a    b
            0  20  100
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† i64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 20  â”† 100 â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[20]]
            b: [[100]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úmaxr&   r(   r   r   r)   n  r*   zExpr.max.<locals>.<lambda>r+   r(   r   r(   r   r_   E  s    )zExpr.maxc                   s   ˆ   ‡ fdd„¡S )u
  
        Returns the number of non-null elements in the column.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 2, 3], "b": [None, 4, 4]})
            >>> df_pl = pl.DataFrame({"a": [1, 2, 3], "b": [None, 4, 4]})
            >>> df_pa = pa.table({"a": [1, 2, 3], "b": [None, 4, 4]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.all().count())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a  b
            0  3  2
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ u32 â”† u32 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 3   â”† 2   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[3]]
            b: [[2]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úcountr&   r(   r   r   r)   ™  r*   zExpr.count.<locals>.<lambda>r+   r(   r   r(   r   r`   p  s    )z
Expr.countc                   s   ˆ   ‡ fdd„¡S )u  
         Returns count of unique values

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 2, 3, 4, 5], "b": [1, 1, 3, 3, 5]})
            >>> df_pl = pl.DataFrame({"a": [1, 2, 3, 4, 5], "b": [1, 1, 3, 3, 5]})
            >>> df_pa = pa.table({"a": [1, 2, 3, 4, 5], "b": [1, 1, 3, 3, 5]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").n_unique())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a  b
            0  5  3
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ u32 â”† u32 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 5   â”† 3   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[5]]
            b: [[3]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Ún_uniquer&   r(   r   r   r)   Ä  r*   zExpr.n_unique.<locals>.<lambda>r+   r(   r   r(   r   ra   ›  s    )zExpr.n_uniqueF©Úmaintain_orderÚbool)rc   r   c                  s   ˆ  ‡ ‡fdd„¡S )u¤  
        Return unique values of this expression.

        Arguments:
            maintain_order: Keep the same order as the original expression. This may be more
                expensive to compute. Settings this to `True` blocks the possibility
                to run on the streaming engine for Polars.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 1, 3, 5, 5], "b": [2, 4, 4, 6, 6]})
            >>> df_pl = pl.DataFrame({"a": [1, 1, 3, 5, 5], "b": [2, 4, 4, 6, 6]})
            >>> df_pa = pa.table({"a": [1, 1, 3, 5, 5], "b": [2, 4, 4, 6, 6]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").unique(maintain_order=True))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a  b
            0  1  2
            1  3  4
            2  5  6
            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† i64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 1   â”† 2   â”‚
            â”‚ 3   â”† 4   â”‚
            â”‚ 5   â”† 6   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[1,3,5]]
            b: [[2,4,6]]
        c                   s   ˆ  | ¡jˆ dS )Nrb   )r   Úuniquer&   ©rc   r!   r   r   r)   ù  r*   zExpr.unique.<locals>.<lambda>r+   )r!   rc   r   rf   r   re   Æ  s    2ÿzExpr.uniquec                   s   ˆ   ‡ fdd„¡S )u  
        Return absolute value of each element.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> data = {"a": [1, -2], "b": [-3, 4]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").abs())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a  b
            0  1  3
            1  2  4
            >>> func(df_pl)
            shape: (2, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† i64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 1   â”† 3   â”‚
            â”‚ 2   â”† 4   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[1,2]]
            b: [[3,4]]
        c                   s   ˆ   | ¡ ¡ S r   )r   r$   r&   r(   r   r   r)   (  r*   zExpr.abs.<locals>.<lambda>r+   r(   r   r(   r   r$   ü  s    ,zExpr.absc                   s   ˆ   ‡ fdd„¡S )u   
        Return cumulative sum.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 1, 3, 5, 5], "b": [2, 4, 4, 6, 6]})
            >>> df_pl = pl.DataFrame({"a": [1, 1, 3, 5, 5], "b": [2, 4, 4, 6, 6]})
            >>> df_pa = pa.table({"a": [1, 1, 3, 5, 5], "b": [2, 4, 4, 6, 6]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").cum_sum())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                a   b
            0   1   2
            1   2   6
            2   5  10
            3  10  16
            4  15  22
            >>> func(df_pl)
            shape: (5, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† i64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 1   â”† 2   â”‚
            â”‚ 2   â”† 6   â”‚
            â”‚ 5   â”† 10  â”‚
            â”‚ 10  â”† 16  â”‚
            â”‚ 15  â”† 22  â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[1,2,5,10,15]]
            b: [[2,6,10,16,22]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úcum_sumr&   r(   r   r   r)   [  r*   zExpr.cum_sum.<locals>.<lambda>r+   r(   r   r(   r   rg   *  s    1zExpr.cum_sumc                   s   ˆ   ‡ fdd„¡S )u&  
        Returns the difference between each element and the previous one.

        Notes:
            pandas may change the dtype here, for example when introducing missing
            values in an integer column. To ensure, that the dtype doesn't change,
            you may want to use `fill_null` and `cast`. For example, to calculate
            the diff and fill missing values with `0` in a Int64 column, you could
            do:

                nw.col("a").diff().fill_null(0).cast(nw.Int64)

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 1, 3, 5, 5]})
            >>> df_pl = pl.DataFrame({"a": [1, 1, 3, 5, 5]})
            >>> df_pa = pa.table({"a": [1, 1, 3, 5, 5]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(a_diff=nw.col("a").diff())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a_diff
            0     NaN
            1     0.0
            2     2.0
            3     2.0
            4     0.0
            >>> func(df_pl)
            shape: (5, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a_diff â”‚
            â”‚ ---    â”‚
            â”‚ i64    â”‚
            â•žâ•â•â•â•â•â•â•â•â•¡
            â”‚ null   â”‚
            â”‚ 0      â”‚
            â”‚ 2      â”‚
            â”‚ 2      â”‚
            â”‚ 0      â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a_diff: int64
            ----
            a_diff: [[null,0,2,2,0]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Údiffr&   r(   r   r   r)   •  r*   zExpr.diff.<locals>.<lambda>r+   r(   r   r(   r   rh   ]  s    8z	Expr.diff)Únr   c                   s   ˆ  ‡ ‡fdd„¡S )u  
        Shift values by `n` positions.

        Notes:
            pandas may change the dtype here, for example when introducing missing
            values in an integer column. To ensure, that the dtype doesn't change,
            you may want to use `fill_null` and `cast`. For example, to shift
            and fill missing values with `0` in a Int64 column, you could
            do:

                nw.col("a").shift(1).fill_null(0).cast(nw.Int64)

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 1, 3, 5, 5]})
            >>> df_pl = pl.DataFrame({"a": [1, 1, 3, 5, 5]})
            >>> df_pa = pa.table({"a": [1, 1, 3, 5, 5]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(a_shift=nw.col("a").shift(n=1))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a_shift
            0      NaN
            1      1.0
            2      1.0
            3      3.0
            4      5.0
            >>> func(df_pl)
            shape: (5, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a_shift â”‚
            â”‚ ---     â”‚
            â”‚ i64     â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•¡
            â”‚ null    â”‚
            â”‚ 1       â”‚
            â”‚ 1       â”‚
            â”‚ 3       â”‚
            â”‚ 5       â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a_shift: int64
            ----
            a_shift: [[null,1,1,3,5]]
        c                   s   ˆ  | ¡ ˆ ¡S r   )r   Úshiftr&   ©ri   r!   r   r   r)   Ï  r*   zExpr.shift.<locals>.<lambda>r+   ©r!   ri   r   rk   r   rj   —  s    8z
Expr.shiftzSequence[Any])ÚoldÚnewÚreturn_dtyper   c                  s   ˆ  ‡ ‡‡‡fdd„¡S )u¹  
        Replace old values with new values.

        This function must replace all non-null input values (else it raises an error),
        and the return dtype must be specified.

        Arguments:
            old: Sequence of old values to replace.
            new: Sequence of new values to replace.
            return_dtype: Return dtype.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> df_pd = pd.DataFrame({"a": [3, 0, 1, 2]})
            >>> df_pl = pl.DataFrame({"a": [3, 0, 1, 2]})
            >>> df_pa = pa.table({"a": [3, 0, 1, 2]})

            Let's define dataframe-agnostic functions:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         b=nw.col("a").replace_strict(
            ...             [0,1,2,3], ['zero', 'one', 'two', 'three']
            ...             return_dtype=nw.String,
            ...         )
            ...     )

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a      b
            0  3  three
            1  0   zero
            2  1    one
            3  2    two
            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b     â”‚
            â”‚ --- â”† ---   â”‚
            â”‚ i64 â”† str   â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
            â”‚ 3   â”† three â”‚
            â”‚ 0   â”† zero  â”‚
            â”‚ 1   â”† one   â”‚
            â”‚ 2   â”† two   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: string
            ----
            a: [[3,0,1,2]]
            b: [["three","zero","one","two"]]
        c                   s   ˆ  | ¡jˆˆ ˆdS )N)ro   )r   Úreplace_strictr&   ©rn   rm   ro   r!   r   r   r)     s   
  ÿz%Expr.replace_strict.<locals>.<lambda>r+   )r!   rm   rn   ro   r   rq   r   rp   Ñ  s    >ÿzExpr.replace_strict©Ú
descendingÚ
nulls_last)rs   rt   r   c                  s   ˆ  ‡ ‡‡fdd„¡S )už  
        Sort this column. Place null values first.

        Arguments:
            descending: Sort in descending order.
            nulls_last: Place null values last instead of first.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> df_pd = pd.DataFrame({"a": [5, None, 1, 2]})
            >>> df_pl = pl.DataFrame({"a": [5, None, 1, 2]})
            >>> df_pa = pa.table({"a": [5, None, 1, 2]})

            Let's define dataframe-agnostic functions:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").sort())

            >>> def func_descend(df):
            ...     df = nw.from_native(df)
            ...     df = df.select(nw.col("a").sort(descending=True))
            ...     return nw.to_native(df)

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                 a
            1  NaN
            2  1.0
            3  2.0
            0  5.0
            >>> func(df_pl)
            shape: (4, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”
            â”‚ a    â”‚
            â”‚ ---  â”‚
            â”‚ i64  â”‚
            â•žâ•â•â•â•â•â•â•¡
            â”‚ null â”‚
            â”‚ 1    â”‚
            â”‚ 2    â”‚
            â”‚ 5    â”‚
            â””â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[null,1,2,5]]

            >>> func_descend(df_pd)
                 a
            1  NaN
            0  5.0
            3  2.0
            2  1.0
            >>> func_descend(df_pl)
            shape: (4, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”
            â”‚ a    â”‚
            â”‚ ---  â”‚
            â”‚ i64  â”‚
            â•žâ•â•â•â•â•â•â•¡
            â”‚ null â”‚
            â”‚ 5    â”‚
            â”‚ 2    â”‚
            â”‚ 1    â”‚
            â””â”€â”€â”€â”€â”€â”€â”˜
            >>> func_descend(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[null,5,2,1]]
        c                   s   ˆ  | ¡jˆ ˆdS )Nrr   )r   Úsortr&   ©rs   rt   r!   r   r   r)   d  r*   zExpr.sort.<locals>.<lambda>r+   )r!   rs   rt   r   rv   r   ru     s    Nÿz	Expr.sortÚboth)Úlower_boundÚupper_boundÚclosedr   c                   s   ˆ  ‡ ‡‡‡fdd„¡S )u5  
        Check if this expression is between the given lower and upper bounds.

        Arguments:
            lower_bound: Lower bound value.

            upper_bound: Upper bound value.

            closed: Define which sides of the interval are closed (inclusive).

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 2, 3, 4, 5]})
            >>> df_pl = pl.DataFrame({"a": [1, 2, 3, 4, 5]})
            >>> df_pa = pa.table({"a": [1, 2, 3, 4, 5]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").is_between(2, 4, "right"))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                   a
            0  False
            1  False
            2   True
            3   True
            4  False
            >>> func(df_pl)
            shape: (5, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a     â”‚
            â”‚ ---   â”‚
            â”‚ bool  â”‚
            â•žâ•â•â•â•â•â•â•â•¡
            â”‚ false â”‚
            â”‚ false â”‚
            â”‚ true  â”‚
            â”‚ true  â”‚
            â”‚ false â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: bool
            ----
            a: [[false,false,true,true,false]]
        c                   s   ˆ  | ¡ ˆˆˆ ¡S r   )r   Ú
is_betweenr&   ©rz   rx   r!   ry   r   r   r)   ¡  r*   z!Expr.is_between.<locals>.<lambda>r+   )r!   rx   ry   rz   r   r|   r   r{   h  s    8ÿzExpr.is_betweenc                   s<   t ˆ tƒr,t ˆ ttfƒs,ˆ ‡ ‡fdd„¡S d}t|ƒ‚dS )u  
        Check if elements of this expression are present in the other iterable.

        Arguments:
            other: iterable

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [1, 2, 9, 10]})
            >>> df_pl = pl.DataFrame({"a": [1, 2, 9, 10]})
            >>> df_pa = pa.table({"a": [1, 2, 9, 10]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(b=nw.col("a").is_in([1, 2]))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                a      b
            0   1   True
            1   2   True
            2   9  False
            3  10  False

            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b     â”‚
            â”‚ --- â”† ---   â”‚
            â”‚ i64 â”† bool  â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
            â”‚ 1   â”† true  â”‚
            â”‚ 2   â”† true  â”‚
            â”‚ 9   â”† false â”‚
            â”‚ 10  â”† false â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: bool
            ----
            a: [[1,2,9,10]]
            b: [[true,true,false,false]]
        c                   s   ˆ  | ¡ ˆ ¡S r   )r   Úis_inr&   r;   r   r   r)   Ø  r*   zExpr.is_in.<locals>.<lambda>zyNarwhals `is_in` doesn't accept expressions as an argument, as opposed to Polars. You should provide an iterable instead.N)r   r   r.   Úbytesr,   ÚNotImplementedError)r!   r   Úmsgr   r;   r   r}   ¤  s    3z
Expr.is_in©Ú
predicatesr   c                   s   ˆ  ‡ ‡fdd„¡S )uL  
        Filters elements based on a condition, returning a new expression.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame({"a": [2, 3, 4, 5, 6, 7], "b": [10, 11, 12, 13, 14, 15]})
            >>> df_pl = pl.DataFrame({"a": [2, 3, 4, 5, 6, 7], "b": [10, 11, 12, 13, 14, 15]})
            >>> df_pa = pa.table({"a": [2, 3, 4, 5, 6, 7], "b": [10, 11, 12, 13, 14, 15]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(
            ...         nw.col("a").filter(nw.col("a") > 4),
            ...         nw.col("b").filter(nw.col("b") < 13),
            ...     )

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a   b
            3  5  10
            4  6  11
            5  7  12
            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† i64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 5   â”† 10  â”‚
            â”‚ 6   â”† 11  â”‚
            â”‚ 7   â”† 12  â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[5,6,7]]
            b: [[10,11,12]]
        c                   s"   ˆ  ˆ ¡j‡ fdd„tˆƒD ƒŽ S )Nc                   s   g | ]}t ˆ |ƒ‘qS r   ©r   )Ú.0Úpredr&   r   r   Ú
<listcomp>  s     z1Expr.filter.<locals>.<lambda>.<locals>.<listcomp>)r   Úfilterr   r&   ©r‚   r!   r&   r   r)     s   
ÿzExpr.filter.<locals>.<lambda>r+   ©r!   r‚   r   rˆ   r   r‡   Ý  s    0ÿzExpr.filterc                   s   ˆ   ‡ fdd„¡S )u	  
        Returns a boolean Series indicating which values are null.

        Notes:
            pandas and Polars handle null values differently. Polars distinguishes
            between NaN and Null, whereas pandas doesn't.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame(
            ...     {"a": [2, 4, None, 3, 5], "b": [2.0, 4.0, float("nan"), 3.0, 5.0]}
            ... )
            >>> df_pl = pl.DataFrame(
            ...     {"a": [2, 4, None, 3, 5], "b": [2.0, 4.0, float("nan"), 3.0, 5.0]}
            ... )
            >>> df_pa = pa.table(
            ...     {"a": [2, 4, None, 3, 5], "b": [2.0, 4.0, float("nan"), 3.0, 5.0]}
            ... )

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         a_is_null=nw.col("a").is_null(), b_is_null=nw.col("b").is_null()
            ...     )

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                 a    b  a_is_null  b_is_null
            0  2.0  2.0      False      False
            1  4.0  4.0      False      False
            2  NaN  NaN       True       True
            3  3.0  3.0      False      False
            4  5.0  5.0      False      False

            >>> func(df_pl)  # nan != null for polars
            shape: (5, 4)
            â”Œâ”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a    â”† b   â”† a_is_null â”† b_is_null â”‚
            â”‚ ---  â”† --- â”† ---       â”† ---       â”‚
            â”‚ i64  â”† f64 â”† bool      â”† bool      â”‚
            â•žâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2    â”† 2.0 â”† false     â”† false     â”‚
            â”‚ 4    â”† 4.0 â”† false     â”† false     â”‚
            â”‚ null â”† NaN â”† true      â”† false     â”‚
            â”‚ 3    â”† 3.0 â”† false     â”† false     â”‚
            â”‚ 5    â”† 5.0 â”† false     â”† false     â”‚
            â””â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜

            >>> func(df_pa)  # nan != null for pyarrow
            pyarrow.Table
            a: int64
            b: double
            a_is_null: bool
            b_is_null: bool
            ----
            a: [[2,4,null,3,5]]
            b: [[2,4,nan,3,5]]
            a_is_null: [[false,false,true,false,false]]
            b_is_null: [[false,false,false,false,false]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úis_nullr&   r(   r   r   r)   V  r*   zExpr.is_null.<locals>.<lambda>r+   r(   r   r(   r   rŠ     s    CzExpr.is_nullc                   s   ˆ   ‡ fdd„¡S )u‡  
        Find elements where boolean expression is True.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> data = {"a": [1, None, None, 2]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").is_null().arg_true())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a
            1  1
            2  2
            >>> func(df_pl)
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ u32 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 1   â”‚
            â”‚ 2   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[1,2]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úarg_truer&   r(   r   r   r)   ‚  r*   zExpr.arg_true.<locals>.<lambda>r+   r(   r   r(   r   r‹   X  s    *zExpr.arg_true©Úvaluer   c                   s   ˆ   ‡ ‡fdd„¡S )u§  
        Fill null values with given value.

        Notes:
            pandas and Polars handle null values differently. Polars distinguishes
            between NaN and Null, whereas pandas doesn't.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> df_pd = pd.DataFrame(
            ...     {"a": [2, 4, None, 3, 5], "b": [2.0, 4.0, float("nan"), 3.0, 5.0]}
            ... )
            >>> df_pl = pl.DataFrame(
            ...     {"a": [2, 4, None, 3, 5], "b": [2.0, 4.0, float("nan"), 3.0, 5.0]}
            ... )
            >>> df_pa = pa.table(
            ...     {"a": [2, 4, None, 3, 5], "b": [2.0, 4.0, float("nan"), 3.0, 5.0]}
            ... )

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(nw.col("a", "b").fill_null(0))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                 a    b
            0  2.0  2.0
            1  4.0  4.0
            2  0.0  0.0
            3  3.0  3.0
            4  5.0  5.0

            >>> func(df_pl)  # nan != null for polars
            shape: (5, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ i64 â”† f64 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 2   â”† 2.0 â”‚
            â”‚ 4   â”† 4.0 â”‚
            â”‚ 0   â”† NaN â”‚
            â”‚ 3   â”† 3.0 â”‚
            â”‚ 5   â”† 5.0 â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

            >>> func(df_pa)  # nan != null for pyarrow
            pyarrow.Table
            a: int64
            b: double
            ----
            a: [[2,4,0,3,5]]
            b: [[2,4,nan,3,5]]
        c                   s   ˆ   | ¡ ˆ¡S r   )r   Ú	fill_nullr&   ©r!   r   r   r   r)   Á  r*   z Expr.fill_null.<locals>.<lambda>r+   r   r   r   r   rŽ   „  s    =zExpr.fill_nullc                   s   ˆ   ‡ fdd„¡S )u  
        Remove missing values.

        Notes:
            pandas and Polars handle null values differently. Polars distinguishes
            between NaN and Null, whereas pandas doesn't.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa

            >>> df_pd = pd.DataFrame({"a": [2.0, 4.0, float("nan"), 3.0, None, 5.0]})
            >>> df_pl = pl.DataFrame({"a": [2.0, 4.0, float("nan"), 3.0, None, 5.0]})
            >>> df_pa = pa.table({"a": [2.0, 4.0, float("nan"), 3.0, None, 5.0]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").drop_nulls())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                 a
            0  2.0
            1  4.0
            3  3.0
            5  5.0
            >>> func(df_pl)  # nan != null for polars
            shape: (5, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ f64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 2.0 â”‚
            â”‚ 4.0 â”‚
            â”‚ NaN â”‚
            â”‚ 3.0 â”‚
            â”‚ 5.0 â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)  # nan != null for pyarrow
            pyarrow.Table
            a: double
            ----
            a: [[2,4,nan,3,5]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Ú
drop_nullsr&   r(   r   r   r)   ÷  r*   z!Expr.drop_nulls.<locals>.<lambda>r+   r(   r   r(   r   r   Ä  s    3zExpr.drop_nullsN©ÚfractionÚwith_replacementÚseedú
int | Nonezfloat | None)r!   ri   r’   r“   r”   r   c                  s   ˆ  ‡ ‡‡‡‡fdd„¡S )ut  
        Sample randomly from this expression.

        Arguments:
            n: Number of items to return. Cannot be used with fraction.
            fraction: Fraction of items to return. Cannot be used with n.
            with_replacement: Allow values to be sampled more than once.
            seed: Seed for the random number generator. If set to None (default), a random
                seed is generated for each sample operation.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> df_pd = pd.DataFrame({"a": [1, 2, 3]})
            >>> df_pl = pl.DataFrame({"a": [1, 2, 3]})
            >>> df_pa = pa.table({"a": [1, 2, 3]})

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").sample(fraction=1.0, with_replacement=True))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)  # doctest: +SKIP
               a
            2  3
            0  1
            2  3
            >>> func(df_pl)  # doctest: +SKIP
            shape: (3, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ f64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 2   â”‚
            â”‚ 3   â”‚
            â”‚ 3   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)  # doctest: +SKIP
            pyarrow.Table
            a: int64
            ----
            a: [[1,3,3]]
        c                   s   ˆ  | ¡jˆˆ ˆˆdS )Nr‘   )r   Úsampler&   ©r’   ri   r”   r!   r“   r   r   r)   3  s
   
   ÿzExpr.sample.<locals>.<lambda>r+   )r!   ri   r’   r“   r”   r   r—   r   r–   ù  s    9ÿzExpr.sampleústr | Iterable[str])Úkeysr   c                   s   ˆ  ‡ ‡fdd„¡S )u   
        Compute expressions over the given groups.

        Arguments:
            keys: Names of columns to compute window expression over.
                  Must be names of columns, as opposed to expressions -
                  so, this is a bit less flexible than Polars' `Expr.over`.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1, 2, 3], "b": [1, 1, 2]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(a_min_per_group=nw.col("a").min().over("b"))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a  b  a_min_per_group
            0  1  1                1
            1  2  1                1
            2  3  2                3
            >>> func(df_pl)
            shape: (3, 3)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”† a_min_per_group â”‚
            â”‚ --- â”† --- â”† ---             â”‚
            â”‚ i64 â”† i64 â”† i64             â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 1   â”† 1   â”† 1               â”‚
            â”‚ 2   â”† 1   â”† 1               â”‚
            â”‚ 3   â”† 2   â”† 3               â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            a_min_per_group: int64
            ----
            a: [[1,2,3]]
            b: [[1,1,2]]
            a_min_per_group: [[1,1,3]]
        c                   s   ˆ  | ¡ tˆ ƒ¡S r   )r   Úoverr   r&   ©r™   r!   r   r   r)   m  r*   zExpr.over.<locals>.<lambda>r+   )r!   r™   r   r›   r   rš   8  s    5z	Expr.overc                   s   ˆ   ‡ fdd„¡S )u"  
        Return a boolean mask indicating duplicated values.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1, 2, 3, 1], "b": ["a", "a", "b", "c"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.all().is_duplicated())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                   a      b
            0   True   True
            1  False   True
            2  False  False
            3   True  False
            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a     â”† b     â”‚
            â”‚ ---   â”† ---   â”‚
            â”‚ bool  â”† bool  â”‚
            â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
            â”‚ true  â”† true  â”‚
            â”‚ false â”† true  â”‚
            â”‚ false â”† false â”‚
            â”‚ true  â”† false â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: bool
            b: bool
            ----
            a: [[true,false,false,true]]
            b: [[true,true,false,false]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úis_duplicatedr&   r(   r   r   r)   Ÿ  r*   z$Expr.is_duplicated.<locals>.<lambda>r+   r(   r   r(   r   rœ   o  s    0zExpr.is_duplicatedc                   s   ˆ   ‡ fdd„¡S )u  
        Return a boolean mask indicating unique values.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1, 2, 3, 1], "b": ["a", "a", "b", "c"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.all().is_unique())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                   a      b
            0  False  False
            1   True  False
            2   True   True
            3  False   True
            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a     â”† b     â”‚
            â”‚ ---   â”† ---   â”‚
            â”‚ bool  â”† bool  â”‚
            â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
            â”‚ false â”† false â”‚
            â”‚ true  â”† false â”‚
            â”‚ true  â”† true  â”‚
            â”‚ false â”† true  â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: bool
            b: bool
            ----
            a: [[false,true,true,false]]
            b: [[false,false,true,true]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Ú	is_uniquer&   r(   r   r   r)   Ñ  r*   z Expr.is_unique.<locals>.<lambda>r+   r(   r   r(   r   r   ¡  s    0zExpr.is_uniquec                   s   ˆ   ‡ fdd„¡S )uv  
        Count null values.

        Notes:
            pandas and Polars handle null values differently. Polars distinguishes
            between NaN and Null, whereas pandas doesn't.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1, 2, None, 1], "b": ["a", None, "b", None]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.all().null_count())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a  b
            0  1  2
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a   â”† b   â”‚
            â”‚ --- â”† --- â”‚
            â”‚ u32 â”† u32 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 1   â”† 2   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            b: int64
            ----
            a: [[1]]
            b: [[2]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Ú
null_countr&   r(   r   r   r)     r*   z!Expr.null_count.<locals>.<lambda>r+   r(   r   r(   r   rž   Ó  s    .zExpr.null_countc                   s   ˆ   ‡ fdd„¡S )u>  
        Return a boolean mask indicating the first occurrence of each distinct value.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1, 2, 3, 1], "b": ["a", "a", "b", "c"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.all().is_first_distinct())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                   a      b
            0   True   True
            1   True  False
            2   True   True
            3  False   True
            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a     â”† b     â”‚
            â”‚ ---   â”† ---   â”‚
            â”‚ bool  â”† bool  â”‚
            â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
            â”‚ true  â”† true  â”‚
            â”‚ true  â”† false â”‚
            â”‚ true  â”† true  â”‚
            â”‚ false â”† true  â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: bool
            b: bool
            ----
            a: [[true,true,true,false]]
            b: [[true,false,true,true]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úis_first_distinctr&   r(   r   r   r)   3  r*   z(Expr.is_first_distinct.<locals>.<lambda>r+   r(   r   r(   r   rŸ     s    0zExpr.is_first_distinctc                   s   ˆ   ‡ fdd„¡S )u3  Return a boolean mask indicating the last occurrence of each distinct value.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1, 2, 3, 1], "b": ["a", "a", "b", "c"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.all().is_last_distinct())

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                   a      b
            0  False  False
            1   True   True
            2   True   True
            3   True   True
            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a     â”† b     â”‚
            â”‚ ---   â”† ---   â”‚
            â”‚ bool  â”† bool  â”‚
            â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
            â”‚ false â”† false â”‚
            â”‚ true  â”† true  â”‚
            â”‚ true  â”† true  â”‚
            â”‚ true  â”† true  â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: bool
            b: bool
            ----
            a: [[false,true,true,true]]
            b: [[false,true,true,true]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úis_last_distinctr&   r(   r   r   r)   d  r*   z'Expr.is_last_distinct.<locals>.<lambda>r+   r(   r   r(   r   r    5  s    /zExpr.is_last_distinctÚfloatz=Literal[('nearest', 'higher', 'lower', 'midpoint', 'linear')])ÚquantileÚinterpolationr   c                   s   ˆ  ‡ ‡‡fdd„¡S )uA  Get quantile value.

        Note:
            - pandas and Polars may have implementation differences for a given interpolation method.
            - [dask](https://docs.dask.org/en/stable/generated/dask.dataframe.Series.quantile.html) has its own method to approximate quantile and it doesn't implement 'nearest', 'higher', 'lower', 'midpoint'
            as interpolation method - use 'linear' which is closest to the native 'dask' - method.

        Arguments:
            quantile: Quantile between 0.0 and 1.0.
            interpolation: Interpolation method.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": list(range(50)), "b": list(range(50, 100))}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a", "b").quantile(0.5, interpolation="linear"))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                  a     b
            0  24.5  74.5

            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”
            â”‚ a    â”† b    â”‚
            â”‚ ---  â”† ---  â”‚
            â”‚ f64  â”† f64  â”‚
            â•žâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•¡
            â”‚ 24.5 â”† 74.5 â”‚
            â””â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: double
            b: double
            ----
            a: [[24.5]]
            b: [[74.5]]
        c                   s   ˆ  | ¡ ˆˆ ¡S r   )r   r¢   r&   ©r£   r¢   r!   r   r   r)   ž  r*   zExpr.quantile.<locals>.<lambda>r+   )r!   r¢   r£   r   r¤   r   r¢   f  s    7ÿzExpr.quantileé
   c                   s   ˆ  ‡ ‡fdd„¡S )uê  
        Get the first `n` rows.

        Arguments:
            n: Number of rows to return.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": list(range(10))}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function that returns the first 3 rows:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").head(3))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a
            0  0
            1  1
            2  2
            >>> func(df_pl)
            shape: (3, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 0   â”‚
            â”‚ 1   â”‚
            â”‚ 2   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[0,1,2]]
        c                   s   ˆ  | ¡ ˆ ¡S r   )r   Úheadr&   rk   r   r   r)   Ð  r*   zExpr.head.<locals>.<lambda>r+   rl   r   rk   r   r¦   ¡  s    /z	Expr.headc                   s   ˆ  ‡ ‡fdd„¡S )uè  
        Get the last `n` rows.

        Arguments:
            n: Number of rows to return.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": list(range(10))}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function that returns the last 3 rows:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").tail(3))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a
            7  7
            8  8
            9  9
            >>> func(df_pl)
            shape: (3, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 7   â”‚
            â”‚ 8   â”‚
            â”‚ 9   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[7,8,9]]
        c                   s   ˆ  | ¡ ˆ ¡S r   )r   Útailr&   rk   r   r   r)     r*   zExpr.tail.<locals>.<lambda>r+   rl   r   rk   r   r§   Ò  s    /z	Expr.tailr   )Údecimalsr   c                   s   ˆ  ‡ ‡fdd„¡S )uË  
        Round underlying floating point data by `decimals` digits.

        Arguments:
            decimals: Number of decimals to round by.

        Notes:
            For values exactly halfway between rounded decimal values pandas behaves differently than Polars and Arrow.

            pandas rounds to the nearest even value (e.g. -0.5 and 0.5 round to 0.0, 1.5 and 2.5 round to 2.0, 3.5 and
            4.5 to 4.0, etc..).

            Polars and Arrow round away from 0 (e.g. -0.5 to -1.0, 0.5 to 1.0, 1.5 to 2.0, 2.5 to 3.0, etc..).


        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1.12345, 2.56789, 3.901234]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function that rounds to the first decimal:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").round(1))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
                 a
            0  1.1
            1  2.6
            2  3.9
            >>> func(df_pl)
            shape: (3, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ f64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 1.1 â”‚
            â”‚ 2.6 â”‚
            â”‚ 3.9 â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: double
            ----
            a: [[1.1,2.6,3.9]]
        c                   s   ˆ  | ¡ ˆ ¡S r   )r   Úroundr&   ©r¨   r!   r   r   r)   ;  r*   zExpr.round.<locals>.<lambda>r+   )r!   r¨   r   rª   r   r©     s    8z
Expr.roundc                   s   ˆ   ‡ fdd„¡S )uö  
        Return the number of elements in the column.

        Null values count towards the total.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": ["x", "y", "z"], "b": [1, 2, 1]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function that computes the len over different values of "b" column:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(
            ...         nw.col("a").filter(nw.col("b") == 1).len().alias("a1"),
            ...         nw.col("a").filter(nw.col("b") == 2).len().alias("a2"),
            ...     )

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a1  a2
            0   2   1
            >>> func(df_pl)
            shape: (1, 2)
            â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ a1  â”† a2  â”‚
            â”‚ --- â”† --- â”‚
            â”‚ u32 â”† u32 â”‚
            â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 2   â”† 1   â”‚
            â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a1: int64
            a2: int64
            ----
            a1: [[2]]
            a2: [[1]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úlenr&   r(   r   r   r)   l  r*   zExpr.len.<locals>.<lambda>r+   r(   r   r(   r   r«   =  s    /zExpr.len)r!   ri   Úoffsetr   c                   s   ˆ  ‡ ‡‡fdd„¡S )uS  
        Take every nth value in the Series and return as new Series.

        Arguments:
            n: Gather every *n*-th row.
            offset: Starting index.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function in which gather every 2 rows,
            starting from a offset of 1:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").gather_every(n=2, offset=1))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a
            1  2
            3  4
            >>> func(df_pl)
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 2   â”‚
            â”‚ 4   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[2,4]]
        c                   s   ˆ  | ¡jˆ ˆdS )N)ri   r¬   )r   Úgather_everyr&   ©ri   r¬   r!   r   r   r)   ž  r*   z#Expr.gather_every.<locals>.<lambda>r+   )r!   ri   r¬   r   r®   r   r­   n  s    /ÿzExpr.gather_everyz
Any | None)rx   ry   r   c                   s   ˆ  ‡ ‡‡fdd„¡S )uÊ  
        Clip values in the Series.

        Arguments:
            lower_bound: Lower bound value.
            upper_bound: Upper bound value.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw

            >>> s = [1, 2, 3]
            >>> df_pd = pd.DataFrame({"s": s})
            >>> df_pl = pl.DataFrame({"s": s})
            >>> df_pa = pa.table({"s": s})

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func_lower(df):
            ...     return df.select(nw.col("s").clip(2))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func_lower`:

            >>> func_lower(df_pd)
               s
            0  2
            1  2
            2  3
            >>> func_lower(df_pl)
            shape: (3, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ s   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 2   â”‚
            â”‚ 2   â”‚
            â”‚ 3   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func_lower(df_pa)
            pyarrow.Table
            s: int64
            ----
            s: [[2,2,3]]

            We define another library agnostic function:

            >>> @nw.narwhalify
            ... def func_upper(df):
            ...     return df.select(nw.col("s").clip(upper_bound=2))

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func_upper`:

            >>> func_upper(df_pd)
               s
            0  1
            1  2
            2  2
            >>> func_upper(df_pl)
            shape: (3, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ s   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 1   â”‚
            â”‚ 2   â”‚
            â”‚ 2   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func_upper(df_pa)
            pyarrow.Table
            s: int64
            ----
            s: [[1,2,2]]

            We can have both at the same time

            >>> s = [-1, 1, -3, 3, -5, 5]
            >>> df_pd = pd.DataFrame({"s": s})
            >>> df_pl = pl.DataFrame({"s": s})
            >>> df_pa = pa.table({"s": s})

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("s").clip(-1, 3))

            We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               s
            0 -1
            1  1
            2 -1
            3  3
            4 -1
            5  3
            >>> func(df_pl)
            shape: (6, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ s   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ -1  â”‚
            â”‚ 1   â”‚
            â”‚ -1  â”‚
            â”‚ 3   â”‚
            â”‚ -1  â”‚
            â”‚ 3   â”‚
            â””â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            s: int64
            ----
            s: [[-1,1,-1,3,-1,3]]
        c                   s   ˆ  | ¡ ˆ ˆ¡S r   )r   Úclipr&   ©rx   r!   ry   r   r   r)   !	  r*   zExpr.clip.<locals>.<lambda>r+   )r!   rx   ry   r   r°   r   r¯   £  s    ~z	Expr.clip©r!   r   c                   s   ˆ   ‡ fdd„¡S )u´  Compute the most occurring value(s).

        Can return multiple values.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw

            >>> data = {
            ...     "a": [1, 1, 2, 3],
            ...     "b": [1, 1, 2, 2],
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").mode()).sort("a")

            We can then pass any supported library such as Pandas, Polars, or PyArrow to `func`:

            >>> func(df_pd)
               a
            0  1

            >>> func(df_pl)
            shape: (1, 1)
            â”Œâ”€â”€â”€â”€â”€â”
            â”‚ a   â”‚
            â”‚ --- â”‚
            â”‚ i64 â”‚
            â•žâ•â•â•â•â•â•¡
            â”‚ 1   â”‚
            â””â”€â”€â”€â”€â”€â”˜

            >>> func(df_pa)
            pyarrow.Table
            a: int64
            ----
            a: [[1]]
        c                   s   ˆ   | ¡ ¡ S r   )r   Úmoder&   r(   r   r   r)   R	  r*   zExpr.mode.<locals>.<lambda>r+   r(   r   r(   r   r²   #	  s    /z	Expr.modezExprStringNamespace[Self]c                 C  s   t | ƒS r   )ÚExprStringNamespacer(   r   r   r   r.   T	  s    zExpr.strzExprDateTimeNamespace[Self]c                 C  s   t | ƒS r   )ÚExprDateTimeNamespacer(   r   r   r   ÚdtX	  s    zExpr.dtzExprCatNamespace[Self]c                 C  s   t | ƒS r   )ÚExprCatNamespacer(   r   r   r   Úcat\	  s    zExpr.catzExprNameNamespace[Self]c                 C  s   t | ƒS r   )ÚExprNameNamespacer(   r   r   r   r/   `	  s    z	Expr.name)rw   )N)r¥   )r¥   )r   )r   )NN)LÚ__name__Ú
__module__Ú__qualname__r"   r-   r0   r5   r7   r:   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   r\   r%   r^   r_   r`   ra   re   r$   rg   rh   rj   rp   ru   r{   r}   r‡   rŠ   r‹   rŽ   r   r–   rš   rœ   r   rž   rŸ   r    r¢   r¦   r§   r©   r«   r­   r¯   r²   Úpropertyr.   rµ   r·   r/   r   r   r   r   r       sª   /08+++0+++++6.3::DT ÿ<96E,@7 þú?722021;11:17  ý 1ÚT)Úboundc                   @  s.   e Zd Zddddœdd„Zdddœdd	„Zd
S )r¶   r   r½   r   ©r!   r   r   c                 C  s
   || _ d S r   ©Ú_expr©r!   r   r   r   r   r"   i	  s    zExprCatNamespace.__init__r±   c                   s   ˆ j  ‡ fdd„¡S )u  
        Get unique categories from column.

        Examples:
            Let's create some dataframes:

            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"fruits": ["apple", "mango", "mango"]}
            >>> df_pd = pd.DataFrame(data, dtype="category")
            >>> df_pl = pl.DataFrame(data, schema={"fruits": pl.Categorical})

            We define a dataframe-agnostic function to get unique categories
            from column 'fruits':

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("fruits").cat.get_categories())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
              fruits
            0  apple
            1  mango
            >>> func(df_pl)
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ fruits â”‚
            â”‚ ---    â”‚
            â”‚ str    â”‚
            â•žâ•â•â•â•â•â•â•â•â•¡
            â”‚ apple  â”‚
            â”‚ mango  â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   r·   Úget_categoriesr&   r(   r   r   r)   “	  r*   z1ExprCatNamespace.get_categories.<locals>.<lambda>©rÁ   r,   r(   r   r(   r   rÃ   l	  s    &
ÿzExprCatNamespace.get_categoriesN)r¹   rº   r»   r"   rÃ   r   r   r   r   r¶   h	  s   r¶   c                   @  s,  e Zd Zddddœdd„Zdddœdd	„Zd
ddœddddddœdd„Zd
dœddddddœdd„Zd6ddddœdd„Zddddœdd„Zddddœd d!„Z	d
dœddddd"œd#d$„Z
d7ddd%dd&œd'd(„Zd8dddd*œd+d,„Zd9dddd*œd-d.„Zd:dddd/œd0d1„Zdddœd2d3„Zdddœd4d5„ZdS );r³   r   r½   r   r¿   c                 C  s
   || _ d S r   rÀ   rÂ   r   r   r   r"   ˜	  s    zExprStringNamespace.__init__r±   c                   s   ˆ j  ‡ fdd„¡S )uµ  
        Return the length of each string as the number of characters.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"words": ["foo", "CafÃ©", "345", "æ±äº¬", None]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(words_len=nw.col("words").str.len_chars())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
              words  words_len
            0   foo        3.0
            1  CafÃ©        4.0
            2   345        3.0
            3    æ±äº¬        2.0
            4  None        NaN

            >>> func(df_pl)
            shape: (5, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ words â”† words_len â”‚
            â”‚ ---   â”† ---       â”‚
            â”‚ str   â”† u32       â”‚
            â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ foo   â”† 3         â”‚
            â”‚ CafÃ©  â”† 4         â”‚
            â”‚ 345   â”† 3         â”‚
            â”‚ æ±äº¬  â”† 2         â”‚
            â”‚ null  â”† null      â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   r.   Ú	len_charsr&   r(   r   r   r)   Å	  r*   z/ExprStringNamespace.len_chars.<locals>.<lambda>rÄ   r(   r   r(   r   rÅ   ›	  s    *zExprStringNamespace.len_charsFrX   ©Úliteralri   r.   rd   r[   )Úpatternr   rÇ   ri   r   c                  s   ˆj  ‡ ‡‡‡‡fdd„¡S )a{  
        Replace first matching regex/literal substring with a new string value.

        Arguments:
            pattern: A valid regular expression pattern.
            value: String that will replace the matched substring.
            literal: Treat `pattern` as a literal string.
            n: Number of matches to replace.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"foo": ["123abc", "abc abc123"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     df = df.with_columns(replaced=nw.col("foo").str.replace("abc", ""))
            ...     return df.to_dict(as_series=False)

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
            {'foo': ['123abc', 'abc abc123'], 'replaced': ['123', ' abc123']}

            >>> func(df_pl)
            {'foo': ['123abc', 'abc abc123'], 'replaced': ['123', ' abc123']}

        c                   s   ˆj  | ¡jjˆˆˆ ˆdS )NrÆ   )rÁ   r   r.   Úreplacer&   ©rÇ   ri   rÈ   r!   r   r   r   r)   ì	  s
      ÿz-ExprStringNamespace.replace.<locals>.<lambda>rÄ   )r!   rÈ   r   rÇ   ri   r   rÊ   r   rÉ   Ç	  s    $ÿzExprStringNamespace.replace©rÇ   )r!   rÈ   r   rÇ   r   c                  s   ˆj  ‡ ‡‡‡fdd„¡S )aJ  
        Replace all matching regex/literal substring with a new string value.

        Arguments:
            pattern: A valid regular expression pattern.
            value: String that will replace the matched substring.
            literal: Treat `pattern` as a literal string.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"foo": ["123abc", "abc abc123"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     df = df.with_columns(replaced=nw.col("foo").str.replace_all("abc", ""))
            ...     return df.to_dict(as_series=False)

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
            {'foo': ['123abc', 'abc abc123'], 'replaced': ['123', ' 123']}

            >>> func(df_pl)
            {'foo': ['123abc', 'abc abc123'], 'replaced': ['123', ' 123']}

        c                   s   ˆj  | ¡jjˆˆˆ dS ©NrË   )rÁ   r   r.   Úreplace_allr&   ©rÇ   rÈ   r!   r   r   r   r)   
  s     ÿz1ExprStringNamespace.replace_all.<locals>.<lambda>rÄ   )r!   rÈ   r   rÇ   r   rÎ   r   rÍ   ñ	  s    !ÿzExprStringNamespace.replace_allNú
str | None)r!   Ú
charactersr   c                   s   ˆj  ‡ ‡fdd„¡S )ac  
        Remove leading and trailing characters.

        Arguments:
            characters: The set of characters to be removed. All combinations of this set of characters will be stripped from the start and end of the string. If set to None (default), all leading and trailing whitespace is removed instead.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"fruits": ["apple", "\nmango"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     df = df.with_columns(stripped=nw.col("fruits").str.strip_chars())
            ...     return df.to_dict(as_series=False)

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
            {'fruits': ['apple', '\nmango'], 'stripped': ['apple', 'mango']}

            >>> func(df_pl)
            {'fruits': ['apple', '\nmango'], 'stripped': ['apple', 'mango']}
        c                   s   ˆj  | ¡j ˆ ¡S r   )rÁ   r   r.   Ústrip_charsr&   ©rÐ   r!   r   r   r)   7
  r*   z1ExprStringNamespace.strip_chars.<locals>.<lambda>rÄ   )r!   rÐ   r   rÒ   r   rÑ   
  s    ÿzExprStringNamespace.strip_chars©r!   Úprefixr   c                   s   ˆj  ‡ ‡fdd„¡S )uf  
        Check if string values start with a substring.

        Arguments:
            prefix: prefix substring

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"fruits": ["apple", "mango", None]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(has_prefix=nw.col("fruits").str.starts_with("app"))

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
              fruits has_prefix
            0  apple       True
            1  mango      False
            2   None       None

            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ fruits â”† has_prefix â”‚
            â”‚ ---    â”† ---        â”‚
            â”‚ str    â”† bool       â”‚
            â•žâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ apple  â”† true       â”‚
            â”‚ mango  â”† false      â”‚
            â”‚ null   â”† null       â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆj  | ¡j ˆ ¡S r   )rÁ   r   r.   Ústarts_withr&   ©rÔ   r!   r   r   r)   d
  r*   z1ExprStringNamespace.starts_with.<locals>.<lambda>rÄ   ©r!   rÔ   r   rÖ   r   rÕ   :
  s    )ÿzExprStringNamespace.starts_with©r!   Úsuffixr   c                   s   ˆ j  ‡ ‡fdd„¡S )ub  
        Check if string values end with a substring.

        Arguments:
            suffix: suffix substring

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"fruits": ["apple", "mango", None]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(has_suffix=nw.col("fruits").str.ends_with("ngo"))

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
              fruits has_suffix
            0  apple      False
            1  mango       True
            2   None       None

            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ fruits â”† has_suffix â”‚
            â”‚ ---    â”† ---        â”‚
            â”‚ str    â”† bool       â”‚
            â•žâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ apple  â”† false      â”‚
            â”‚ mango  â”† true       â”‚
            â”‚ null   â”† null       â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ˆ¡S r   )rÁ   r   r.   Ú	ends_withr&   ©r!   rÙ   r   r   r)   ‘
  r*   z/ExprStringNamespace.ends_with.<locals>.<lambda>rÄ   rÛ   r   rÛ   r   rÚ   g
  s    )ÿzExprStringNamespace.ends_with)r!   rÈ   rÇ   r   c                  s   ˆj  ‡ ‡‡fdd„¡S )u  
        Check if string contains a substring that matches a pattern.

        Arguments:
            pattern: A Character sequence or valid regular expression pattern.
            literal: If True, treats the pattern as a literal string.
                     If False, assumes the pattern is a regular expression.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"pets": ["cat", "dog", "rabbit and parrot", "dove", None]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         default_match=nw.col("pets").str.contains("parrot|Dove"),
            ...         case_insensitive_match=nw.col("pets").str.contains("(?i)parrot|Dove"),
            ...         literal_match=nw.col("pets").str.contains(
            ...             "parrot|Dove", literal=True
            ...         ),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                            pets default_match case_insensitive_match literal_match
            0                cat         False                  False         False
            1                dog         False                  False         False
            2  rabbit and parrot          True                   True         False
            3               dove         False                   True         False
            4               None          None                   None          None
            >>> func(df_pl)
            shape: (5, 4)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ pets              â”† default_match â”† case_insensitive_match â”† literal_match â”‚
            â”‚ ---               â”† ---           â”† ---                    â”† ---           â”‚
            â”‚ str               â”† bool          â”† bool                   â”† bool          â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ cat               â”† false         â”† false                  â”† false         â”‚
            â”‚ dog               â”† false         â”† false                  â”† false         â”‚
            â”‚ rabbit and parrot â”† true          â”† true                   â”† false         â”‚
            â”‚ dove              â”† false         â”† true                   â”† false         â”‚
            â”‚ null              â”† null          â”† null                   â”† null          â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆj  | ¡jjˆˆ dS rÌ   )rÁ   r   r.   Úcontainsr&   ©rÇ   rÈ   r!   r   r   r)   É
  r*   z.ExprStringNamespace.contains.<locals>.<lambda>rÄ   )r!   rÈ   rÇ   r   rÝ   r   rÜ   ”
  s    4ÿzExprStringNamespace.containsr•   )r!   r¬   Úlengthr   c                   s   ˆj  ‡ ‡‡fdd„¡S )u½
  
        Create subslices of the string values of an expression.

        Arguments:
            offset: Start index. Negative indexing is supported.
            length: Length of the slice. If set to `None` (default), the slice is taken to the
                end of the string.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"s": ["pear", None, "papaya", "dragonfruit"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(s_sliced=nw.col("s").str.slice(4, length=3))

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)  # doctest: +NORMALIZE_WHITESPACE
                         s s_sliced
            0         pear
            1         None     None
            2       papaya       ya
            3  dragonfruit      onf

            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ s           â”† s_sliced â”‚
            â”‚ ---         â”† ---      â”‚
            â”‚ str         â”† str      â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ pear        â”†          â”‚
            â”‚ null        â”† null     â”‚
            â”‚ papaya      â”† ya       â”‚
            â”‚ dragonfruit â”† onf      â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜

            Using negative indexes:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(s_sliced=nw.col("s").str.slice(-3))

            >>> func(df_pd)
                         s s_sliced
            0         pear      ear
            1         None     None
            2       papaya      aya
            3  dragonfruit      uit

            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ s           â”† s_sliced â”‚
            â”‚ ---         â”† ---      â”‚
            â”‚ str         â”† str      â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ pear        â”† ear      â”‚
            â”‚ null        â”† null     â”‚
            â”‚ papaya      â”† aya      â”‚
            â”‚ dragonfruit â”† uit      â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆj  | ¡jjˆˆ dS )N)r¬   rÞ   ©rÁ   r   r.   Úslicer&   ©rÞ   r¬   r!   r   r   r)     r*   z+ExprStringNamespace.slice.<locals>.<lambda>rÄ   )r!   r¬   rÞ   r   rá   r   rà   Ì
  s    GÿzExprStringNamespace.sliceé   )r!   ri   r   c                   s   ˆj  ‡ ‡fdd„¡S )u¯  
        Take the first n elements of each string.

        Arguments:
            n: Number of elements to take. Negative indexing is **not** supported.

        Notes:
            If the length of the string has fewer than `n` characters, the full string is returned.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"lyrics": ["Atatata", "taata", "taatatata", "zukkyun"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(lyrics_head=nw.col("lyrics").str.head())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                  lyrics lyrics_head
            0    Atatata       Atata
            1      taata       taata
            2  taatatata       taata
            3    zukkyun       zukky

            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ lyrics    â”† lyrics_head â”‚
            â”‚ ---       â”† ---         â”‚
            â”‚ str       â”† str         â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ Atatata   â”† Atata       â”‚
            â”‚ taata     â”† taata       â”‚
            â”‚ taatatata â”† taata       â”‚
            â”‚ zukkyun   â”† zukky       â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆj  | ¡j dˆ ¡S )Nr   rß   r&   rk   r   r   r)   E  r*   z*ExprStringNamespace.head.<locals>.<lambda>rÄ   rl   r   rk   r   r¦     s    .zExprStringNamespace.headc                   s   ˆj  ‡ ‡fdd„¡S )u®  
        Take the last n elements of each string.

        Arguments:
            n: Number of elements to take. Negative indexing is **not** supported.

        Notes:
            If the length of the string has fewer than `n` characters, the full string is returned.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"lyrics": ["Atatata", "taata", "taatatata", "zukkyun"]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(lyrics_tail=nw.col("lyrics").str.tail())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                  lyrics lyrics_tail
            0    Atatata       atata
            1      taata       taata
            2  taatatata       atata
            3    zukkyun       kkyun

            >>> func(df_pl)
            shape: (4, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ lyrics    â”† lyrics_tail â”‚
            â”‚ ---       â”† ---         â”‚
            â”‚ str       â”† str         â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ Atatata   â”† atata       â”‚
            â”‚ taata     â”† taata       â”‚
            â”‚ taatatata â”† atata       â”‚
            â”‚ zukkyun   â”† kkyun       â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆj  | ¡j ˆ  ¡S r   rß   r&   rk   r   r   r)   u  r*   z*ExprStringNamespace.tail.<locals>.<lambda>rÄ   rl   r   rk   r   r§   G  s    .zExprStringNamespace.tail©r!   Úformatr   c                   s   ˆj  ‡ ‡fdd„¡S )uI  
        Convert to Datetime dtype.

        Notes:
            pandas defaults to nanosecond time unit, Polars to microsecond.
            Prior to pandas 2.0, nanoseconds were the only time unit supported
            in pandas, with no ability to set any other one. The ability to
            set the time unit in pandas, if the version permits, will arrive.

        Warning:
            As different backends auto-infer format in different ways, if `format=None`
            there is no guarantee that the result will be equal.

        Arguments:
            format: Format to use for conversion. If set to None (default), the format is
                inferred from the data.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> data = ["2020-01-01", "2020-01-02"]
            >>> df_pd = pd.DataFrame({"a": data})
            >>> df_pl = pl.DataFrame({"a": data})
            >>> df_pa = pa.table({"a": data})

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").str.to_datetime(format="%Y-%m-%d"))

            We can then pass any supported library such as pandas, Polars, or PyArrow:

            >>> func(df_pd)
                       a
            0 2020-01-01
            1 2020-01-02
            >>> func(df_pl)
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a                   â”‚
            â”‚ ---                 â”‚
            â”‚ datetime[Î¼s]        â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2020-01-01 00:00:00 â”‚
            â”‚ 2020-01-02 00:00:00 â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: timestamp[us]
            ----
            a: [[2020-01-01 00:00:00.000000,2020-01-02 00:00:00.000000]]
        c                   s   ˆj  | ¡jjˆ dS )N)rä   )rÁ   r   r.   Úto_datetimer&   ©rä   r!   r   r   r)   °  r*   z1ExprStringNamespace.to_datetime.<locals>.<lambda>rÄ   ©r!   rä   r   ræ   r   rå   w  s    8ÿzExprStringNamespace.to_datetimec                   s   ˆ j  ‡ fdd„¡S )u'  
        Transform string to uppercase variant.

        Notes:
            The PyArrow backend will convert 'ÃŸ' to 'áºž' instead of 'SS'.
            For more info see [the related issue](https://github.com/apache/arrow/issues/34599).
            There may be other unicode-edge-case-related variations across implementations.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"fruits": ["apple", "mango", None]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(upper_col=nw.col("fruits").str.to_uppercase())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
              fruits upper_col
            0  apple     APPLE
            1  mango     MANGO
            2   None      None

            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ fruits â”† upper_col â”‚
            â”‚ ---    â”† ---       â”‚
            â”‚ str    â”† str       â”‚
            â•žâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ apple  â”† APPLE     â”‚
            â”‚ mango  â”† MANGO     â”‚
            â”‚ null   â”† null      â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜

        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   r.   Úto_uppercaser&   r(   r   r   r)   ß  r*   z2ExprStringNamespace.to_uppercase.<locals>.<lambda>rÄ   r(   r   r(   r   rè   ³  s    ,z ExprStringNamespace.to_uppercasec                   s   ˆ j  ‡ fdd„¡S )u  
        Transform string to lowercase variant.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = {"fruits": ["APPLE", "MANGO", None]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(lower_col=nw.col("fruits").str.to_lowercase())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
              fruits lower_col
            0  APPLE     apple
            1  MANGO     mango
            2   None      None

            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ fruits â”† lower_col â”‚
            â”‚ ---    â”† ---       â”‚
            â”‚ str    â”† str       â”‚
            â•žâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ APPLE  â”† apple     â”‚
            â”‚ MANGO  â”† mango     â”‚
            â”‚ null   â”† null      â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   r.   Úto_lowercaser&   r(   r   r   r)     r*   z2ExprStringNamespace.to_lowercase.<locals>.<lambda>rÄ   r(   r   r(   r   ré   á  s    &z ExprStringNamespace.to_lowercase)N)N)râ   )râ   )N)r¹   rº   r»   r"   rÅ   rÉ   rÍ   rÑ   rÕ   rÚ   rÜ   rà   r¦   r§   rå   rè   ré   r   r   r   r   r³   —	  s    - ÿ*'"--8K00<.r³   c                   @  sh  e Zd Zddddœdd„Zdddœdd	„Zdddœd
d„Zdddœdd„Zdddœdd„Zdddœdd„Zdddœdd„Z	dddœdd„Z
dddœdd„Zdddœdd„Zdddœdd„Zdddœdd„Zdddœdd„Zdddœd d!„Zdddœd"d#„Zdddœd$d%„Zdddœd&d'„Zdd(dd)œd*d+„Zdd,dd-œd.d/„Zdd(dd-œd0d1„Zd8dd3dd4œd5d6„Zd7S )9r´   r   r½   r   r¿   c                 C  s
   || _ d S r   rÀ   rÂ   r   r   r   r"     s    zExprDateTimeNamespace.__init__r±   c                   s   ˆ j  ‡ fdd„¡S )u  
        Extract the date from underlying DateTime representation.

        Raises:
            NotImplementedError: If pandas default backend is being used.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {"a": [datetime(2012, 1, 7, 10, 20), datetime(2023, 3, 10, 11, 32)]}
            >>> df_pd = pd.DataFrame(data).convert_dtypes(dtype_backend="pyarrow")
            >>> df_pl = pl.DataFrame(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").dt.date())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                        a
            0  2012-01-07
            1  2023-03-10

            >>> func(df_pl)  # docetst
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a          â”‚
            â”‚ ---        â”‚
            â”‚ date       â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2012-01-07 â”‚
            â”‚ 2023-03-10 â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Údater&   r(   r   r   r)   6  r*   z,ExprDateTimeNamespace.date.<locals>.<lambda>rÄ   r(   r   r(   r   rê     s    (zExprDateTimeNamespace.datec                   s   ˆ j  ‡ fdd„¡S )u©  
        Extract year from underlying DateTime representation.

        Returns the year number in the calendar date.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 6, 1),
            ...         datetime(2024, 12, 13),
            ...         datetime(2065, 1, 1),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(nw.col("datetime").dt.year().alias("year"))

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                datetime  year
            0 1978-06-01  1978
            1 2024-12-13  2024
            2 2065-01-01  2065
            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime            â”† year â”‚
            â”‚ ---                 â”† ---  â”‚
            â”‚ datetime[Î¼s]        â”† i32  â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•¡
            â”‚ 1978-06-01 00:00:00 â”† 1978 â”‚
            â”‚ 2024-12-13 00:00:00 â”† 2024 â”‚
            â”‚ 2065-01-01 00:00:00 â”† 2065 â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úyearr&   r(   r   r   r)   f  r*   z,ExprDateTimeNamespace.year.<locals>.<lambda>rÄ   r(   r   r(   r   rë   8  s    .zExprDateTimeNamespace.yearc                   s   ˆ j  ‡ fdd„¡S )uá  
        Extract month from underlying DateTime representation.

        Returns the month number starting from 1. The return value ranges from 1 to 12.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 6, 1),
            ...         datetime(2024, 12, 13),
            ...         datetime(2065, 1, 1),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("datetime").dt.year().alias("year"),
            ...         nw.col("datetime").dt.month().alias("month"),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                datetime  year  month
            0 1978-06-01  1978      6
            1 2024-12-13  2024     12
            2 2065-01-01  2065      1
            >>> func(df_pl)
            shape: (3, 3)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime            â”† year â”† month â”‚
            â”‚ ---                 â”† ---  â”† ---   â”‚
            â”‚ datetime[Î¼s]        â”† i32  â”† i8    â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
            â”‚ 1978-06-01 00:00:00 â”† 1978 â”† 6     â”‚
            â”‚ 2024-12-13 00:00:00 â”† 2024 â”† 12    â”‚
            â”‚ 2065-01-01 00:00:00 â”† 2065 â”† 1     â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úmonthr&   r(   r   r   r)   ™  r*   z-ExprDateTimeNamespace.month.<locals>.<lambda>rÄ   r(   r   r(   r   rì   h  s    1zExprDateTimeNamespace.monthc                   s   ˆ j  ‡ fdd„¡S )uÆ  
        Extract day from underlying DateTime representation.

        Returns the day of month starting from 1. The return value ranges from 1 to 31. (The last day of month differs by months.)

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 6, 1),
            ...         datetime(2024, 12, 13),
            ...         datetime(2065, 1, 1),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("datetime").dt.year().alias("year"),
            ...         nw.col("datetime").dt.month().alias("month"),
            ...         nw.col("datetime").dt.day().alias("day"),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                datetime  year  month  day
            0 1978-06-01  1978      6    1
            1 2024-12-13  2024     12   13
            2 2065-01-01  2065      1    1
            >>> func(df_pl)
            shape: (3, 4)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
            â”‚ datetime            â”† year â”† month â”† day â”‚
            â”‚ ---                 â”† ---  â”† ---   â”† --- â”‚
            â”‚ datetime[Î¼s]        â”† i32  â”† i8    â”† i8  â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•¡
            â”‚ 1978-06-01 00:00:00 â”† 1978 â”† 6     â”† 1   â”‚
            â”‚ 2024-12-13 00:00:00 â”† 2024 â”† 12    â”† 13  â”‚
            â”‚ 2065-01-01 00:00:00 â”† 2065 â”† 1     â”† 1   â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Údayr&   r(   r   r   r)   Í  r*   z+ExprDateTimeNamespace.day.<locals>.<lambda>rÄ   r(   r   r(   r   rí   ›  s    2zExprDateTimeNamespace.dayc                   s   ˆ j  ‡ fdd„¡S )uÏ  
        Extract hour from underlying DateTime representation.

        Returns the hour number from 0 to 23.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 1, 1, 1),
            ...         datetime(2024, 10, 13, 5),
            ...         datetime(2065, 1, 1, 10),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(nw.col("datetime").dt.hour().alias("hour"))

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                         datetime  hour
            0 1978-01-01 01:00:00     1
            1 2024-10-13 05:00:00     5
            2 2065-01-01 10:00:00    10
            >>> func(df_pl)
            shape: (3, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime            â”† hour â”‚
            â”‚ ---                 â”† ---  â”‚
            â”‚ datetime[Î¼s]        â”† i8   â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•¡
            â”‚ 1978-01-01 01:00:00 â”† 1    â”‚
            â”‚ 2024-10-13 05:00:00 â”† 5    â”‚
            â”‚ 2065-01-01 10:00:00 â”† 10   â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úhourr&   r(   r   r   r)   ý  r*   z,ExprDateTimeNamespace.hour.<locals>.<lambda>rÄ   r(   r   r(   r   rî   Ï  s    .zExprDateTimeNamespace.hourc                   s   ˆ j  ‡ fdd„¡S )u	  
        Extract minutes from underlying DateTime representation.

        Returns the minute number from 0 to 59.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 1, 1, 1, 1),
            ...         datetime(2024, 10, 13, 5, 30),
            ...         datetime(2065, 1, 1, 10, 20),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("datetime").dt.hour().alias("hour"),
            ...         nw.col("datetime").dt.minute().alias("minute"),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                         datetime  hour  minute
            0 1978-01-01 01:01:00     1       1
            1 2024-10-13 05:30:00     5      30
            2 2065-01-01 10:20:00    10      20
            >>> func(df_pl)
            shape: (3, 3)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime            â”† hour â”† minute â”‚
            â”‚ ---                 â”† ---  â”† ---    â”‚
            â”‚ datetime[Î¼s]        â”† i8   â”† i8     â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•¡
            â”‚ 1978-01-01 01:01:00 â”† 1    â”† 1      â”‚
            â”‚ 2024-10-13 05:30:00 â”† 5    â”† 30     â”‚
            â”‚ 2065-01-01 10:20:00 â”† 10   â”† 20     â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úminuter&   r(   r   r   r)   0  r*   z.ExprDateTimeNamespace.minute.<locals>.<lambda>rÄ   r(   r   r(   r   rï   ÿ  s    1zExprDateTimeNamespace.minutec                   s   ˆ j  ‡ fdd„¡S )uÞ  
        Extract seconds from underlying DateTime representation.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 1, 1, 1, 1, 1),
            ...         datetime(2024, 10, 13, 5, 30, 14),
            ...         datetime(2065, 1, 1, 10, 20, 30),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("datetime").dt.hour().alias("hour"),
            ...         nw.col("datetime").dt.minute().alias("minute"),
            ...         nw.col("datetime").dt.second().alias("second"),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                         datetime  hour  minute  second
            0 1978-01-01 01:01:01     1       1       1
            1 2024-10-13 05:30:14     5      30      14
            2 2065-01-01 10:20:30    10      20      30
            >>> func(df_pl)
            shape: (3, 4)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime            â”† hour â”† minute â”† second â”‚
            â”‚ ---                 â”† ---  â”† ---    â”† ---    â”‚
            â”‚ datetime[Î¼s]        â”† i8   â”† i8     â”† i8     â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•¡
            â”‚ 1978-01-01 01:01:01 â”† 1    â”† 1      â”† 1      â”‚
            â”‚ 2024-10-13 05:30:14 â”† 5    â”† 30     â”† 14     â”‚
            â”‚ 2065-01-01 10:20:30 â”† 10   â”† 20     â”† 30     â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úsecondr&   r(   r   r   r)   b  r*   z.ExprDateTimeNamespace.second.<locals>.<lambda>rÄ   r(   r   r(   r   rð   2  s    0zExprDateTimeNamespace.secondc                   s   ˆ j  ‡ fdd„¡S )u¥
  
        Extract milliseconds from underlying DateTime representation.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 1, 1, 1, 1, 1, 0),
            ...         datetime(2024, 10, 13, 5, 30, 14, 505000),
            ...         datetime(2065, 1, 1, 10, 20, 30, 67000),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("datetime").dt.hour().alias("hour"),
            ...         nw.col("datetime").dt.minute().alias("minute"),
            ...         nw.col("datetime").dt.second().alias("second"),
            ...         nw.col("datetime").dt.millisecond().alias("millisecond"),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                             datetime  hour  minute  second  millisecond
            0 1978-01-01 01:01:01.000     1       1       1            0
            1 2024-10-13 05:30:14.505     5      30      14          505
            2 2065-01-01 10:20:30.067    10      20      30           67
            >>> func(df_pl)
            shape: (3, 5)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime                â”† hour â”† minute â”† second â”† millisecond â”‚
            â”‚ ---                     â”† ---  â”† ---    â”† ---    â”† ---         â”‚
            â”‚ datetime[Î¼s]            â”† i8   â”† i8     â”† i8     â”† i32         â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 1978-01-01 01:01:01     â”† 1    â”† 1      â”† 1      â”† 0           â”‚
            â”‚ 2024-10-13 05:30:14.505 â”† 5    â”† 30     â”† 14     â”† 505         â”‚
            â”‚ 2065-01-01 10:20:30.067 â”† 10   â”† 20     â”† 30     â”† 67          â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úmillisecondr&   r(   r   r   r)   •  r*   z3ExprDateTimeNamespace.millisecond.<locals>.<lambda>rÄ   r(   r   r(   r   rñ   d  s    1z!ExprDateTimeNamespace.millisecondc                   s   ˆ j  ‡ fdd„¡S )u¥
  
        Extract microseconds from underlying DateTime representation.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 1, 1, 1, 1, 1, 0),
            ...         datetime(2024, 10, 13, 5, 30, 14, 505000),
            ...         datetime(2065, 1, 1, 10, 20, 30, 67000),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("datetime").dt.hour().alias("hour"),
            ...         nw.col("datetime").dt.minute().alias("minute"),
            ...         nw.col("datetime").dt.second().alias("second"),
            ...         nw.col("datetime").dt.microsecond().alias("microsecond"),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                             datetime  hour  minute  second  microsecond
            0 1978-01-01 01:01:01.000     1       1       1            0
            1 2024-10-13 05:30:14.505     5      30      14       505000
            2 2065-01-01 10:20:30.067    10      20      30        67000
            >>> func(df_pl)
            shape: (3, 5)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime                â”† hour â”† minute â”† second â”† microsecond â”‚
            â”‚ ---                     â”† ---  â”† ---    â”† ---    â”† ---         â”‚
            â”‚ datetime[Î¼s]            â”† i8   â”† i8     â”† i8     â”† i32         â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 1978-01-01 01:01:01     â”† 1    â”† 1      â”† 1      â”† 0           â”‚
            â”‚ 2024-10-13 05:30:14.505 â”† 5    â”† 30     â”† 14     â”† 505000      â”‚
            â”‚ 2065-01-01 10:20:30.067 â”† 10   â”† 20     â”† 30     â”† 67000       â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úmicrosecondr&   r(   r   r   r)   È  r*   z3ExprDateTimeNamespace.microsecond.<locals>.<lambda>rÄ   r(   r   r(   r   rò   —  s    1z!ExprDateTimeNamespace.microsecondc                   s   ˆ j  ‡ fdd„¡S )uŽ
  
        Extract Nanoseconds from underlying DateTime representation

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {
            ...     "datetime": [
            ...         datetime(1978, 1, 1, 1, 1, 1, 0),
            ...         datetime(2024, 10, 13, 5, 30, 14, 500000),
            ...         datetime(2065, 1, 1, 10, 20, 30, 60000),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("datetime").dt.hour().alias("hour"),
            ...         nw.col("datetime").dt.minute().alias("minute"),
            ...         nw.col("datetime").dt.second().alias("second"),
            ...         nw.col("datetime").dt.nanosecond().alias("nanosecond"),
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                             datetime  hour  minute  second  nanosecond
            0 1978-01-01 01:01:01.000     1       1       1           0
            1 2024-10-13 05:30:14.500     5      30      14   500000000
            2 2065-01-01 10:20:30.060    10      20      30    60000000
            >>> func(df_pl)
            shape: (3, 5)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ datetime                â”† hour â”† minute â”† second â”† nanosecond â”‚
            â”‚ ---                     â”† ---  â”† ---    â”† ---    â”† ---        â”‚
            â”‚ datetime[Î¼s]            â”† i8   â”† i8     â”† i8     â”† i32        â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 1978-01-01 01:01:01     â”† 1    â”† 1      â”† 1      â”† 0          â”‚
            â”‚ 2024-10-13 05:30:14.500 â”† 5    â”† 30     â”† 14     â”† 500000000  â”‚
            â”‚ 2065-01-01 10:20:30.060 â”† 10   â”† 20     â”† 30     â”† 60000000   â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Ú
nanosecondr&   r(   r   r   r)   û  r*   z2ExprDateTimeNamespace.nanosecond.<locals>.<lambda>rÄ   r(   r   r(   r   ró   Ê  s    1z ExprDateTimeNamespace.nanosecondc                   s   ˆ j  ‡ fdd„¡S )uò  
        Get ordinal day.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = {"a": [datetime(2020, 1, 1), datetime(2020, 8, 3)]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(a_ordinal_day=nw.col("a").dt.ordinal_day())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                       a  a_ordinal_day
            0 2020-01-01              1
            1 2020-08-03            216
            >>> func(df_pl)
            shape: (2, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a                   â”† a_ordinal_day â”‚
            â”‚ ---                 â”† ---           â”‚
            â”‚ datetime[Î¼s]        â”† i16           â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2020-01-01 00:00:00 â”† 1             â”‚
            â”‚ 2020-08-03 00:00:00 â”† 216           â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Úordinal_dayr&   r(   r   r   r)   !  r*   z3ExprDateTimeNamespace.ordinal_day.<locals>.<lambda>rÄ   r(   r   r(   r   rô   ý  s    $z!ExprDateTimeNamespace.ordinal_dayc                   s   ˆ j  ‡ fdd„¡S )uÑ  
        Get total minutes.

        Notes:
            The function outputs the total minutes in the int dtype by default,
            however, pandas may change the dtype to float when there are missing values,
            consider using `fill_null()` and `cast` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = {"a": [timedelta(minutes=10), timedelta(minutes=20, seconds=40)]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(a_total_minutes=nw.col("a").dt.total_minutes())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                            a  a_total_minutes
            0 0 days 00:10:00               10
            1 0 days 00:20:40               20
            >>> func(df_pl)
            shape: (2, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a            â”† a_total_minutes â”‚
            â”‚ ---          â”† ---             â”‚
            â”‚ duration[Î¼s] â”† i64             â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 10m          â”† 10              â”‚
            â”‚ 20m 40s      â”† 20              â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Útotal_minutesr&   r(   r   r   r)   L  r*   z5ExprDateTimeNamespace.total_minutes.<locals>.<lambda>rÄ   r(   r   r(   r   rõ   #  s    )z#ExprDateTimeNamespace.total_minutesc                   s   ˆ j  ‡ fdd„¡S )uë  
        Get total seconds.

        Notes:
            The function outputs the total seconds in the int dtype by default,
            however, pandas may change the dtype to float when there are missing values,
            consider using `fill_null()` and `cast` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = {"a": [timedelta(seconds=10), timedelta(seconds=20, milliseconds=40)]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(a_total_seconds=nw.col("a").dt.total_seconds())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                                   a  a_total_seconds
            0        0 days 00:00:10               10
            1 0 days 00:00:20.040000               20
            >>> func(df_pl)
            shape: (2, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a            â”† a_total_seconds â”‚
            â”‚ ---          â”† ---             â”‚
            â”‚ duration[Î¼s] â”† i64             â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 10s          â”† 10              â”‚
            â”‚ 20s 40ms     â”† 20              â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Útotal_secondsr&   r(   r   r   r)   w  r*   z5ExprDateTimeNamespace.total_seconds.<locals>.<lambda>rÄ   r(   r   r(   r   rö   N  s    )z#ExprDateTimeNamespace.total_secondsc                   s   ˆ j  ‡ fdd„¡S )uú  
        Get total milliseconds.

        Notes:
            The function outputs the total milliseconds in the int dtype by default,
            however, pandas may change the dtype to float when there are missing values,
            consider using `fill_null()` and `cast` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = {
            ...     "a": [
            ...         timedelta(milliseconds=10),
            ...         timedelta(milliseconds=20, microseconds=40),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         a_total_milliseconds=nw.col("a").dt.total_milliseconds()
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                                   a  a_total_milliseconds
            0 0 days 00:00:00.010000                    10
            1 0 days 00:00:00.020040                    20
            >>> func(df_pl)
            shape: (2, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a            â”† a_total_milliseconds â”‚
            â”‚ ---          â”† ---                  â”‚
            â”‚ duration[Î¼s] â”† i64                  â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 10ms         â”† 10                   â”‚
            â”‚ 20040Âµs      â”† 20                   â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Útotal_millisecondsr&   r(   r   r   r)   ª  r*   z:ExprDateTimeNamespace.total_milliseconds.<locals>.<lambda>rÄ   r(   r   r(   r   r÷   y  s    0
ÿz(ExprDateTimeNamespace.total_millisecondsc                   s   ˆ j  ‡ fdd„¡S )uû  
        Get total microseconds.

        Notes:
            The function outputs the total microseconds in the int dtype by default,
            however, pandas may change the dtype to float when there are missing values,
            consider using `fill_null()` and `cast` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = {
            ...     "a": [
            ...         timedelta(microseconds=10),
            ...         timedelta(milliseconds=1, microseconds=200),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         a_total_microseconds=nw.col("a").dt.total_microseconds()
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                                   a  a_total_microseconds
            0 0 days 00:00:00.000010                    10
            1 0 days 00:00:00.001200                  1200
            >>> func(df_pl)
            shape: (2, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a            â”† a_total_microseconds â”‚
            â”‚ ---          â”† ---                  â”‚
            â”‚ duration[Î¼s] â”† i64                  â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 10Âµs         â”† 10                   â”‚
            â”‚ 1200Âµs       â”† 1200                 â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Útotal_microsecondsr&   r(   r   r   r)   Þ  r*   z:ExprDateTimeNamespace.total_microseconds.<locals>.<lambda>rÄ   r(   r   r(   r   rø   ­  s    0
ÿz(ExprDateTimeNamespace.total_microsecondsc                   s   ˆ j  ‡ fdd„¡S )uJ	  
        Get total nanoseconds.

        Notes:
            The function outputs the total nanoseconds in the int dtype by default,
            however, pandas may change the dtype to float when there are missing values,
            consider using `fill_null()` and `cast` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = ["2024-01-01 00:00:00.000000001", "2024-01-01 00:00:00.000000002"]
            >>> df_pd = pd.DataFrame({"a": pd.to_datetime(data)})
            >>> df_pl = pl.DataFrame({"a": data}).with_columns(
            ...     pl.col("a").str.to_datetime(time_unit="ns")
            ... )

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         a_diff_total_nanoseconds=nw.col("a").diff().dt.total_nanoseconds()
            ...     )

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                                          a  a_diff_total_nanoseconds
            0 2024-01-01 00:00:00.000000001                       NaN
            1 2024-01-01 00:00:00.000000002                       1.0
            >>> func(df_pl)
            shape: (2, 2)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a                             â”† a_diff_total_nanoseconds â”‚
            â”‚ ---                           â”† ---                      â”‚
            â”‚ datetime[ns]                  â”† i64                      â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2024-01-01 00:00:00.000000001 â”† null                     â”‚
            â”‚ 2024-01-01 00:00:00.000000002 â”† 1                        â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   rµ   Útotal_nanosecondsr&   r(   r   r   r)     r*   z9ExprDateTimeNamespace.total_nanoseconds.<locals>.<lambda>rÄ   r(   r   r(   r   rù   á  s    -
ÿz'ExprDateTimeNamespace.total_nanosecondsr.   rã   c                   s   ˆj  ‡ ‡fdd„¡S )uh  
        Convert a Date/Time/Datetime column into a String column with the given format.

        Notes:
            Unfortunately, different libraries interpret format directives a bit
            differently.

            - Chrono, the library used by Polars, uses `"%.f"` for fractional seconds,
              whereas pandas and Python stdlib use `".%f"`.
            - PyArrow interprets `"%S"` as "seconds, including fractional seconds"
              whereas most other tools interpret it as "just seconds, as 2 digits".

            Therefore, we make the following adjustments:

            - for pandas-like libraries, we replace `"%S.%f"` with `"%S%.f"`.
            - for PyArrow, we replace `"%S.%f"` with `"%S"`.

            Workarounds like these don't make us happy, and we try to avoid them as
            much as possible, but here we feel like it's the best compromise.

            If you just want to format a date/datetime Series as a local datetime
            string, and have it work as consistently as possible across libraries,
            we suggest using:

            - `"%Y-%m-%dT%H:%M:%S%.f"` for datetimes
            - `"%Y-%m-%d"` for dates

            though note that, even then, different tools may return a different number
            of trailing zeros. Nonetheless, this is probably consistent enough for
            most applications.

            If you have an application where this is not enough, please open an issue
            and let us know.

        Examples:
            >>> from datetime import datetime
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = [
            ...     datetime(2020, 3, 1),
            ...     datetime(2020, 4, 1),
            ...     datetime(2020, 5, 1),
            ... ]
            >>> df_pd = pd.DataFrame({"a": data})
            >>> df_pl = pl.DataFrame({"a": data})

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").dt.to_string("%Y/%m/%d %H:%M:%S"))

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd)
                                 a
            0  2020/03/01 00:00:00
            1  2020/04/01 00:00:00
            2  2020/05/01 00:00:00

            >>> func(df_pl)
            shape: (3, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a                   â”‚
            â”‚ ---                 â”‚
            â”‚ str                 â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2020/03/01 00:00:00 â”‚
            â”‚ 2020/04/01 00:00:00 â”‚
            â”‚ 2020/05/01 00:00:00 â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        c                   s   ˆj  | ¡j ˆ ¡S r   )rÁ   r   rµ   Ú	to_stringr&   ræ   r   r   r)   ]  r*   z1ExprDateTimeNamespace.to_string.<locals>.<lambda>rÄ   rç   r   ræ   r   rú     s    JÿzExprDateTimeNamespace.to_stringrÏ   )r!   Ú	time_zoner   c                   s   ˆ j  ‡ ‡fdd„¡S )u  
        Replace time zone.

        Arguments:
            time_zone: Target time zone.

        Examples:
            >>> from datetime import datetime, timezone
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {
            ...     "a": [
            ...         datetime(2024, 1, 1, tzinfo=timezone.utc),
            ...         datetime(2024, 1, 2, tzinfo=timezone.utc),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").dt.replace_time_zone("Asia/Kathmandu"))

            We can then pass pandas / PyArrow / Polars / any other supported library:

            >>> func(df_pd)
                                      a
            0 2024-01-01 00:00:00+05:45
            1 2024-01-02 00:00:00+05:45
            >>> func(df_pl)
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a                            â”‚
            â”‚ ---                          â”‚
            â”‚ datetime[Î¼s, Asia/Kathmandu] â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2024-01-01 00:00:00 +0545    â”‚
            â”‚ 2024-01-02 00:00:00 +0545    â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: timestamp[us, tz=Asia/Kathmandu]
            ----
            a: [[2023-12-31 18:15:00.000000Z,2024-01-01 18:15:00.000000Z]]
        c                   s   ˆ j  | ¡j ˆ¡S r   )rÁ   r   rµ   Úreplace_time_zoner&   ©r!   rû   r   r   r)   ”  r*   z9ExprDateTimeNamespace.replace_time_zone.<locals>.<lambda>rÄ   rý   r   rý   r   rü   `  s    3ÿz'ExprDateTimeNamespace.replace_time_zonec                   s*   ˆdkrd}t |ƒ‚ˆ j ‡ ‡fdd„¡S )u	  
        Convert to a new time zone.

        If converting from a time-zone-naive column, then conversion happens
        as if converting from UTC.

        Arguments:
            time_zone: Target time zone.

        Examples:
            >>> from datetime import datetime, timezone
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {
            ...     "a": [
            ...         datetime(2024, 1, 1, tzinfo=timezone.utc),
            ...         datetime(2024, 1, 2, tzinfo=timezone.utc),
            ...     ]
            ... }
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("a").dt.convert_time_zone("Asia/Kathmandu"))

            We can then pass pandas / PyArrow / Polars / any other supported library:

            >>> func(df_pd)
                                      a
            0 2024-01-01 05:45:00+05:45
            1 2024-01-02 05:45:00+05:45
            >>> func(df_pl)
            shape: (2, 1)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ a                            â”‚
            â”‚ ---                          â”‚
            â”‚ datetime[Î¼s, Asia/Kathmandu] â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2024-01-01 05:45:00 +0545    â”‚
            â”‚ 2024-01-02 05:45:00 +0545    â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            a: timestamp[us, tz=Asia/Kathmandu]
            ----
            a: [[2024-01-01 00:00:00.000000Z,2024-01-02 00:00:00.000000Z]]
        Nz…Target `time_zone` cannot be `None` in `convert_time_zone`. Please use `replace_time_zone(None)` if you want to remove the time zone.c                   s   ˆ j  | ¡j ˆ¡S r   )rÁ   r   rµ   Úconvert_time_zoner&   rý   r   r   r)   Ñ  r*   z9ExprDateTimeNamespace.convert_time_zone.<locals>.<lambda>)Ú	TypeErrorrÁ   r,   )r!   rû   r€   r   rý   r   rþ   —  s    6ÿz'ExprDateTimeNamespace.convert_time_zoneÚuszLiteral[('ns', 'us', 'ms')])r!   Ú	time_unitr   c                   s2   ˆdkrdˆ›d}t |ƒ‚ˆ j ‡ ‡fdd„¡S )u×	  
        Return a timestamp in the given time unit.

        Arguments:
            time_unit: {'ns', 'us', 'ms'}
                Time unit.

        Examples:
            >>> from datetime import date
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> data = {"date": [date(2001, 1, 1), None, date(2001, 1, 3)]}
            >>> df_pd = pd.DataFrame(data, dtype="datetime64[ns]")
            >>> df_pl = pl.DataFrame(data)
            >>> df_pa = pa.table(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(
            ...         nw.col("date").dt.timestamp().alias("timestamp_us"),
            ...         nw.col("date").dt.timestamp("ms").alias("timestamp_ms"),
            ...     )

            We can then pass pandas / PyArrow / Polars / any other supported library:

            >>> func(df_pd)
                    date  timestamp_us  timestamp_ms
            0 2001-01-01  9.783072e+14  9.783072e+11
            1        NaT           NaN           NaN
            2 2001-01-03  9.784800e+14  9.784800e+11
            >>> func(df_pl)
            shape: (3, 3)
            â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
            â”‚ date       â”† timestamp_us    â”† timestamp_ms â”‚
            â”‚ ---        â”† ---             â”† ---          â”‚
            â”‚ date       â”† i64             â”† i64          â”‚
            â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
            â”‚ 2001-01-01 â”† 978307200000000 â”† 978307200000 â”‚
            â”‚ null       â”† null            â”† null         â”‚
            â”‚ 2001-01-03 â”† 978480000000000 â”† 978480000000 â”‚
            â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜
            >>> func(df_pa)
            pyarrow.Table
            date: date32[day]
            timestamp_us: int64
            timestamp_ms: int64
            ----
            date: [[2001-01-01,null,2001-01-03]]
            timestamp_us: [[978307200000000,null,978480000000000]]
            timestamp_ms: [[978307200000,null,978480000000]]
        >   r   ÚnsÚmsz=invalid `time_unit`

Expected one of {'ns', 'us', 'ms'}, got Ú.c                   s   ˆ j  | ¡j ˆ¡S r   )rÁ   r   rµ   Ú	timestampr&   ©r!   r  r   r   r)     r*   z1ExprDateTimeNamespace.timestamp.<locals>.<lambda>)Ú
ValueErrorrÁ   r,   )r!   r  r€   r   r  r   r  Ô  s    8
ÿÿzExprDateTimeNamespace.timestampN)r   )r¹   rº   r»   r"   rê   rë   rì   rí   rî   rï   rð   rñ   rò   ró   rô   rõ   rö   r÷   rø   rù   rú   rü   rþ   r  r   r   r   r   r´   
  s*   *034032333&++441N7=r´   c                   @  s„   e Zd Zddddœdd„Zdddœdd	„Zdd
ddœdd„Zddddœdd„Zddddœdd„Zdddœdd„Zdddœdd„Z	dS )r¸   r   r½   r   r¿   c                 C  s
   || _ d S r   rÀ   rÂ   r   r   r   r"     s    zExprNameNamespace.__init__r±   c                   s   ˆ j  ‡ fdd„¡S )aï  
        Keep the original root name of the expression.

        Notes:
            This will undo any previous renaming operations on the expression.
            Due to implementation constraints, this method can only be called as the last
            expression in a chain. Only one name operation per expression will work.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = {"foo": [1, 2], "BAR": [4, 5]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("foo").alias("alias_for_foo").name.keep())

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd).columns
            Index(['foo'], dtype='object')
            >>> func(df_pl).columns
            ['foo']
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   r/   Úkeepr&   r(   r   r   r)   9  r*   z(ExprNameNamespace.keep.<locals>.<lambda>rÄ   r(   r   r(   r   r    s    zExprNameNamespace.keepzCallable[[str], str])r!   r2   r   c                   s   ˆj  ‡ ‡fdd„¡S )a¸  
        Rename the output of an expression by mapping a function over the root name.

        Arguments:
            function: Function that maps a root name to a new name.

        Notes:
            This will undo any previous renaming operations on the expression.
            Due to implementation constraints, this method can only be called as the last
            expression in a chain. Only one name operation per expression will work.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = {"foo": [1, 2], "BAR": [4, 5]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> renaming_func = lambda s: s[::-1]  # reverse column name
            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.select(nw.col("foo", "BAR").name.map(renaming_func))

            We can then pass either pandas or Polars to `func`:

            >>> func(df_pd).columns
            Index(['oof', 'RAB'], dtype='object')
            >>> func(df_pl).columns
            ['oof', 'RAB']
        c                   s   ˆj  | ¡j ˆ ¡S r   )rÁ   r   r/   Úmapr&   ©r2   r!   r   r   r)   ]  r*   z'ExprNameNamespace.map.<locals>.<lambda>rÄ   )r!   r2   r   r
  r   r	  ;  s    "zExprNameNamespace.mapr.   rÓ   c                   s   ˆj  ‡ ‡fdd„¡S )aÐ  
        Add a prefix to the root column name of the expression.

        Arguments:
            prefix: Prefix to add to the root column name.

        Notes:
            This will undo any previous renaming operations on the expression.
            Due to implementation constraints, this method can only be called as the last
            expression in a chain. Only one name operation per expression will work.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = {"foo": [1, 2], "BAR": [4, 5]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def add_colname_prefix(df, prefix):
            ...     return df.select(nw.col("foo", "BAR").name.prefix(prefix))

            We can then pass either pandas or Polars to `func`:

            >>> add_colname_prefix(df_pd, "with_prefix_").columns
            Index(['with_prefix_foo', 'with_prefix_BAR'], dtype='object')

            >>> add_colname_prefix(df_pl, "with_prefix_").columns
            ['with_prefix_foo', 'with_prefix_BAR']
        c                   s   ˆj  | ¡j ˆ ¡S r   )rÁ   r   r/   rÔ   r&   rÖ   r   r   r)     r*   z*ExprNameNamespace.prefix.<locals>.<lambda>rÄ   r×   r   rÖ   r   rÔ   _  s    "zExprNameNamespace.prefixrØ   c                   s   ˆ j  ‡ ‡fdd„¡S )aÏ  
        Add a suffix to the root column name of the expression.

        Arguments:
            suffix: Suffix to add to the root column name.

        Notes:
            This will undo any previous renaming operations on the expression.
            Due to implementation constraints, this method can only be called as the last
            expression in a chain. Only one name operation per expression will work.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = {"foo": [1, 2], "BAR": [4, 5]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def add_colname_suffix(df, suffix):
            ...     return df.select(nw.col("foo", "BAR").name.suffix(suffix))

            We can then pass either pandas or Polars to `func`:

            >>> add_colname_suffix(df_pd, "_with_suffix").columns
            Index(['foo_with_suffix', 'BAR_with_suffix'], dtype='object')
            >>> add_colname_suffix(df_pl, "_with_suffix").columns
            ['foo_with_suffix', 'BAR_with_suffix']
        c                   s   ˆ j  | ¡j ˆ¡S r   )rÁ   r   r/   rÙ   r&   rÛ   r   r   r)   ¤  r*   z*ExprNameNamespace.suffix.<locals>.<lambda>rÄ   rÛ   r   rÛ   r   rÙ   ƒ  s    !zExprNameNamespace.suffixc                   s   ˆ j  ‡ fdd„¡S )a÷  
        Make the root column name lowercase.

        Notes:
            This will undo any previous renaming operations on the expression.
            Due to implementation constraints, this method can only be called as the last
            expression in a chain. Only one name operation per expression will work.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = {"foo": [1, 2], "BAR": [4, 5]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def to_lower(df):
            ...     return df.select(nw.col("foo", "BAR").name.to_lowercase())

            We can then pass either pandas or Polars to `func`:

            >>> to_lower(df_pd).columns
            Index(['foo', 'bar'], dtype='object')
            >>> to_lower(df_pl).columns
            ['foo', 'bar']
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   r/   ré   r&   r(   r   r   r)   Ä  r*   z0ExprNameNamespace.to_lowercase.<locals>.<lambda>rÄ   r(   r   r(   r   ré   ¦  s    zExprNameNamespace.to_lowercasec                   s   ˆ j  ‡ fdd„¡S )aö  
        Make the root column name uppercase.

        Notes:
            This will undo any previous renaming operations on the expression.
            Due to implementation constraints, this method can only be called as the last
            expression in a chain. Only one name operation per expression will work.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = {"foo": [1, 2], "BAR": [4, 5]}
            >>> df_pd = pd.DataFrame(data)
            >>> df_pl = pl.DataFrame(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def to_upper(df):
            ...     return df.select(nw.col("foo", "BAR").name.to_uppercase())

            We can then pass either pandas or Polars to `func`:
            >>> to_upper(df_pd).columns
            Index(['FOO', 'BAR'], dtype='object')
            >>> to_upper(df_pl).columns
            ['FOO', 'BAR']
        c                   s   ˆ j  | ¡j ¡ S r   )rÁ   r   r/   rè   r&   r(   r   r   r)   ã  r*   z0ExprNameNamespace.to_uppercase.<locals>.<lambda>rÄ   r(   r   r(   r   rè   Æ  s    zExprNameNamespace.to_uppercaseN)
r¹   rº   r»   r"   r  r	  rÔ   rÙ   ré   rè   r   r   r   r   r¸     s    $$# r¸   r˜   )Únamesr   c                    s   dddœ‡ fdd„}t |ƒS )u|  
    Creates an expression that references one or more columns by their name(s).

    Arguments:
        names: Name(s) of the columns to use in the aggregation function.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pl = pl.DataFrame({"a": [1, 2], "b": [3, 4]})
        >>> df_pd = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
        >>> df_pa = pa.table({"a": [1, 2], "b": [3, 4]})

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.col("a") * nw.col("b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           a
        0  3
        1  8
        >>> func(df_pl)
        shape: (2, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 3   â”‚
        â”‚ 8   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        ----
        a: [[3,8]]
    r   ©r'   r   c                   s   | j tˆ ƒŽ S r   )Úcolr   r&   ©r  r   r   Úfunc  s    zcol.<locals>.func©r   )r  r  r   r  r   r  æ  s    -r  zint | Sequence[int])Úindicesr   c                    s   dddœ‡ fdd„}t |ƒS )uç  
    Creates an expression that references one or more columns by their index(es).

    Notes:
        `nth` is not supported for Polars version<1.0.0. Please use [`col`](/api-reference/narwhals/#narwhals.col) instead.

    Arguments:
        indices: One or more indices representing the columns to retrieve.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> data = {"a": [1, 2], "b": [3, 4]}
        >>> df_pl = pl.DataFrame(data)
        >>> df_pd = pd.DataFrame(data)
        >>> df_pa = pa.table(data)

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.nth(0) * 2)

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           a
        0  2
        1  4
        >>> func(df_pl)
        shape: (2, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 2   â”‚
        â”‚ 4   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        ----
        a: [[2,4]]
    r   r  c                   s   | j tˆ ƒŽ S r   )Únthr   r&   ©r  r   r   r  J  s    znth.<locals>.funcr  )r  r  r   r  r   r    s    1r  r#   c                   C  s   t dd„ ƒS )uÓ  
    Instantiate an expression representing all columns.

    Examples:
        >>> import polars as pl
        >>> import pandas as pd
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pd = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
        >>> df_pl = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
        >>> df_pa = pa.table({"a": [1, 2, 3], "b": [4, 5, 6]})

        Let's define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.all() * 2)

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           a   b
        0  2   8
        1  4  10
        2  6  12
        >>> func(df_pl)
        shape: (3, 2)
        â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
        â”‚ a   â”† b   â”‚
        â”‚ --- â”† --- â”‚
        â”‚ i64 â”† i64 â”‚
        â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
        â”‚ 2   â”† 8   â”‚
        â”‚ 4   â”† 10  â”‚
        â”‚ 6   â”† 12  â”‚
        â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        b: int64
        ----
        a: [[2,4,6]]
        b: [[8,10,12]]
    c                 S  s   |   ¡ S r   )rV   r&   r   r   r   r)   ~  r*   zall_.<locals>.<lambda>r  r   r   r   r   Úall_Q  s    -r  c                  C  s   dddœdd„} t | ƒS )uË  
    Return the number of rows.

    Examples:
        >>> import polars as pl
        >>> import pandas as pd
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pd = pd.DataFrame({"a": [1, 2], "b": [5, 10]})
        >>> df_pl = pl.DataFrame({"a": [1, 2], "b": [5, 10]})
        >>> df_pa = pa.table({"a": [1, 2], "b": [5, 10]})

        Let's define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.len())

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           len
        0    2
        >>> func(df_pl)
        shape: (1, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ len â”‚
        â”‚ --- â”‚
        â”‚ u32 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 2   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        len: int64
        ----
        len: [[2]]
    r   r  c                 S  s   |   ¡ S r   )r«   r&   r   r   r   r  ª  s    zlen_.<locals>.funcr  )r  r   r   r   Úlen_‚  s    (r  r.   )Úcolumnsr   c                    s   t ‡ fdd„ƒS )u*  
    Sum all values.

    Note:
        Syntactic sugar for ``nw.col(columns).sum()``

    Arguments:
        columns: Name(s) of the columns to use in the aggregation function

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pl = pl.DataFrame({"a": [1, 2]})
        >>> df_pd = pd.DataFrame({"a": [1, 2]})
        >>> df_pa = pa.table({"a": [1, 2]})

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.sum("a"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           a
        0  3
        >>> func(df_pl)
        shape: (1, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 3   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        ----
        a: [[3]]
    c                   s
   | j ˆ Ž S r   )r%   r&   ©r  r   r   r)   Þ  r*   zsum.<locals>.<lambda>r  r  r   r  r   r%   °  s    .r%   c                    s   t ‡ fdd„ƒS )u>  
    Get the mean value.

    Note:
        Syntactic sugar for ``nw.col(columns).mean()``

    Arguments:
        columns: Name(s) of the columns to use in the aggregation function

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pl = pl.DataFrame({"a": [1, 8, 3]})
        >>> df_pd = pd.DataFrame({"a": [1, 8, 3]})
        >>> df_pa = pa.table({"a": [1, 8, 3]})

        We define a dataframe agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.mean("a"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
             a
        0  4.0
        >>> func(df_pl)
        shape: (1, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ f64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 4.0 â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: double
        ----
        a: [[4]]
    c                   s
   | j ˆ Ž S r   )rW   r&   r  r   r   r)     r*   zmean.<locals>.<lambda>r  r  r   r  r   rW   á  s    .rW   c                    s   t ‡ fdd„ƒS )ub  
    Return the minimum value.

    Note:
       Syntactic sugar for ``nw.col(columns).min()``.

    Arguments:
        columns: Name(s) of the columns to use in the aggregation function.

    Examples:
        >>> import polars as pl
        >>> import pandas as pd
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pd = pd.DataFrame({"a": [1, 2], "b": [5, 10]})
        >>> df_pl = pl.DataFrame({"a": [1, 2], "b": [5, 10]})
        >>> df_pa = pa.table({"a": [1, 2], "b": [5, 10]})

        Let's define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.min("b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           b
        0  5
        >>> func(df_pl)
        shape: (1, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ b   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 5   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        b: int64
        ----
        b: [[5]]
    c                   s
   | j ˆ Ž S r   )r^   r&   r  r   r   r)   ?  r*   zmin.<locals>.<lambda>r  r  r   r  r   r^     s    -r^   c                    s   t ‡ fdd„ƒS )ub  
    Return the maximum value.

    Note:
       Syntactic sugar for ``nw.col(columns).max()``.

    Arguments:
        columns: Name(s) of the columns to use in the aggregation function.

    Examples:
        >>> import polars as pl
        >>> import pandas as pd
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pd = pd.DataFrame({"a": [1, 2], "b": [5, 10]})
        >>> df_pl = pl.DataFrame({"a": [1, 2], "b": [5, 10]})
        >>> df_pa = pa.table({"a": [1, 2], "b": [5, 10]})

        Let's define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.max("a"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           a
        0  2
        >>> func(df_pl)
        shape: (1, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 2   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        ----
        a: [[2]]
    c                   s
   | j ˆ Ž S r   )r_   r&   r  r   r   r)   o  r*   zmax.<locals>.<lambda>r  r  r   r  r   r_   B  s    -r_   úIntoExpr | Iterable[IntoExpr])Úexprsr   c                    s    ˆ sd}t |ƒ‚t‡ fdd„ƒS )u  
    Sum all values horizontally across columns.

    Warning:
        Unlike Polars, we support horizontal sum over numeric columns only.

    Arguments:
        exprs: Name(s) of the columns to use in the aggregation function. Accepts
            expression input.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> data = {"a": [1, 2, 3], "b": [5, 10, None]}
        >>> df_pl = pl.DataFrame(data)
        >>> df_pd = pd.DataFrame(data)
        >>> df_pa = pa.table(data)

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.sum_horizontal("a", "b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
              a
        0   6.0
        1  12.0
        2   3.0
        >>> func(df_pl)
        shape: (3, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 6   â”‚
        â”‚ 12  â”‚
        â”‚ 3   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        ----
        a: [[6,12,3]]
    z:At least one expression must be passed to `sum_horizontal`c                   s   ˆ j ‡ fdd„tˆƒD ƒŽ S )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   ©r„   Úvr&   r   r   r†   ª  s     z4sum_horizontal.<locals>.<lambda>.<locals>.<listcomp>)Úsum_horizontalr   r&   ©r  r&   r   r)   ©  s   ÿz sum_horizontal.<locals>.<lambda>©r  r   ©r  r€   r   r  r   r  r  s    3
ÿr  c                    s    ˆ sd}t |ƒ‚t‡ fdd„ƒS )u=  
    Get the minimum value horizontally across columns.

    Notes:
        We support `min_horizontal` over numeric columns only.

    Arguments:
        exprs: Name(s) of the columns to use in the aggregation function. Accepts
            expression input.

    Examples:
        >>> import narwhals as nw
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> data = {
        ...     "a": [1, 8, 3],
        ...     "b": [4, 5, None],
        ...     "c": ["x", "y", "z"],
        ... }

        We define a dataframe-agnostic function that computes the horizontal min of "a"
        and "b" columns:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.min_horizontal("a", "b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(pd.DataFrame(data))
             a
        0  1.0
        1  5.0
        2  3.0
        >>> func(pl.DataFrame(data))
        shape: (3, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 1   â”‚
        â”‚ 5   â”‚
        â”‚ 3   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(pa.table(data))
        pyarrow.Table
        a: int64
        ----
        a: [[1,5,3]]
    z:At least one expression must be passed to `min_horizontal`c                   s   ˆ j ‡ fdd„tˆƒD ƒŽ S )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   é  s     z4min_horizontal.<locals>.<lambda>.<locals>.<listcomp>)Úmin_horizontalr   r&   r  r&   r   r)   è  s   ÿz min_horizontal.<locals>.<lambda>r  r  r   r  r   r   ¯  s    5
ÿr   c                    s    ˆ sd}t |ƒ‚t‡ fdd„ƒS )u=  
    Get the maximum value horizontally across columns.

    Notes:
        We support `max_horizontal` over numeric columns only.

    Arguments:
        exprs: Name(s) of the columns to use in the aggregation function. Accepts
            expression input.

    Examples:
        >>> import narwhals as nw
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> data = {
        ...     "a": [1, 8, 3],
        ...     "b": [4, 5, None],
        ...     "c": ["x", "y", "z"],
        ... }

        We define a dataframe-agnostic function that computes the horizontal max of "a"
        and "b" columns:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.max_horizontal("a", "b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(pd.DataFrame(data))
             a
        0  4.0
        1  8.0
        2  3.0
        >>> func(pl.DataFrame(data))
        shape: (3, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ i64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 4   â”‚
        â”‚ 8   â”‚
        â”‚ 3   â”‚
        â””â”€â”€â”€â”€â”€â”˜
        >>> func(pa.table(data))
        pyarrow.Table
        a: int64
        ----
        a: [[4,8,3]]
    z:At least one expression must be passed to `max_horizontal`c                   s   ˆ j ‡ fdd„tˆƒD ƒŽ S )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   (  s     z4max_horizontal.<locals>.<lambda>.<locals>.<listcomp>)Úmax_horizontalr   r&   r  r&   r   r)   '  s   ÿz max_horizontal.<locals>.<lambda>r  r  r   r  r   r!  î  s    5
ÿr!  c                   @  s<   e Zd Zdddœdd„Zdddœdd	„Zdd
dœdd„ZdS )ÚWhenr  r   r   c                 G  s   t |gƒ| _d S r   )r   Ú_predicatesr‰   r   r   r   r"   .  s    zWhen.__init__r   r  c                   s   ‡ fdd„| j D ƒS )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   2  s     z,When._extract_predicates.<locals>.<listcomp>)r#  )r!   r'   r   r&   r   Ú_extract_predicates1  s    zWhen._extract_predicatesÚThenrŒ   c                   s   t ‡ ‡fdd„ƒS )Nc                   s   | j ˆ  | ¡Ž  t| ˆƒ¡S r   )Úwhenr$  Úthenr   r&   r   r   r   r)   6  s   ÿzWhen.then.<locals>.<lambda>)r%  r   r   r   r   r'  4  s    ÿz	When.thenN)r¹   rº   r»   r"   r$  r'  r   r   r   r   r"  -  s   r"  c                   @  s,   e Zd Zdddœdd„Zdddœd	d
„ZdS )r%  r   r   r   c                 C  s
   || _ d S r   r   r    r   r   r   r"   =  s    zThen.__init__r   r   rŒ   c                   s   t ‡ ‡fdd„ƒS )Nc                   s   ˆ   | ¡ t| ˆƒ¡S r   )r   Ú	otherwiser   r&   r   r   r   r)   A  r*   z Then.otherwise.<locals>.<lambda>r  r   r   r   r   r(  @  s    zThen.otherwiseN)r¹   rº   r»   r"   r(  r   r   r   r   r%  <  s   r%  r   c                  G  s   t | Ž S )ui	  
    Start a `when-then-otherwise` expression.

    Expression similar to an `if-else` statement in Python. Always initiated by a `pl.when(<condition>).then(<value if condition>)`., and optionally followed by chaining one or more `.when(<condition>).then(<value>)` statements.
    Chained when-then operations should be read as Python `if, elif, ... elif` blocks, not as `if, if, ... if`, i.e. the first condition that evaluates to `True` will be picked.
    If none of the conditions are `True`, an optional `.otherwise(<value if all statements are false>)` can be appended at the end. If not appended, and none of the conditions are `True`, `None` will be returned.

    Arguments:
        predicates: Condition(s) that must be met in order to apply the subsequent statement. Accepts one or more boolean expressions, which are implicitly combined with `&`. String input is parsed as a column name.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pl = pl.DataFrame({"a": [1, 2, 3], "b": [5, 10, 15]})
        >>> df_pd = pd.DataFrame({"a": [1, 2, 3], "b": [5, 10, 15]})
        >>> df_pa = pa.table({"a": [1, 2, 3], "b": [5, 10, 15]})

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df_any):
        ...     return df_any.with_columns(
        ...         nw.when(nw.col("a") < 3).then(5).otherwise(6).alias("a_when")
        ...     )

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           a   b  a_when
        0  1   5       5
        1  2  10       5
        2  3  15       6
        >>> func(df_pl)
        shape: (3, 3)
        â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”
        â”‚ a   â”† b   â”† a_when â”‚
        â”‚ --- â”† --- â”† ---    â”‚
        â”‚ i64 â”† i64 â”† i32    â”‚
        â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•¡
        â”‚ 1   â”† 5   â”† 5      â”‚
        â”‚ 2   â”† 10  â”† 5      â”‚
        â”‚ 3   â”† 15  â”† 6      â”‚
        â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        b: int64
        a_when: int64
        ----
        a: [[1,2,3]]
        b: [[5,10,15]]
        a_when: [[5,5,6]]
    )r"  )r‚   r   r   r   r&  D  s    8r&  c                    s    ˆ sd}t |ƒ‚t‡ fdd„ƒS )u:  
    Compute the bitwise AND horizontally across columns.

    Arguments:
        exprs: Name(s) of the columns to use in the aggregation function. Accepts expression input.

    Notes:
        pandas and Polars handle null values differently.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> data = {
        ...     "a": [False, False, True, True, False, None],
        ...     "b": [False, True, True, None, None, None],
        ... }
        >>> df_pl = pl.DataFrame(data)
        >>> df_pd = pd.DataFrame(data)
        >>> df_pa = pa.table(data)

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select("a", "b", all=nw.all_horizontal("a", "b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
               a      b    all
        0  False  False  False
        1  False   True  False
        2   True   True   True
        3   True   None  False
        4  False   None  False
        5   None   None  False

        >>> func(df_pl)
        shape: (6, 3)
        â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
        â”‚ a     â”† b     â”† all   â”‚
        â”‚ ---   â”† ---   â”† ---   â”‚
        â”‚ bool  â”† bool  â”† bool  â”‚
        â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
        â”‚ false â”† false â”† false â”‚
        â”‚ false â”† true  â”† false â”‚
        â”‚ true  â”† true  â”† true  â”‚
        â”‚ true  â”† null  â”† null  â”‚
        â”‚ false â”† null  â”† false â”‚
        â”‚ null  â”† null  â”† null  â”‚
        â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜

        >>> func(df_pa)
        pyarrow.Table
        a: bool
        b: bool
        all: bool
        ----
        a: [[false,false,true,true,false,null]]
        b: [[false,true,true,null,null,null]]
        all: [[false,false,true,null,false,null]]
    z:At least one expression must be passed to `all_horizontal`c                   s   ˆ j ‡ fdd„tˆƒD ƒŽ S )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   Å  s     z4all_horizontal.<locals>.<lambda>.<locals>.<listcomp>)Úall_horizontalr   r&   r  r&   r   r)   Ä  s   ÿz all_horizontal.<locals>.<lambda>r  r  r   r  r   r)    s    A
ÿr)  NzDType | None)r   r6   r   c                   sF   t ˆƒrd}t|ƒ‚tˆttfƒr4dˆ› }t|ƒ‚t‡ ‡fdd„ƒS )u  
    Return an expression representing a literal value.

    Arguments:
        value: The value to use as literal.
        dtype: The data type of the literal value. If not provided, the data type will be inferred.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> df_pl = pl.DataFrame({"a": [1, 2]})
        >>> df_pd = pd.DataFrame({"a": [1, 2]})
        >>> df_pa = pa.table({"a": [1, 2]})

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.with_columns(nw.lit(3).alias("b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
           a  b
        0  1  3
        1  2  3
        >>> func(df_pl)
        shape: (2, 2)
        â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
        â”‚ a   â”† b   â”‚
        â”‚ --- â”† --- â”‚
        â”‚ i64 â”† i32 â”‚
        â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
        â”‚ 1   â”† 3   â”‚
        â”‚ 2   â”† 3   â”‚
        â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
        >>> func(df_pa)
        pyarrow.Table
        a: int64
        b: int64
        ----
        a: [[1,2]]
        b: [[3,3]]
    zvnumpy arrays are not supported as literal values. Consider using `with_columns` to create a new column from the array.z,Nested datatypes are not supported yet. Got c                   s   |   ˆˆ ¡S r   )Úlitr&   ©r6   r   r   r   r)     r*   zlit.<locals>.<lambda>)r   r  r   ÚlistÚtupler   r   )r   r6   r€   r   r+  r   r*  Ê  s    /ÿ
r*  c                    s    ˆ sd}t |ƒ‚t‡ fdd„ƒS )u7  
    Compute the bitwise OR horizontally across columns.

    Arguments:
        exprs: Name(s) of the columns to use in the aggregation function. Accepts expression input.

    Notes:
        pandas and Polars handle null values differently.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> data = {
        ...     "a": [False, False, True, True, False, None],
        ...     "b": [False, True, True, None, None, None],
        ... }
        >>> df_pl = pl.DataFrame(data)
        >>> df_pd = pd.DataFrame(data)
        >>> df_pa = pa.table(data)

        We define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select("a", "b", any=nw.any_horizontal("a", "b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
               a      b    any
        0  False  False  False
        1  False   True   True
        2   True   True   True
        3   True   None   True
        4  False   None  False
        5   None   None  False

        >>> func(df_pl)
        shape: (6, 3)
        â”Œâ”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
        â”‚ a     â”† b     â”† any   â”‚
        â”‚ ---   â”† ---   â”† ---   â”‚
        â”‚ bool  â”† bool  â”† bool  â”‚
        â•žâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
        â”‚ false â”† false â”† false â”‚
        â”‚ false â”† true  â”† true  â”‚
        â”‚ true  â”† true  â”† true  â”‚
        â”‚ true  â”† null  â”† true  â”‚
        â”‚ false â”† null  â”† null  â”‚
        â”‚ null  â”† null  â”† null  â”‚
        â””â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜

        >>> func(df_pa)
        pyarrow.Table
        a: bool
        b: bool
        any: bool
        ----
        a: [[false,false,true,true,false,null]]
        b: [[false,true,true,null,null,null]]
        any: [[false,true,true,true,null,null]]
    z:At least one expression must be passed to `any_horizontal`c                   s   ˆ j ‡ fdd„tˆƒD ƒŽ S )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   M  s     z4any_horizontal.<locals>.<lambda>.<locals>.<listcomp>)Úany_horizontalr   r&   r  r&   r   r)   L  s   ÿz any_horizontal.<locals>.<lambda>r  r  r   r  r   r.    s    A
ÿr.  c                    s    ˆ sd}t |ƒ‚t‡ fdd„ƒS )uR  
    Compute the mean of all values horizontally across columns.

    Arguments:
        exprs: Name(s) of the columns to use in the aggregation function. Accepts
            expression input.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> data = {
        ...     "a": [1, 8, 3],
        ...     "b": [4, 5, None],
        ...     "c": ["x", "y", "z"],
        ... }
        >>> df_pl = pl.DataFrame(data)
        >>> df_pd = pd.DataFrame(data)
        >>> df_pa = pa.table(data)

        We define a dataframe-agnostic function that computes the horizontal mean of "a"
        and "b" columns:

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(nw.mean_horizontal("a", "b"))

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(df_pd)
             a
        0  2.5
        1  6.5
        2  3.0

        >>> func(df_pl)
        shape: (3, 1)
        â”Œâ”€â”€â”€â”€â”€â”
        â”‚ a   â”‚
        â”‚ --- â”‚
        â”‚ f64 â”‚
        â•žâ•â•â•â•â•â•¡
        â”‚ 2.5 â”‚
        â”‚ 6.5 â”‚
        â”‚ 3.0 â”‚
        â””â”€â”€â”€â”€â”€â”˜

        >>> func(df_pa)
        pyarrow.Table
        a: double
        ----
        a: [[2.5,6.5,3]]
    z;At least one expression must be passed to `mean_horizontal`c                   s   ˆ j ‡ fdd„tˆƒD ƒŽ S )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   Ž  s     z5mean_horizontal.<locals>.<lambda>.<locals>.<listcomp>)Úmean_horizontalr   r&   r  r&   r   r)     s   ÿz!mean_horizontal.<locals>.<lambda>r  r  r   r  r   r/  R  s    7
ÿr/  Ú F©Ú	separatorÚignore_nullsr   rd   )r  Ú
more_exprsr2  r3  r   c                  s   t ‡ ‡‡‡fdd„ƒS )uS	  
    Horizontally concatenate columns into a single string column.

    Arguments:
        exprs: Columns to concatenate into a single string column. Accepts expression
            input. Strings are parsed as column names, other non-expression inputs are
            parsed as literals. Non-`String` columns are cast to `String`.
        *more_exprs: Additional columns to concatenate into a single string column,
            specified as positional arguments.
        separator: String that will be used to separate the values of each column.
        ignore_nulls: Ignore null values (default is `False`).
            If set to `False`, null values will be propagated and if the row contains any
            null values, the output is null.

    Examples:
        >>> import narwhals as nw
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> data = {
        ...     "a": [1, 2, 3],
        ...     "b": ["dogs", "cats", None],
        ...     "c": ["play", "swim", "walk"],
        ... }

        We define a dataframe-agnostic function that computes the horizontal string
        concatenation of different columns

        >>> @nw.narwhalify
        ... def func(df):
        ...     return df.select(
        ...         nw.concat_str(
        ...             [
        ...                 nw.col("a") * 2,
        ...                 nw.col("b"),
        ...                 nw.col("c"),
        ...             ],
        ...             separator=" ",
        ...         ).alias("full_sentence")
        ...     )

        We can pass any supported library such as Pandas, Polars, or PyArrow to `func`:

        >>> func(pd.DataFrame(data))
          full_sentence
        0   2 dogs play
        1   4 cats swim
        2          None

        >>> func(pl.DataFrame(data))
        shape: (3, 1)
        â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
        â”‚ full_sentence â”‚
        â”‚ ---           â”‚
        â”‚ str           â”‚
        â•žâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡
        â”‚ 2 dogs play   â”‚
        â”‚ 4 cats swim   â”‚
        â”‚ null          â”‚
        â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜

        >>> func(pa.table(data))
        pyarrow.Table
        full_sentence: string
        ----
        full_sentence: [["2 dogs play","4 cats swim",null]]
    c                   s:   ˆ j ‡ fdd„tˆgƒD ƒf‡ fdd„ˆD ƒžˆˆdœŽS )Nc                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   Þ  s     z0concat_str.<locals>.<lambda>.<locals>.<listcomp>c                   s   g | ]}t ˆ |ƒ‘qS r   rƒ   r  r&   r   r   r†   ß  s     r1  )Ú
concat_strr   r&   ©r  r3  r4  r2  r&   r   r)   Ý  s   ÿþüzconcat_str.<locals>.<lambda>r  )r  r2  r3  r4  r   r6  r   r5  “  s    Iÿr5  )N)0Ú
__future__r   Útypingr   r   r   r   r   r   r	   r
   Znarwhals.dependenciesr   Znarwhals.utilsr   Ztyping_extensionsr   Znarwhals.dtypesr   Znarwhals.typingr   r   r   r½   r¶   r³   r´   r¸   r  r  r  r  r%   rW   r^   r_   r  r   r!  r"  r%  r&  r)  r*  r.  r/  r5  Ú__all__r   r   r   r   Ú<module>   s–   
                  W/    w         P381.1100=??;K=KDüTÿ