U
     )3g                    @  s*  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rd dlmZ d dlZd dlZd dlZd dlmZ d dlmZ d dlm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 dS )    )annotations)TYPE_CHECKING)Any)Callable)Generic)Iterator)Literal)Sequence)TypeVar)overload)parse_version)
ModuleTypeN)Self	DataFrame)DTypec                	   @  s  e Zd ZdZeddddZdddd	d
ddZddddddddZeddddddZ	e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#d$Zddd%d&Zd'ddd(d)d*Zed+dd,d-Zddd.d/d0Zddd1d2d3Zd4dddd5d6d7Zd8dd9d:Zddd;d<Zddd=d>Zedd?dd@dAZed8ddBdCZddDddEdFdGZdHddIdJZdKddLdMZdddNdOZdddPdQZdddRdSZdddTdUZdddVdWZdddXdYZdddZd[Z d\d]ddd^d_d`Z!ddadaddbdcddZ"dddedfdgZ#dddhdiZ$dddjdkZ%dddldmZ&dddndoZ'dpdqdrddsdtduZ(dddvdwZ)dddxdydzZ*dddpdd{dd|d}drd|dd~ddZ+d8ddddZ,d8ddddZ-dddDddddZ.dpdpddrdrddddZ/ddddZ0dddddZ1dddd8ddddZ2ddddZ3ddddZ4ddddZ5d!ddeddZ6d!ddeddZ7d!ddeddZ8d!ddeddZ9d!ddeddZ:d!ddeddZ;d!ddeddZ<d!ddeddZ=d!ddeddZ>d!ddeddZ?d!ddeddZ@d!ddeddZAd!ddeddZBd!ddeddZCd!ddeddZDd!ddeddZEdddeddZFdddeddZGdddeddÄZHdddeddńZIdddeddǄZJdddeddɄZKdddd˄ZLdddedd̈́ZMdddddτZNddrdddфZOdddddӄZPdddddՄZQdddddׄZRdddddلZSdpdڜddrdrdۜdd݄ZTdpdpddpdޜddrdrddrdHdddZUddddddZVdddddddZWddd|ddddZXdddddddZYdddddddZZdddddddZ[ddpddd8drdHdddZ\ddddddddZ]dd dddZ^dddddZ_dddddZ`edddd	d
ZaedddddZbedddddZcdS (  Seriesa  
    Narwhals Series, backed by a native series.

    The native series might be pandas.Series, polars.Series, ...

    This class is not meant to be instantiated directly - instead, use
    `narwhals.from_native`, making sure to pass `allow_series=True` or
    `series_only=True`.
    ztype[DataFrame[Any]]returnc                 C  s   ddl m} |S )Nr   r   )narwhals.dataframer   )selfr    r   3/tmp/pip-unpacked-wheel-hfsjijke/narwhals/series.py
_dataframe&   s    zSeries._dataframer   r   z Literal[('full', 'interchange')]None)r   serieslevelr   c                C  s8   || _ t|dr| | _ndt| d}t|d S )N__narwhals_series__zQExpected Polars Series or an object which implements `__narwhals_series__`, got: .)_levelhasattrr   _compliant_seriestypeAssertionError)r   r   r   msgr   r   r   __init__,   s
    
zSeries.__init__Nzbool | Nonez
np.ndarray)r   dtypecopyr   c                 C  s   | j j||dS )N)r&   r'   )r!   	__array__)r   r&   r'   r   r   r   r(   9   s    zSeries.__array__int)r   idxr   c                 C  s   d S Nr   r   r*   r   r   r   __getitem__<   s    zSeries.__getitem__zslice | Sequence[int]c                 C  s   d S r+   r   r,   r   r   r   r-   ?   s    zint | slice | Sequence[int]z
Any | Selfc                 C  s$   t |tr| j| S | | j| S r+   )
isinstancer)   r!   _from_compliant_seriesr,   r   r   r   r-   B   s    

r   r   r   c                 C  s
   | j  S r+   )r!   __native_namespace__r   r   r   r   r1   G   s    zSeries.__native_namespace__zobject | Noneobject)requested_schemar   c              
   C  s   | j j}t|dr|j|dS zddl}W n: tk
rd } zdt| }t||W 5 d}~X Y nX t|jdk rdt| }t||	| 
 g}|j|dS )a  
        Export a Series via the Arrow PyCapsule Interface.

        Narwhals doesn't implement anything itself here:

        - if the underlying series implements the interface, it'll return that
        - else, it'll call `to_arrow` and then defer to PyArrow's implementation

        See [PyCapsule Interface](https://arrow.apache.org/docs/dev/format/CDataInterface/PyCapsuleInterface.html)
        for more.
        __arrow_c_stream__)r4   r   NzOPyArrow>=16.0.0 is required for `Series.__arrow_c_stream__` for object of type )   r   )r!   _native_seriesr    r5   pyarrowModuleNotFoundErrorr"   r   __version__Zchunked_arrayto_arrow)r   r4   Znative_seriespaexcr$   car   r   r   r5   J   s    
zSeries.__arrow_c_stream__c                 C  s   | j jS )au  
        Convert Narwhals series to native series.

        Returns:
            Series of class that user started with.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.to_native()

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

            >>> func(s_pd)
            0    1
            1    2
            2    3
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
                1
                2
                3
            ]
        )r!   r7   r2   r   r   r   	to_natived   s    %zSeries.to_nativezint | Sequence[int])indicesvaluesr   c                 C  s   |  | j|| |S )uK  
        Set value(s) at given position(s).

        Arguments:
            indices: Position(s) to set items at.
            values: Values to set.

        Note:
            This method always returns a new Series, without modifying the original one.
            Using this function in a for-loop is an anti-pattern, we recommend building
            up your positions and values beforehand and doing an update in one go.

            For example, instead of

            ```python
            for i in [1, 3, 2]:
                value = some_function(i)
                s = s.scatter(i, value)
            ```

            prefer

            ```python
            positions = [1, 3, 2]
            values = [some_function(x) for x in positions]
            s = s.scatter(positions, values)
            ```

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

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(df):
            ...     return df.with_columns(df["a"].scatter([0, 1], [999, 888]))

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

            >>> func(df_pd)
                 a  b
            0  999  4
            1  888  5
            2    3  6
            >>> func(df_pl)
            shape: (3, 2)
            ┌─────┬─────┐
            │ a   ┆ b   │
            │ --- ┆ --- │
            │ i64 ┆ i64 │
            ╞═════╪═════╡
            │ 999 ┆ 4   │
            │ 888 ┆ 5   │
            │ 3   ┆ 6   │
            └─────┴─────┘
        )r/   r!   scatter_extract_native)r   r@   rA   r   r   r   rB      s    >zSeries.scatterz
tuple[int]c                 C  s   | j jS )aC  
        Get the shape of the Series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.shape

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

            >>> func(s_pd)
            (3,)
            >>> func(s_pl)
            (3,)
        )r!   shaper2   r   r   r   rD      s    zSeries.shape)argr   c                 C  s    ddl m} t||r|jS |S )Nr   )r   )Znarwhals.seriesr   r.   r!   )r   rE   r   r   r   r   rC      s    
zSeries._extract_native)r   r   c                 C  s   | j || jdS )Nr   )	__class__r   r   r   r   r   r   r/      s    zSeries._from_compliant_serieszCallable[[Any], Self])functionargskwargsr   c                 O  s   || f||S )a!  
        Pipe function call.

        Examples:
            >>> import polars as pl
            >>> import pandas as pd
            >>> import narwhals as nw
            >>> s_pd = pd.Series([1, 2, 3, 4])
            >>> s_pl = pl.Series([1, 2, 3, 4])

            Lets define a function to pipe into
            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.pipe(lambda x: x + 2)

            Now apply it to the series

            >>> func(s_pd)
            0    3
            1    4
            2    5
            3    6
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [i64]
            [
               3
               4
               5
               6
            ]


        r   )r   rI   rJ   rK   r   r   r   pipe   s    $zSeries.pipestrc                 C  s<   d}t |}dd|  d d| d d d d|  d	 S )
Nz) Narwhals Series                         u   ┌u   ─u   ┐
|z|
z,| Use `.to_native()` to see native output |
u   └u   ┘)len)r   headerlengthr   r   r   __repr__  s$    
zSeries.__repr__c                 C  s
   t | jS r+   rO   r!   r2   r   r   r   __len__*  s    zSeries.__len__c                 C  s
   t | jS )a  
        Return the number of elements in the Series.

        Null values count towards the total.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = [1, 2, None]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            Let's define a dataframe-agnostic function that computes the len of the series:

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

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

            >>> func(s_pd)
            3
            >>> func(s_pl)
            3
        rS   r2   r   r   r   rO   -  s    z
Series.lenr   c                 C  s   | j jS )aI  
        Get the data type of the Series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dtype

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

            >>> func(s_pd)
            Int64
            >>> func(s_pl)
            Int64
        )r!   r&   r2   r   r   r   r&   J  s    zSeries.dtypec                 C  s   | j jS )aV  
        Get the name of the Series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s, name="foo")
            >>> s_pl = pl.Series("foo", s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.name

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

            >>> func(s_pd)
            'foo'
            >>> func(s_pl)
            'foo'
        )r!   namer2   r   r   r   rU   f  s    zSeries.namezDType | type[DType])r   r&   r   c                 C  s   |  | j|S )a~  
        Cast between data types.

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

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [True, False, True]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.cast(nw.Int64)

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

            >>> func(s_pd)
            0    1
            1    0
            2    1
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               1
               0
               1
            ]
        )r/   r!   cast)r   r&   r   r   r   rV     s    %zSeries.castzDataFrame[Any]c                 C  s   | j | j | jdS )u  
        Convert to dataframe.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s, name="a")
            >>> s_pl = pl.Series("a", s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.to_frame()

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

            >>> func(s_pd)
               a
            0  1
            1  2
            2  3
            >>> func(s_pl)
            shape: (3, 1)
            ┌─────┐
            │ a   │
            │ --- │
            │ i64 │
            ╞═════╡
            │ 1   │
            │ 2   │
            │ 3   │
            └─────┘
        rF   )r   r!   to_framer   r2   r   r   r   rW     s    %zSeries.to_framez	list[Any]c                 C  s
   | j  S )a^  
        Convert to list.

        Notes:
            This function converts to Python scalars. It's typically
            more efficient to keep your data in the format native to
            your original dataframe, so we recommend only calling this
            when you absolutely need to.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s, name="a")
            >>> s_pl = pl.Series("a", s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.to_list()

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

            >>> func(s_pd)
            [1, 2, 3]
            >>> func(s_pl)
            [1, 2, 3]
        )r!   to_listr2   r   r   r   rX     s    zSeries.to_listc                 C  s
   | j  S )aW  
        Reduce this Series to the mean value.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.mean()

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

            >>> func(s_pd)
            np.float64(2.0)
            >>> func(s_pl)
            2.0
        )r!   meanr2   r   r   r   rY     s    zSeries.meanc                 C  s
   | j  S )ad  
        Returns the number of non-null elements in the Series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.count()

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

            >>> func(s_pd)
            np.int64(3)
            >>> func(s_pl)
            3

        )r!   countr2   r   r   r   rZ     s    zSeries.countc                 C  s
   | j  S )a  
        Return whether any of the values in the Series are True.

        Notes:
          Only works on Series of data type Boolean.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [False, True, False]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.any()

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

            >>> func(s_pd)
            np.True_
            >>> func(s_pl)
            True
        )r!   anyr2   r   r   r   r[   +  s    z
Series.anyc                 C  s
   | j  S )ai  
        Return whether all values in the Series are True.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [True, False, True]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.all()

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

            >>> func(s_pd)
            np.False_
            >>> func(s_pl)
            False

        )r!   allr2   r   r   r   r\   I  s    z
Series.allc                 C  s
   | j  S )aP  
        Get the minimal value in this Series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.min()

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

            >>> func(s_pd)
            np.int64(1)
            >>> func(s_pl)
            1
        )r!   minr2   r   r   r   r]   e  s    z
Series.minc                 C  s
   | j  S )aP  
        Get the maximum value in this Series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.max()

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

            >>> func(s_pd)
            np.int64(3)
            >>> func(s_pl)
            3
        )r!   maxr2   r   r   r   r^     s    z
Series.maxc                 C  s
   | j  S )aO  
        Reduce this Series to the sum value.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.sum()

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

            >>> func(s_pd)
            np.int64(6)
            >>> func(s_pl)
            6
        )r!   sumr2   r   r   r   r_     s    z
Series.sum   ddof)rb   r   c                C  s   | j j|dS )u  
        Get the standard deviation of this Series.

        Arguments:
            ddof: “Delta Degrees of Freedom”: the divisor used in the calculation is N - ddof,
                     where N represents the number of elements.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.std()

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

            >>> func(s_pd)
            np.float64(1.0)
            >>> func(s_pl)
            1.0
        ra   )r!   std)r   rb   r   r   r   rc     s    z
Series.stdz
Any | None)lower_boundupper_boundr   c                 C  s   |  | jj||dS )a  
        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 narwhals as nw
            >>>
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func_lower(s):
            ...     return s.clip(2)

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

            >>> func_lower(s_pd)
            0    2
            1    2
            2    3
            dtype: int64
            >>> func_lower(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               2
               2
               3
            ]

            We define another library agnostic function:

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

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

            >>> func_upper(s_pd)
            0    1
            1    2
            2    2
            dtype: int64
            >>> func_upper(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               1
               2
               2
            ]

            We can have both at the same time

            >>> s = [-1, 1, -3, 3, -5, 5]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

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

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

            >>> func(s_pd)
            0   -1
            1    1
            2   -1
            3    3
            4   -1
            5    3
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (6,)
            Series: '' [i64]
            [
               -1
                1
               -1
                3
               -1
                3
            ]
        )rd   re   )r/   r!   clip)r   rd   re   r   r   r   rf     s    azSeries.clip)otherr   c                 C  s   |  | j| |S )a  
        Check if the elements of this Series are in the other sequence.

        Arguments:
            other: Sequence of primitive type.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s_pd = pd.Series([1, 2, 3])
            >>> s_pl = pl.Series([1, 2, 3])

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_in([3, 2, 8])

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

            >>> func(s_pd)
            0    False
            1     True
            2     True
            dtype: bool
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [bool]
            [
               false
               true
               true
            ]
        )r/   r!   is_inrC   r   rg   r   r   r   rh   :  s    $zSeries.is_inc                 C  s   |  | j S )a>  
        Find elements where boolean Series is True.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = [1, None, None, 2]
            >>> s_pd = pd.Series(data, name="a")
            >>> s_pl = pl.Series("a", data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_null().arg_true()

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

            >>> func(s_pd)
            1    1
            2    2
            Name: a, dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: 'a' [u32]
            [
               1
               2
            ]
        )r/   r!   arg_truer2   r   r   r   rj   b  s     zSeries.arg_truec                 C  s   |  | j S )a  
        Drop all null values.

        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 numpy as np
          >>> import narwhals as nw
          >>> s_pd = pd.Series([2, 4, None, 3, 5])
          >>> s_pl = pl.Series("a", [2, 4, None, 3, 5])

          Now define a dataframe-agnostic function with a `column` argument for the column to evaluate :

          >>> @nw.narwhalify
          ... def func(s):
          ...     return s.drop_nulls()

          Then we can pass either Series (polars or pandas) to `func`:

          >>> func(s_pd)
          0    2.0
          1    4.0
          3    3.0
          4    5.0
          dtype: float64
          >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
          shape: (4,)
          Series: 'a' [i64]
          [
             2
             4
             3
             5
          ]
        )r/   r!   
drop_nullsr2   r   r   r   rk     s    (zSeries.drop_nullsc                 C  s   |  | j S )a-  
        Calculate the absolute value of each element.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [2, -4, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.abs()

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

            >>> func(s_pd)
            0    2
            1    4
            2    3
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               2
               4
               3
            ]
        )r/   r!   absr2   r   r   r   rl     s    "z
Series.absc                 C  s   |  | j S )a   
        Calculate the cumulative sum.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [2, 4, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.cum_sum()

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

            >>> func(s_pd)
            0    2
            1    6
            2    9
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               2
               6
               9
            ]
        )r/   r!   cum_sumr2   r   r   r   rm     s    "zSeries.cum_sumFmaintain_orderbool)ro   r   c                C  s   |  | jj|dS )a<  
        Returns unique values of the series.

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

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [2, 4, 4, 6]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.unique(maintain_order=True)

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

            >>> func(s_pd)
            0    2
            1    4
            2    6
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               2
               4
               6
            ]
        rn   )r/   r!   unique)r   ro   r   r   r   rq     s    'zSeries.uniquec                 C  s   |  | j S )a  
        Calculate the difference with the previous element, for each element.

        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:

                s.diff().fill_null(0).cast(nw.Int64)

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [2, 4, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.diff()

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

            >>> func(s_pd)
            0    NaN
            1    2.0
            2   -1.0
            dtype: float64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               null
               2
               -1
            ]
        )r/   r!   diffr2   r   r   r   rr   !  s    +zSeries.diff)nr   c                 C  s   |  | j|S )am  
        Shift values by `n` positions.

        Arguments:
            n: Number of indices to shift forward. If a negative value is passed,
                values are shifted in the opposite direction instead.

        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:

                s.shift(1).fill_null(0).cast(nw.Int64)

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [2, 4, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.shift(1)

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

            >>> func(s_pd)
            0    NaN
            1    2.0
            2    4.0
            dtype: float64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               null
               2
               4
            ]
        )r/   r!   shiftr   rs   r   r   r   rt   N  s    /zSeries.shift)fractionwith_replacementseed
int | Nonezfloat | None)r   rs   rv   rw   rx   r   c                C  s   |  | jj||||dS )a  
        Sample randomly from this Series.

        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.

        Notes:
            The `sample` method returns a Series with a specified number of
            randomly selected items chosen from this Series.
            The results are not consistent across libraries.

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

            >>> s_pd = pd.Series([1, 2, 3, 4])
            >>> s_pl = pl.Series([1, 2, 3, 4])

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.sample(fraction=1.0, with_replacement=True)

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

            >>> func(s_pd)  # doctest: +SKIP
               a
            2  3
            1  2
            3  4
            3  4
            >>> func(s_pl)  # doctest: +SKIP
            shape: (4,)
            Series: '' [i64]
            [
               1
               4
               3
               4
            ]
        )rs   rv   rw   rx   )r/   r!   sample)r   rs   rv   rw   rx   r   r   r   rz     s    7   zSeries.sample)rU   r   c                 C  s   |  | jj|dS )ar  
        Rename the Series.

        Notes:
            This method is very cheap, but does not guarantee that data
            will be copied. For example:

            ```python
            s1: nw.Series
            s2 = s1.alias("foo")
            arr = s2.to_numpy()
            arr[0] = 999
            ```

            may (depending on the backend, and on the version) result in
            `s1`'s data being modified. We recommend:

                - if you need to alias an object and don't need the original
                  one around any more, just use `alias` without worrying about it.
                - if you were expecting `alias` to copy data, then explicily call
                  `.clone` before calling `alias`.

        Arguments:
            name: The new name.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s, name="foo")
            >>> s_pl = pl.Series("foo", s)
            >>> s_pa = pa.chunked_array([s])

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.alias("bar")

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

            >>> func(s_pd)
            0    1
            1    2
            2    3
            Name: bar, dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: 'bar' [i64]
            [
               1
               2
               3
            ]
            >>> func(s_pa)  # doctest: +ELLIPSIS
            <pyarrow.lib.ChunkedArray object at 0x...>
            [
              [
                1,
                2,
                3
              ]
            ]
        rU   )r/   r!   aliasr   rU   r   r   r   r|     s    CzSeries.aliasc                 C  s   | j |dS )a  
        Rename the Series.

        Alias for `Series.alias()`.

        Notes:
            This method is very cheap, but does not guarantee that data
            will be copied. For example:

            ```python
            s1: nw.Series
            s2 = s1.rename("foo")
            arr = s2.to_numpy()
            arr[0] = 999
            ```

            may (depending on the backend, and on the version) result in
            `s1`'s data being modified. We recommend:

                - if you need to rename an object and don't need the original
                  one around any more, just use `rename` without worrying about it.
                - if you were expecting `rename` to copy data, then explicily call
                  `.clone` before calling `rename`.

        Arguments:
            name: The new name.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import pyarrow as pa
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s, name="foo")
            >>> s_pl = pl.Series("foo", s)
            >>> s_pa = pa.chunked_array([s])

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.rename("bar")

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

            >>> func(s_pd)
            0    1
            1    2
            2    3
            Name: bar, dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: 'bar' [i64]
            [
               1
               2
               3
            ]
            >>> func(s_pa)  # doctest: +ELLIPSIS
            <pyarrow.lib.ChunkedArray object at 0x...>
            [
              [
                1,
                2,
                3
              ]
            ]
        r{   )r|   r}   r   r   r   rename  s    EzSeries.renamezSequence[Any])oldnewreturn_dtyper   c                C  s   |  | jj|||dS )a  
        Replace old values with 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(s):
            ...     return s.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"])
            0    three
            1     zero
            2      one
            3      two
            Name: a, dtype: object
            >>> func(df_pl["a"])  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: 'a' [str]
            [
                "three"
                "zero"
                "one"
                "two"
            ]
            >>> func(df_pa["a"])
            <pyarrow.lib.ChunkedArray object at ...>
            [
              [
                "three",
                "zero",
                "one",
                "two"
              ]
            ]
        )r   )r/   r!   replace_strict)r   r   r   r   r   r   r   r   H  s    ;zSeries.replace_strict
descending
nulls_last)r   r   r   c                C  s   |  | jj||dS )a  
        Sort this Series. Place null values first.

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

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [5, None, 1, 2]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define library agnostic functions:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.sort()

            >>> @nw.narwhalify
            ... def func_descend(s):
            ...     return s.sort(descending=True)

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

            >>> func(s_pd)
            1    NaN
            2    1.0
            3    2.0
            0    5.0
            dtype: float64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [i64]
            [
               null
               1
               2
               5
            ]
            >>> func_descend(s_pd)
            1    NaN
            0    5.0
            3    2.0
            2    1.0
            dtype: float64
            >>> func_descend(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [i64]
            [
               null
               5
               2
               1
            ]
        r   )r/   r!   sort)r   r   r   r   r   r   r     s    ;zSeries.sortc                 C  s   |  | j S )a  
        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 narwhals as nw
            >>> s = [1, 2, None]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_null()

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

            >>> func(s_pd)
            0    False
            1    False
            2     True
            dtype: bool
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [bool]
            [
               false
               false
               true
            ]
        )r/   r!   is_nullr2   r   r   r   r     s    &zSeries.is_null)valuer   c                 C  s   |  | j|S )a   
        Fill null values using the specified value.

        Arguments:
            value: Value used to fill null values.

        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 narwhals as nw
            >>> s = [1, 2, None]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.fill_null(5)

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

            >>> func(s_pd)
            0    1.0
            1    2.0
            2    5.0
            dtype: float64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               1
               2
               5
            ]
        )r/   r!   	fill_null)r   r   r   r   r   r     s    )zSeries.fill_nullboth)rd   re   closedr   c                 C  s   |  | jj|||dS )aD  
        Get a boolean mask of the values that are between the given lower/upper bounds.

        Arguments:
            lower_bound: Lower bound value.

            upper_bound: Upper bound value.

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

        Notes:
            If the value of the `lower_bound` is greater than that of the `upper_bound`,
            then the values will be False, as no value can satisfy the condition.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s_pd = pd.Series([1, 2, 3, 4, 5])
            >>> s_pl = pl.Series([1, 2, 3, 4, 5])

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_between(2, 4, "right")

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

            >>> func(s_pd)
            0    False
            1    False
            2     True
            3     True
            4    False
            dtype: bool
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: '' [bool]
            [
               false
               false
               true
               true
               false
            ]
        )r   )r/   r!   
is_between)r   rd   re   r   r   r   r   r     s    2zSeries.is_betweenc                 C  s
   | j  S )aK  
        Count the number of unique values.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 2, 3]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.n_unique()

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

            >>> func(s_pd)
            3
            >>> func(s_pl)
            3
        )r!   n_uniquer2   r   r   r   r   O  s    zSeries.n_uniquec                 C  s
   | j  S )aj  
        Convert to numpy.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s, name="a")
            >>> s_pl = pl.Series("a", s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.to_numpy()

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

            >>> func(s_pd)
            array([1, 2, 3]...)
            >>> func(s_pl)
            array([1, 2, 3]...)
        )r!   to_numpyr2   r   r   r   r   j  s    zSeries.to_numpyz	pd.Seriesc                 C  s
   | j  S )a  
        Convert to pandas.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [1, 2, 3]
            >>> s_pd = pd.Series(s, name="a")
            >>> s_pl = pl.Series("a", s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.to_pandas()

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

            >>> func(s_pd)
            0    1
            1    2
            2    3
            Name: a, dtype: int64
            >>> func(s_pl)
            0    1
            1    2
            2    3
            Name: a, dtype: int64
        )r!   	to_pandasr2   r   r   r   r     s    zSeries.to_pandasc                 C  s   |  | j| |S r+   )r/   r!   __add__rC   ri   r   r   r   r     s    zSeries.__add__c                 C  s   |  | j| |S r+   )r/   r!   __radd__rC   ri   r   r   r   r     s    zSeries.__radd__c                 C  s   |  | j| |S r+   )r/   r!   __sub__rC   ri   r   r   r   r     s    zSeries.__sub__c                 C  s   |  | j| |S r+   )r/   r!   __rsub__rC   ri   r   r   r   r     s    zSeries.__rsub__c                 C  s   |  | j| |S r+   )r/   r!   __mul__rC   ri   r   r   r   r     s    zSeries.__mul__c                 C  s   |  | j| |S r+   )r/   r!   __rmul__rC   ri   r   r   r   r     s    zSeries.__rmul__c                 C  s   |  | j| |S r+   )r/   r!   __truediv__rC   ri   r   r   r   r     s    zSeries.__truediv__c                 C  s   |  | j| |S r+   )r/   r!   __rtruediv__rC   ri   r   r   r   r     s    zSeries.__rtruediv__c                 C  s   |  | j| |S r+   )r/   r!   __floordiv__rC   ri   r   r   r   r     s    zSeries.__floordiv__c                 C  s   |  | j| |S r+   )r/   r!   __rfloordiv__rC   ri   r   r   r   r     s    zSeries.__rfloordiv__c                 C  s   |  | j| |S r+   )r/   r!   __pow__rC   ri   r   r   r   r     s    zSeries.__pow__c                 C  s   |  | j| |S r+   )r/   r!   __rpow__rC   ri   r   r   r   r     s    zSeries.__rpow__c                 C  s   |  | j| |S r+   )r/   r!   __mod__rC   ri   r   r   r   r     s    zSeries.__mod__c                 C  s   |  | j| |S r+   )r/   r!   __rmod__rC   ri   r   r   r   r     s    zSeries.__rmod__c                 C  s   |  | j| |S r+   )r/   r!   __eq__rC   ri   r   r   r   r     s    zSeries.__eq__c                 C  s   |  | j| |S r+   )r/   r!   __ne__rC   ri   r   r   r   r     s    zSeries.__ne__c                 C  s   |  | j| |S r+   )r/   r!   __gt__rC   ri   r   r   r   r     s    zSeries.__gt__c                 C  s   |  | j| |S r+   )r/   r!   __ge__rC   ri   r   r   r   r     s    zSeries.__ge__c                 C  s   |  | j| |S r+   )r/   r!   __lt__rC   ri   r   r   r   r      s    zSeries.__lt__c                 C  s   |  | j| |S r+   )r/   r!   __le__rC   ri   r   r   r   r     s    zSeries.__le__c                 C  s   |  | j| |S r+   )r/   r!   __and__rC   ri   r   r   r   r   
  s    zSeries.__and__c                 C  s   |  | j| |S r+   )r/   r!   __or__rC   ri   r   r   r   r     s    zSeries.__or__c                 C  s   |  | j S r+   )r/   r!   
__invert__r2   r   r   r   r     s    zSeries.__invert__c                 C  s   |  | j| |S )aI  
        Filter elements in the Series based on a condition.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> s = [4, 10, 15, 34, 50]
            >>> s_pd = pd.Series(s)
            >>> s_pl = pl.Series(s)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.filter(s > 10)

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

            >>> func(s_pd)
            2    15
            3    34
            4    50
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               15
               34
               50
            ]
        )r/   r!   filterrC   ri   r   r   r   r     s    "zSeries.filterc                 C  s   |  | j S )a  
        Get a mask of all duplicated rows in the Series.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> s_pd = pd.Series([1, 2, 3, 1])
            >>> s_pl = pl.Series([1, 2, 3, 1])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_duplicated()

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0     True
            1    False
            2    False
            3     True
            dtype: bool
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [bool]
            [
                true
                false
                false
                true
            ]
        )r/   r!   is_duplicatedr2   r   r   r   r   ?  s    #zSeries.is_duplicatedc                 C  s
   | j  S )aM  
        Check if the series is empty.

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

            Let's define a dataframe-agnostic function that filters rows in which "foo"
            values are greater than 10, and then checks if the result is empty or not:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.filter(s > 10).is_empty()

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

            >>> s_pd = pd.Series([1, 2, 3])
            >>> s_pl = pl.Series([1, 2, 3])
            >>> func(s_pd), func(s_pl)
            (True, True)

            >>> s_pd = pd.Series([100, 2, 3])
            >>> s_pl = pl.Series([100, 2, 3])
            >>> func(s_pd), func(s_pl)
            (False, False)
        )r!   is_emptyr2   r   r   r   r   d  s    zSeries.is_emptyc                 C  s   |  | j S )a  
        Get a mask of all unique rows in the Series.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> s_pd = pd.Series([1, 2, 3, 1])
            >>> s_pl = pl.Series([1, 2, 3, 1])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_unique()

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0    False
            1     True
            2     True
            3    False
            dtype: bool

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [bool]
            [
                false
                 true
                 true
                false
            ]
        )r/   r!   	is_uniquer2   r   r   r   r     s    $zSeries.is_uniquec                 C  s
   | j  S )a>  
        Create a new Series that shows the null counts per column.

        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
            >>> s_pd = pd.Series([1, None, 3])
            >>> s_pl = pl.Series([1, None, None])

            Let's define a dataframe-agnostic function that returns the null count of
            the series:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.null_count()

            We can then pass either pandas or Polars to `func`:
            >>> func(s_pd)
            np.int64(1)
            >>> func(s_pl)
            2
        )r!   
null_countr2   r   r   r   r     s    zSeries.null_countc                 C  s   |  | j S )a  
        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
            >>> s_pd = pd.Series([1, 1, 2, 3, 2])
            >>> s_pl = pl.Series([1, 1, 2, 3, 2])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_first_distinct()

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0     True
            1    False
            2     True
            3     True
            4    False
            dtype: bool

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: '' [bool]
            [
                true
                false
                true
                true
                false
            ]
        )r/   r!   is_first_distinctr2   r   r   r   r     s    &zSeries.is_first_distinctc                 C  s   |  | j S )a  
        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
            >>> s_pd = pd.Series([1, 1, 2, 3, 2])
            >>> s_pl = pl.Series([1, 1, 2, 3, 2])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.is_last_distinct()

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0    False
            1     True
            2    False
            3     True
            4     True
            dtype: bool

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: '' [bool]
            [
                false
                true
                false
                true
                true
            ]
        )r/   r!   is_last_distinctr2   r   r   r   r     s    &zSeries.is_last_distinctr   )r   r   r   c                C  s   | j j|dS )a  
        Check if the Series is sorted.

        Arguments:
            descending: Check if the Series is sorted in descending order.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> unsorted_data = [1, 3, 2]
            >>> sorted_data = [3, 2, 1]

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s, descending=False):
            ...     return s.is_sorted(descending=descending)

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

            >>> func(pl.Series(unsorted_data))
            False
            >>> func(pl.Series(sorted_data), descending=True)
            True
            >>> func(pd.Series(unsorted_data))
            False
            >>> func(pd.Series(sorted_data), descending=True)
            True
        r   )r!   	is_sorted)r   r   r   r   r   r     s    zSeries.is_sortedr   parallelrU   	normalize
str | None)r   r   r   rU   r   r   c                C  s    | j | jj||||d| jdS )uz  
        Count the occurrences of unique values.

        Arguments:
            sort: Sort the output by count in descending order. If set to False (default),
                the order of the output is random.
            parallel: Execute the computation in parallel. Used for Polars only.
            name: Give the resulting count column a specific name; if `normalize` is True
                defaults to "proportion", otherwise defaults to "count".
            normalize: If true gives relative frequencies of the unique values

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> s_pd = pd.Series([1, 1, 2, 3, 2], name="s")
            >>> s_pl = pl.Series(values=[1, 1, 2, 3, 2], name="s")

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.value_counts(sort=True)

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
               s  count
            0  1      2
            1  2      2
            2  3      1

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3, 2)
            ┌─────┬───────┐
            │ s   ┆ count │
            │ --- ┆ ---   │
            │ i64 ┆ u32   │
            ╞═════╪═══════╡
            │ 1   ┆ 2     │
            │ 2   ┆ 2     │
            │ 3   ┆ 1     │
            └─────┴───────┘
        r   rF   )r   r!   value_countsr   )r   r   r   rU   r   r   r   r   r   7  s    4   zSeries.value_countsfloatz=Literal[('nearest', 'higher', 'lower', 'midpoint', 'linear')])quantileinterpolationr   c                 C  s   | j j||dS )aZ  
        Get quantile value of the series.

        Note:
            pandas and Polars may have implementation differences for a given interpolation 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
            >>> data = list(range(50))
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return [
            ...         s.quantile(quantile=q, interpolation="nearest")
            ...         for q in (0.1, 0.25, 0.5, 0.75, 0.9)
            ...     ]

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

            >>> func(s_pd)
            [np.int64(5), np.int64(12), np.int64(24), np.int64(37), np.int64(44)]

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            [5.0, 12.0, 25.0, 37.0, 44.0]
        )r   r   )r!   r   )r   r   r   r   r   r   r   r  s    ( zSeries.quantile)r   maskrg   r   c                 C  s    |  | j| || |S )a  
        Take values from self or other based on the given mask.

        Where mask evaluates true, take values from self. Where mask evaluates false,
        take values from other.

        Arguments:
            mask: Boolean Series
            other: Series of same type.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> s1_pl = pl.Series([1, 2, 3, 4, 5])
            >>> s2_pl = pl.Series([5, 4, 3, 2, 1])
            >>> mask_pl = pl.Series([True, False, True, False, True])
            >>> s1_pd = pd.Series([1, 2, 3, 4, 5])
            >>> s2_pd = pd.Series([5, 4, 3, 2, 1])
            >>> mask_pd = pd.Series([True, False, True, False, True])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s1_any, mask_any, s2_any):
            ...     return s1_any.zip_with(mask_any, s2_any)

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

            >>> func(s1_pl, mask_pl, s2_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: '' [i64]
            [
               1
               4
               3
               2
               5
            ]
            >>> func(s1_pd, mask_pd, s2_pd)
            0    1
            1    4
            2    3
            3    2
            4    5
            dtype: int64
        )r/   r!   zip_withrC   )r   r   rg   r   r   r   r     s    0 zSeries.zip_with)r   indexr   c                 C  s   | j j|dS )aW  
        Return the Series as a scalar, or return the element at the given index.

        If no index is provided, this is equivalent to `s[0]`, with a check
        that the shape is (1,). With an index, this is equivalent to `s[index]`.

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

            Let's define a dataframe-agnostic function that returns item at given index

            >>> @nw.narwhalify
            ... def func(s, index=None):
            ...     return s.item(index)

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

            >>> func(pl.Series("a", [1]), None), func(pd.Series([1]), None)
            (1, np.int64(1))

            >>> func(pl.Series("a", [9, 8, 7]), -1), func(pl.Series([9, 8, 7]), -2)
            (7, 8)
        )r   )r!   item)r   r   r   r   r   r     s    zSeries.item
   r   rs   r   c                 C  s   |  | j|S )a  
        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
            >>> data = list(range(10))
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

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

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.head(3)

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0    0
            1    1
            2    2
            dtype: int64

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               0
               1
               2
            ]
        )r/   r!   headru   r   r   r   r     s    &zSeries.headc                 C  s   |  | j|S )a  
        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
            >>> data = list(range(10))
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

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

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.tail(3)

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            7    7
            8    8
            9    9
            dtype: int64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
               7
               8
               9
            ]
        )r/   r!   tailru   r   r   r   r   	  s    %zSeries.tailr   )r   decimalsr   c                 C  s   |  | j|S )a  
        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
            >>> data = [1.12345, 2.56789, 3.901234]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

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

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.round(1)

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0    1.1
            1    2.6
            2    3.9
            dtype: float64

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [f64]
            [
               1.1
               2.6
               3.9
            ]
        )r/   r!   round)r   r   r   r   r   r   ?	  s    .zSeries.round_	separator
drop_first)r   r   r   r   c                C  s   | j | jj||d| jdS )ui  
        Get dummy/indicator variables.

        Arguments:
            separator: Separator/delimiter used when generating column names.
            drop_first: Remove the first category from the variable being encoded.

        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
            >>> data = [1, 2, 3]
            >>> s_pd = pd.Series(data, name="a")
            >>> s_pl = pl.Series("a", data)

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

            >>> @nw.narwhalify
            ... def func(s, drop_first: bool = False):
            ...     return s.to_dummies(drop_first=drop_first)

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

            >>> func(s_pd)
               a_1  a_2  a_3
            0    1    0    0
            1    0    1    0
            2    0    0    1

            >>> func(s_pd, drop_first=True)
               a_2  a_3
            0    0    0
            1    1    0
            2    0    1

            >>> func(s_pl)
            shape: (3, 3)
            ┌─────┬─────┬─────┐
            │ a_1 ┆ a_2 ┆ a_3 │
            │ --- ┆ --- ┆ --- │
            │ u8  ┆ u8  ┆ u8  │
            ╞═════╪═════╪═════╡
            │ 1   ┆ 0   ┆ 0   │
            │ 0   ┆ 1   ┆ 0   │
            │ 0   ┆ 0   ┆ 1   │
            └─────┴─────┴─────┘
            >>> func(s_pl, drop_first=True)
            shape: (3, 2)
            ┌─────┬─────┐
            │ a_2 ┆ a_3 │
            │ --- ┆ --- │
            │ u8  ┆ u8  │
            ╞═════╪═════╡
            │ 0   ┆ 0   │
            │ 1   ┆ 0   │
            │ 0   ┆ 1   │
            └─────┴─────┘
        r   rF   )r   r!   
to_dummiesr   )r   r   r   r   r   r   r   o	  s    AzSeries.to_dummies)r   rs   offsetr   c                 C  s   |  | jj||dS )a  
        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
            >>> data = [1, 2, 3, 4]
            >>> s_pd = pd.Series(name="a", data=data)
            >>> s_pl = pl.Series(name="a", values=data)

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

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.gather_every(n=2, offset=1)

            >>> func(s_pd)
            1    2
            3    4
            Name: a, dtype: int64

            >>> func(s_pl)  # doctest:+NORMALIZE_WHITESPACE
            shape: (2,)
            Series: 'a' [i64]
            [
               2
               4
            ]
        )rs   r   )r/   r!   gather_every)r   rs   r   r   r   r   r   	  s    $zSeries.gather_everyzpa.Arrayc                 C  s
   | j  S )a  
        Convert to arrow.

        Examples:
            >>> import narwhals as nw
            >>> import pandas as pd
            >>> import polars as pl
            >>> data = [1, 2, 3, 4]
            >>> s_pd = pd.Series(name="a", data=data)
            >>> s_pl = pl.Series(name="a", values=data)

            Let's define a dataframe-agnostic function that converts to arrow:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.to_arrow()

            >>> func(s_pd)  # doctest:+NORMALIZE_WHITESPACE
            <pyarrow.lib.Int64Array object at ...>
            [
                1,
                2,
                3,
                4
            ]

            >>> func(s_pl)  # doctest:+NORMALIZE_WHITESPACE
            <pyarrow.lib.Int64Array object at ...>
            [
                1,
                2,
                3,
                4
            ]
        )r!   r;   r2   r   r   r   r;   	  s    $zSeries.to_arrowc                 C  s   |  | j S )ad  
        Compute the most occurring value(s).

        Can return multiple values.

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

            >>> data = [1, 1, 2, 2, 3]
            >>> s_pd = pd.Series(name="a", data=data)
            >>> s_pl = pl.Series(name="a", values=data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.mode().sort()

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

            >>> func(s_pd)
            0    1
            1    2
            Name: a, dtype: int64

            >>> func(s_pl)  # doctest:+NORMALIZE_WHITESPACE
            shape: (2,)
            Series: 'a' [i64]
            [
               1
               2
            ]
        )r/   r!   moder2   r   r   r   r   
  s    $zSeries.modezIterator[Any]c                 c  s   | j  E d H  d S r+   )r!   __iter__r2   r   r   r   r   )
  s    zSeries.__iter__zSeriesStringNamespace[Self]c                 C  s   t | S r+   )SeriesStringNamespacer2   r   r   r   rM   ,
  s    z
Series.strzSeriesDateTimeNamespace[Self]c                 C  s   t | S r+   )SeriesDateTimeNamespacer2   r   r   r   dt0
  s    z	Series.dtzSeriesCatNamespace[Self]c                 C  s   t | S r+   )SeriesCatNamespacer2   r   r   r   cat4
  s    z
Series.cat)NN)N)NN)N)r   )N)r   )r   )r   )r   )d__name__
__module____qualname____doc__propertyr   r%   r(   r   r-   r1   r5   r?   rB   rD   rC   r/   rL   rR   rT   rO   r&   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r_   rc   rf   rh   rj   rk   rl   rm   rq   rr   rt   rz   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   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r;   r   r   rM   r   r   r   r   r   r   r      s   
'B&'*!   e("*$$+-3=EG??(,6!'%&(($;,6('1 F(&&r   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+   _narwhals_seriesrH   r   r   r   r%   =
  s    zSeriesCatNamespace.__init__r0   c                 C  s   | j | j jj S )a  
        Get unique categories from column.

        Examples:
            Let's create some series:

            >>> import pandas as pd
            >>> import polars as pl
            >>> import narwhals as nw
            >>> data = ["apple", "mango", "mango"]
            >>> s_pd = pd.Series(data, dtype="category")
            >>> s_pl = pl.Series(data, dtype=pl.Categorical)

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

            >>> @nw.narwhalify(series_only=True)
            ... def func(s):
            ...     return s.cat.get_categories()

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

            >>> func(s_pd)
            0    apple
            1    mango
            dtype: object
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [str]
            [
               "apple"
               "mango"
            ]
        )r   r/   r!   r   get_categoriesr2   r   r   r   r   @
  s    #z!SeriesCatNamespace.get_categoriesN)r   r   r   r%   r   r   r   r   r   r   <
  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dZd
dddddddddZd7d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
d8ddd%dd&d'd(Zd9dddd*d+d,Zd:dddd*d-d.Zdd/d0d1Zdd/d2d3Zd;dddd4d5d6ZdS )<r   r   r   r   r   c                 C  s
   || _ d S r+   r   rH   r   r   r   r%   i
  s    zSeriesStringNamespace.__init__r0   c                 C  s   | j | j jj 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 = ["foo", "Café", "345", "東京", None]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.len_chars()

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

            >>> func(s_pd)
            0    3.0
            1    4.0
            2    3.0
            3    2.0
            4    NaN
            dtype: float64

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: '' [u32]
            [
               3
               4
               3
               2
               null
            ]
        )r   r/   r!   rM   	len_charsr2   r   r   r   r   l
  s    'zSeriesStringNamespace.len_charsFr`   literalrs   rM   rp   r)   )r   patternr   r   rs   r   c                C  s    | j | j jjj||||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 = ["123abc", "abc abc123"]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     s = s.str.replace("abc", "")
            ...     return s.to_list()

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

            >>> func(s_pd)
            ['123', ' abc123']

            >>> func(s_pl)
            ['123', ' abc123']
        r   )r   r/   r!   rM   replace)r   r   r   r   rs   r   r   r   r   
  s    #
   zSeriesStringNamespace.replacer   )r   r   r   r   r   c                C  s   | j | j jjj|||dS )a  
        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 = ["123abc", "abc abc123"]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     s = s.str.replace_all("abc", "")
            ...     return s.to_list()

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

            >>> func(s_pd)
            ['123', ' 123']

            >>> func(s_pl)
            ['123', ' 123']
        r   )r   r/   r!   rM   replace_all)r   r   r   r   r   r   r   r   
  s     
  z!SeriesStringNamespace.replace_allNr   )r   
charactersr   c                 C  s   | j | j jj|S )a  
        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 = ["apple", "\nmango"]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     s = s.str.strip_chars()
            ...     return s.to_list()

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

            >>> func(s_pd)
            ['apple', 'mango']

            >>> func(s_pl)
            ['apple', 'mango']
        )r   r/   r!   rM   strip_chars)r   r   r   r   r   r   
  s    z!SeriesStringNamespace.strip_chars)r   prefixr   c                 C  s   | j | j jj|S )a  
        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 = ["apple", "mango", None]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.starts_with("app")

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

            >>> func(s_pd)
            0     True
            1    False
            2     None
            dtype: object

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [bool]
            [
               true
               false
               null
            ]
        )r   r/   r!   rM   starts_with)r   r   r   r   r   r     s    &z!SeriesStringNamespace.starts_with)r   suffixr   c                 C  s   | j | j jj|S )a  
        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 = ["apple", "mango", None]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.ends_with("ngo")

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

            >>> func(s_pd)
            0    False
            1     True
            2     None
            dtype: object

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [bool]
            [
               false
               true
               null
            ]
        )r   r/   r!   rM   	ends_with)r   r   r   r   r   r   2  s    &zSeriesStringNamespace.ends_with)r   r   r   r   c                C  s   | j | j jjj||dS )a  
        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
            >>> pets = ["cat", "dog", "rabbit and parrot", "dove", None]
            >>> s_pd = pd.Series(pets)
            >>> s_pl = pl.Series(pets)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.contains("parrot|dove")

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

            >>> func(s_pd)
            0    False
            1    False
            2     True
            3     True
            4     None
            dtype: object

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: '' [bool]
            [
               false
               false
               true
               true
               null
            ]
        r   )r   r/   r!   rM   contains)r   r   r   r   r   r   r   \  s    ,zSeriesStringNamespace.containsry   )r   r   rQ   r   c                 C  s   | j | j jjj||dS )a  
        Create subslices of the string values of a Series.

        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 = ["pear", None, "papaya", "dragonfruit"]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.slice(4, length=3)

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

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0
            1    None
            2      ya
            3     onf
            dtype: object

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [str]
            [
               ""
               null
               "ya"
               "onf"
            ]

            Using negative indexes:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.slice(-3)

            >>> func(s_pd)  # doctest: +NORMALIZE_WHITESPACE
            0     ear
            1    None
            2     aya
            3     uit
            dtype: object

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [str]
            [
                "ear"
                null
                "aya"
                "uit"
            ]
        )r   rQ   r   r/   r!   rM   slice)r   r   rQ   r   r   r   r     s    A
 zSeriesStringNamespace.slice   r   c                 C  s   | j | j jjd|S )ag  
        Take the first n elements of each string.

        Arguments:
            n: Number of elements to take. Negative indexing is supported (see note (1.))

        Notes:
            1. When the `n` input is negative, `head` returns characters up to the n-th from the end of the string.
                For example, if `n = -3`, then all characters except the last three are returned.
            2. 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
            >>> lyrics = ["Atatata", "taata", "taatatata", "zukkyun"]
            >>> s_pd = pd.Series(lyrics)
            >>> s_pl = pl.Series(lyrics)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.head()

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

            >>> func(s_pd)
            0    Atata
            1    taata
            2    taata
            3    zukky
            dtype: object
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [str]
            [
               "Atata"
               "taata"
               "taata"
               "zukky"
            ]
        r   r   ru   r   r   r   r     s    ,zSeriesStringNamespace.headc                 C  s   | j | j jj| S )au  
        Take the last n elements of each string.

        Arguments:
            n: Number of elements to take. Negative indexing is supported (see note (1.))

        Notes:
            1. When the `n` input is negative, `tail` returns characters starting from the n-th from the beginning of
                the string. For example, if `n = -3`, then all characters except the first three are returned.
            2. 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
            >>> lyrics = ["Atatata", "taata", "taatatata", "zukkyun"]
            >>> s_pd = pd.Series(lyrics)
            >>> s_pl = pl.Series(lyrics)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.str.tail()

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

            >>> func(s_pd)
            0    atata
            1    taata
            2    atata
            3    kkyun
            dtype: object
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (4,)
            Series: '' [str]
            [
               "atata"
               "taata"
               "atata"
               "kkyun"
            ]
        r   ru   r   r   r   r     s    ,zSeriesStringNamespace.tailr   c                 C  s   | j | j jj S )uY  
        Transform string to uppercase variant.

        Notes:
            The PyArrow backend will convert 'ß' to 'ẞ' instead of 'SS'.
            For more info see: 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)  # doctest: +NORMALIZE_WHITESPACE
             fruits  upper_col
            0  apple      APPLE
            1  mango      MANGO
            2   None       None

            >>> func(df_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3, 2)
            ┌────────┬───────────┐
            │ fruits ┆ upper_col │
            │ ---    ┆ ---       │
            │ str    ┆ str       │
            ╞════════╪═══════════╡
            │ apple  ┆ APPLE     │
            │ mango  ┆ MANGO     │
            │ null   ┆ null      │
            └────────┴───────────┘

        )r   r/   r!   rM   to_uppercaser2   r   r   r   r   3  s    ,z"SeriesStringNamespace.to_uppercasec                 C  s   | j | j jj S )uR  
        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)  # doctest: +NORMALIZE_WHITESPACE
              fruits lower_col
            0  APPLE     apple
            1  MANGO     mango
            2   None      None


            >>> func(df_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3, 2)
            ┌────────┬───────────┐
            │ fruits ┆ lower_col │
            │ ---    ┆ ---       │
            │ str    ┆ str       │
            ╞════════╪═══════════╡
            │ APPLE  ┆ apple     │
            │ MANGO  ┆ mango     │
            │ null   ┆ null      │
            └────────┴───────────┘
        )r   r/   r!   rM   to_lowercaser2   r   r   r   r   c  s    'z"SeriesStringNamespace.to_lowercaser   formatr   c                 C  s   | j | j jjj|dS )u  
        Parse Series with strings to a Series with 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"]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)
            >>> s_pa = pa.chunked_array([data])

            We define a dataframe-agnostic function:

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

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

            >>> func(s_pd)
            0   2020-01-01
            1   2020-01-02
            dtype: datetime64[ns]
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [datetime[μs]]
            [
               2020-01-01 00:00:00
               2020-01-02 00:00:00
            ]
            >>> func(s_pa)  # doctest: +ELLIPSIS
            <pyarrow.lib.ChunkedArray object at 0x...>
            [
              [
                2020-01-01 00:00:00.000000,
                2020-01-02 00:00:00.000000
              ]
            ]
        )r   )r   r/   r!   rM   to_datetimer   r   r   r   r   r     s    8z!SeriesStringNamespace.to_datetime)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   h
  s    , )&"**0G0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   rH   r   r   r   r%     s    z SeriesDateTimeNamespace.__init__r0   c                 C  s   | j | j jj S )a%  
        Get the date in a datetime series.

        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
            >>> dates = [datetime(2012, 1, 7, 10, 20), datetime(2023, 3, 10, 11, 32)]
            >>> s_pd = pd.Series(dates).convert_dtypes(dtype_backend="pyarrow")
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.date()

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

            >>> func(s_pd)
            0    2012-01-07
            1    2023-03-10
            dtype: date32[day][pyarrow]

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [date]
            [
               2012-01-07
               2023-03-10
            ]
        )r   r/   r!   r   dater2   r   r   r   r     s    %zSeriesDateTimeNamespace.datec                 C  s   | j | j jj S )aj  
        Get the year in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [datetime(2012, 1, 7), datetime(2023, 3, 10)]
            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.year()

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

            >>> func(s_pd)
            0    2012
            1    2023
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i32]
            [
               2012
               2023
            ]
        )r   r/   r!   r   yearr2   r   r   r   r     s    !zSeriesDateTimeNamespace.yearc                 C  s   | j | j jj S )a_  
        Gets the month in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [datetime(2023, 2, 1), datetime(2023, 8, 3)]
            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.month()

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

            >>> func(s_pd)
            0    2
            1    8
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i8]
            [
               2
               8
            ]
        )r   r/   r!   r   monthr2   r   r   r   r     s    !zSeriesDateTimeNamespace.monthc                 C  s   | j | j jj S )a_  
        Extracts the day in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [datetime(2022, 1, 1), datetime(2022, 1, 5)]
            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.day()

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

            >>> func(s_pd)
            0    1
            1    5
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i8]
            [
               1
               5
            ]
        )r   r/   r!   r   dayr2   r   r   r   r   B  s    !zSeriesDateTimeNamespace.dayc                 C  s   | j | j jj S )ao  
         Extracts the hour in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [datetime(2022, 1, 1, 5, 3), datetime(2022, 1, 5, 9, 12)]
            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.hour()

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

            >>> func(s_pd)
            0    5
            1    9
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i8]
            [
               5
               9
            ]
        )r   r/   r!   r   hourr2   r   r   r   r   g  s    !zSeriesDateTimeNamespace.hourc                 C  s   | j | j jj S )au  
        Extracts the minute in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [datetime(2022, 1, 1, 5, 3), datetime(2022, 1, 5, 9, 12)]
            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.minute()

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

            >>> func(s_pd)
            0     3
            1    12
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i8]
            [
               3
               12
            ]
        )r   r/   r!   r   minuter2   r   r   r   r     s    !zSeriesDateTimeNamespace.minutec                 C  s   | j | j jj S )a  
        Extracts the second(s) in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [datetime(2022, 1, 1, 5, 3, 10), datetime(2022, 1, 5, 9, 12, 4)]
            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.second()

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

            >>> func(s_pd)
            0    10
            1     4
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i8]
            [
               10
                4
            ]
        )r   r/   r!   r   secondr2   r   r   r   r     s    !zSeriesDateTimeNamespace.secondc                 C  s   | j | j jj S )a<  
        Extracts the milliseconds in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [
            ...     datetime(2023, 5, 21, 12, 55, 10, 400000),
            ...     datetime(2023, 5, 21, 12, 55, 10, 600000),
            ...     datetime(2023, 5, 21, 12, 55, 10, 800000),
            ...     datetime(2023, 5, 21, 12, 55, 11, 0),
            ...     datetime(2023, 5, 21, 12, 55, 11, 200000),
            ... ]

            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.millisecond().alias("datetime")

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

            >>> func(s_pd)
            0    400
            1    600
            2    800
            3      0
            4    200
            Name: datetime, dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: 'datetime' [i32]
            [
                400
                600
                800
                0
                200
            ]
        )r   r/   r!   r   millisecondr2   r   r   r   r     s    .z#SeriesDateTimeNamespace.millisecondc                 C  s   | j | j jj S )aR  
        Extracts the microseconds in a datetime series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [
            ...     datetime(2023, 5, 21, 12, 55, 10, 400000),
            ...     datetime(2023, 5, 21, 12, 55, 10, 600000),
            ...     datetime(2023, 5, 21, 12, 55, 10, 800000),
            ...     datetime(2023, 5, 21, 12, 55, 11, 0),
            ...     datetime(2023, 5, 21, 12, 55, 11, 200000),
            ... ]

            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.microsecond().alias("datetime")

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

            >>> func(s_pd)
            0    400000
            1    600000
            2    800000
            3         0
            4    200000
            Name: datetime, dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (5,)
            Series: 'datetime' [i32]
            [
               400000
               600000
               800000
               0
               200000
            ]
        )r   r/   r!   r   microsecondr2   r   r   r   r     s    .z#SeriesDateTimeNamespace.microsecondc                 C  s   | j | j jj S )a  
        Extracts the nanosecond(s) in a date series.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> dates = [
            ...     datetime(2022, 1, 1, 5, 3, 10, 500000),
            ...     datetime(2022, 1, 5, 9, 12, 4, 60000),
            ... ]
            >>> s_pd = pd.Series(dates)
            >>> s_pl = pl.Series(dates)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.nanosecond()

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

            >>> func(s_pd)
            0    500000000
            1     60000000
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i32]
            [
               500000000
               60000000
            ]
        )r   r/   r!   r   
nanosecondr2   r   r   r   r   :  s    $z"SeriesDateTimeNamespace.nanosecondc                 C  s   | j | j jj S )aT  
        Get ordinal day.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import datetime
            >>> import narwhals as nw
            >>> data = [datetime(2020, 1, 1), datetime(2020, 8, 3)]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.ordinal_day()

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

            >>> func(s_pd)
            0      1
            1    216
            dtype: int32
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i16]
            [
               1
               216
            ]
        )r   r/   r!   r   ordinal_dayr2   r   r   r   r   b  s    !z#SeriesDateTimeNamespace.ordinal_dayc                 C  s   | j | j jj S )a`  
        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()` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = [timedelta(minutes=10), timedelta(minutes=20, seconds=40)]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.total_minutes()

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

            >>> func(s_pd)
            0    10
            1    20
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i64]
            [
                    10
                    20
            ]
        )r   r/   r!   r   total_minutesr2   r   r   r   r     s    &z%SeriesDateTimeNamespace.total_minutesc                 C  s   | j | j jj S )ae  
        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()` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = [timedelta(seconds=10), timedelta(seconds=20, milliseconds=40)]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.total_seconds()

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

            >>> func(s_pd)
            0    10
            1    20
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i64]
            [
                    10
                    20
            ]
        )r   r/   r!   r   total_secondsr2   r   r   r   r     s    &z%SeriesDateTimeNamespace.total_secondsc                 C  s   | j | j jj S )a  
        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()` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = [
            ...     timedelta(milliseconds=10),
            ...     timedelta(milliseconds=20, microseconds=40),
            ... ]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.total_milliseconds()

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

            >>> func(s_pd)
            0    10
            1    20
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i64]
            [
                    10
                    20
            ]
        )r   r/   r!   r   total_millisecondsr2   r   r   r   r     s    )z*SeriesDateTimeNamespace.total_millisecondsc                 C  s   | j | j jj S )a  
        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()` in this case.

        Examples:
            >>> import pandas as pd
            >>> import polars as pl
            >>> from datetime import timedelta
            >>> import narwhals as nw
            >>> data = [
            ...     timedelta(microseconds=10),
            ...     timedelta(milliseconds=1, microseconds=200),
            ... ]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.total_microseconds()

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

            >>> func(s_pd)
            0      10
            1    1200
            dtype: int...
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i64]
            [
                    10
                    1200
            ]
        )r   r/   r!   r   total_microsecondsr2   r   r   r   r     s    )z*SeriesDateTimeNamespace.total_microsecondsc                 C  s   | j | j jj S )a  
        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()` 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"]
            >>> s_pd = pd.to_datetime(pd.Series(data))
            >>> s_pl = pl.Series(data).str.to_datetime(time_unit="ns")

            We define a library agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.diff().dt.total_nanoseconds()

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

            >>> func(s_pd)
            0    NaN
            1    1.0
            dtype: float64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [i64]
            [
                    null
                    1
            ]
        )r   r/   r!   r   total_nanosecondsr2   r   r   r   r  5  s    &z)SeriesDateTimeNamespace.total_nanosecondsrM   r   c                 C  s   | j | j jj|S )a	  
        Convert a Date/Time/Datetime series into a String series 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),
            ... ]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)

            We define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.to_string("%Y/%m/%d")

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

            >>> func(s_pd)
            0    2020/03/01
            1    2020/04/01
            2    2020/05/01
            dtype: object

            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [str]
            [
               "2020/03/01"
               "2020/04/01"
               "2020/05/01"
            ]
        )r   r/   r!   r   	to_stringr   r   r   r   r  _  s    Gz!SeriesDateTimeNamespace.to_stringr   )r   	time_zoner   c                 C  s   | j | j jj|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 = [
            ...     datetime(2024, 1, 1, tzinfo=timezone.utc),
            ...     datetime(2024, 1, 2, tzinfo=timezone.utc),
            ... ]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)
            >>> s_pa = pa.chunked_array([data])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.replace_time_zone("Asia/Kathmandu")

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

            >>> func(s_pd)
            0   2024-01-01 00:00:00+05:45
            1   2024-01-02 00:00:00+05:45
            dtype: datetime64[ns, Asia/Kathmandu]
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [datetime[μs, Asia/Kathmandu]]
            [
                2024-01-01 00:00:00 +0545
                2024-01-02 00:00:00 +0545
            ]
            >>> func(s_pa)
            <pyarrow.lib.ChunkedArray object at ...>
            [
              [
                2023-12-31 18:15:00.000000Z,
                2024-01-01 18:15:00.000000Z
              ]
            ]
        )r   r/   r!   r   replace_time_zone)r   r  r   r   r   r    s    1z)SeriesDateTimeNamespace.replace_time_zonec                 C  s,   |dkrd}t || j| jjj|S )uk  
        Convert 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 = [
            ...     datetime(2024, 1, 1, tzinfo=timezone.utc),
            ...     datetime(2024, 1, 2, tzinfo=timezone.utc),
            ... ]
            >>> s_pd = pd.Series(data)
            >>> s_pl = pl.Series(data)
            >>> s_pa = pa.chunked_array([data])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.convert_time_zone("Asia/Kathmandu")

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

            >>> func(s_pd)
            0   2024-01-01 05:45:00+05:45
            1   2024-01-02 05:45:00+05:45
            dtype: datetime64[ns, Asia/Kathmandu]
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (2,)
            Series: '' [datetime[μs, Asia/Kathmandu]]
            [
                2024-01-01 05:45:00 +0545
                2024-01-02 05:45:00 +0545
            ]
            >>> func(s_pa)
            <pyarrow.lib.ChunkedArray object at ...>
            [
              [
                2024-01-01 00:00:00.000000Z,
                2024-01-02 00:00:00.000000Z
              ]
            ]
        NzTarget `time_zone` cannot be `None` in `convert_time_zone`. Please use `replace_time_zone(None)` if you want to remove the time zone.)	TypeErrorr   r/   r!   r   convert_time_zone)r   r  r$   r   r   r   r    s    4z)SeriesDateTimeNamespace.convert_time_zoneuszLiteral[('ns', 'us', 'ms')])r   	time_unitr   c                 C  s4   |dkrd|d}t || j| jjj|S )a  
        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(2001, 1, 1), None, date(2001, 1, 3)]
            >>> s_pd = pd.Series(data, dtype="datetime64[ns]")
            >>> s_pl = pl.Series(data)
            >>> s_pa = pa.chunked_array([data])

            Let's define a dataframe-agnostic function:

            >>> @nw.narwhalify
            ... def func(s):
            ...     return s.dt.timestamp("ms")

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

            >>> func(s_pd)
            0    9.783072e+11
            1             NaN
            2    9.784800e+11
            dtype: float64
            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
            shape: (3,)
            Series: '' [i64]
            [
                    978307200000
                    null
                    978480000000
            ]
            >>> func(s_pa)
            <pyarrow.lib.ChunkedArray object at ...>
            [
              [
                978307200000,
                null,
                978480000000
              ]
            ]
        >   r  nsmsz=invalid `time_unit`

Expected one of {'ns', 'us', 'ms'}, got r   )
ValueErrorr   r/   r!   r   	timestamp)r   r  r$   r   r   r   r    s    2
z!SeriesDateTimeNamespace.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*   )%%%%%%22(%**--*K5;r   )!
__future__r   typingr   r   r   r   r   r   r	   r
   r   Znarwhals.utilsr   typesr   ZnumpynpZpandaspdr8   r<   Ztyping_extensionsr   r   r   Znarwhals.dtypesr   r   r   r   r   r   r   r   r   r   <module>   s^                       2,    g