
    g                        d dl mZ d dlZd dl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 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
deeef         Zer-d dlmZ d dlZd dlmZ d dlm Z  d dl!m"Z" d dl#m$Z$  G d de	      Z%dd	 	 	 	 	 d2dZ&	 d3	 	 	 	 	 	 	 	 	 d4dZ'	 d3	 	 	 	 	 	 	 	 	 	 	 d5dZ(	 d3dd 	 	 	 	 	 	 	 d6d!Z)	 d3dd 	 	 	 	 	 	 	 	 	 d7d"Z*	 d3	 	 	 	 	 	 	 d8d#Z+	 d3	 	 	 	 	 	 	 	 	 d9d$Z,	 	 	 	 	 	 d:d%Z-d;d&Z.d;d'Z/d<d(Z0	 	 	 	 d=d)Z1	 	 	 	 	 	 	 	 d>d*Z2	 	 	 	 	 	 	 	 d>d+Z3	 	 	 	 	 	 	 	 d?d,Z4	 	 	 	 	 	 	 	 d?d-Z5	 	 	 	 	 	 	 	 d>d.Z6	 	 	 	 	 	 	 	 d>d/Z7	 	 	 	 	 	 	 	 d?d0Z8	 	 	 	 	 	 	 	 d?d1Z9y)@    )annotationsN)TYPE_CHECKING)Any)Iterable)Literal)Protocol)TypeVar)Union)"broadcast_align_and_extract_native)	DataFrame)	LazyFrame)from_native)Implementation)Version)parse_version)validate_lazinessFrameT)bound)
ModuleType)DTypeSchemaSeries)IntoSeriesTc                      e Zd Z	 d	 	 	 ddZy)ArrowStreamExportableNc                     y N )selfrequested_schemas     G/var/www/openai/venv/lib/python3.12/site-packages/narwhals/functions.py__arrow_c_stream__z(ArrowStreamExportable.__arrow_c_stream__'   s        r   )r"   zobject | Nonereturnobject)__name__
__module____qualname__r$   r    r%   r#   r   r   &   s    48	$1		r%   r   verticalhowc                  |dvrd}t        |      | sd}t        |      t        |       } t        |        | d   }|j	                         }|j                  |j                  | D cg c]  }|j                   c}|            S c c}w )u^  Concatenate multiple DataFrames, LazyFrames into a single entity.

    Arguments:
        items: DataFrames, LazyFrames to concatenate.
        how: concatenating strategy:

            - vertical: Concatenate vertically. Column names must match.
            - horizontal: Concatenate horizontally. If lengths don't match, then
                missing rows are filled with null values.
            - diagonal: Finds a union between the column schemas and fills missing column
                values with null.

    Returns:
        A new DataFrame, Lazyframe resulting from the concatenation.

    Raises:
        TypeError: The items to concatenate should either all be eager, or all lazy

    Examples:
        Let's take an example of vertical concatenation:

        >>> import pandas as pd
        >>> import polars as pl
        >>> import narwhals as nw
        >>> data_1 = {"a": [1, 2, 3], "b": [4, 5, 6]}
        >>> data_2 = {"a": [5, 2], "b": [1, 4]}

        >>> df_pd_1 = pd.DataFrame(data_1)
        >>> df_pd_2 = pd.DataFrame(data_2)
        >>> df_pl_1 = pl.DataFrame(data_1)
        >>> df_pl_2 = pl.DataFrame(data_2)

        Let's define a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def agnostic_vertical_concat(df1, df2):
        ...     return nw.concat([df1, df2], how="vertical")

        >>> agnostic_vertical_concat(df_pd_1, df_pd_2)
           a  b
        0  1  4
        1  2  5
        2  3  6
        0  5  1
        1  2  4
        >>> agnostic_vertical_concat(df_pl_1, df_pl_2)
        shape: (5, 2)
        ┌─────┬─────┐
        │ a   ┆ b   │
        │ --- ┆ --- │
        │ i64 ┆ i64 │
        ╞═════╪═════╡
        │ 1   ┆ 4   │
        │ 2   ┆ 5   │
        │ 3   ┆ 6   │
        │ 5   ┆ 1   │
        │ 2   ┆ 4   │
        └─────┴─────┘

        Let's look at case a for horizontal concatenation:

        >>> import pandas as pd
        >>> import polars as pl
        >>> import narwhals as nw
        >>> data_1 = {"a": [1, 2, 3], "b": [4, 5, 6]}
        >>> data_2 = {"c": [5, 2], "d": [1, 4]}

        >>> df_pd_1 = pd.DataFrame(data_1)
        >>> df_pd_2 = pd.DataFrame(data_2)
        >>> df_pl_1 = pl.DataFrame(data_1)
        >>> df_pl_2 = pl.DataFrame(data_2)

        Defining a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def agnostic_horizontal_concat(df1, df2):
        ...     return nw.concat([df1, df2], how="horizontal")

        >>> agnostic_horizontal_concat(df_pd_1, df_pd_2)
           a  b    c    d
        0  1  4  5.0  1.0
        1  2  5  2.0  4.0
        2  3  6  NaN  NaN

        >>> agnostic_horizontal_concat(df_pl_1, df_pl_2)
        shape: (3, 4)
        ┌─────┬─────┬──────┬──────┐
        │ a   ┆ b   ┆ c    ┆ d    │
        │ --- ┆ --- ┆ ---  ┆ ---  │
        │ i64 ┆ i64 ┆ i64  ┆ i64  │
        ╞═════╪═════╪══════╪══════╡
        │ 1   ┆ 4   ┆ 5    ┆ 1    │
        │ 2   ┆ 5   ┆ 2    ┆ 4    │
        │ 3   ┆ 6   ┆ null ┆ null │
        └─────┴─────┴──────┴──────┘

        Let's look at case a for diagonal concatenation:

        >>> import pandas as pd
        >>> import polars as pl
        >>> import narwhals as nw
        >>> data_1 = {"a": [1, 2], "b": [3.5, 4.5]}
        >>> data_2 = {"a": [3, 4], "z": ["x", "y"]}

        >>> df_pd_1 = pd.DataFrame(data_1)
        >>> df_pd_2 = pd.DataFrame(data_2)
        >>> df_pl_1 = pl.DataFrame(data_1)
        >>> df_pl_2 = pl.DataFrame(data_2)

        Defining a dataframe-agnostic function:

        >>> @nw.narwhalify
        ... def agnostic_diagonal_concat(df1, df2):
        ...     return nw.concat([df1, df2], how="diagonal")

        >>> agnostic_diagonal_concat(df_pd_1, df_pd_2)
           a    b    z
        0  1  3.5  NaN
        1  2  4.5  NaN
        0  3  NaN    x
        1  4  NaN    y

        >>> agnostic_diagonal_concat(df_pl_1, df_pl_2)
        shape: (4, 3)
        ┌─────┬──────┬──────┐
        │ a   ┆ b    ┆ z    │
        │ --- ┆ ---  ┆ ---  │
        │ i64 ┆ f64  ┆ str  │
        ╞═════╪══════╪══════╡
        │ 1   ┆ 3.5  ┆ null │
        │ 2   ┆ 4.5  ┆ null │
        │ 3   ┆ null ┆ x    │
        │ 4   ┆ null ┆ y    │
        └─────┴──────┴──────┘
    >   diagonalr+   
horizontalzDOnly vertical, horizontal and diagonal concatenations are supported.zNo items to concatenater   r,   )NotImplementedError
ValueErrorlistr   __narwhals_namespace___from_compliant_dataframeconcat_compliant_frame)itemsr-   msg
first_itemplxdfs         r#   r6   r6   ,   s    X 88T!#&&'oKEeqJ

+
+
-C//

%8%BB''%8c
B 8s   &Bc               >    t        | |||t        j                        S )a  Instantiate Narwhals Series from iterable (e.g. list or array).

    Arguments:
        name: Name of resulting Series.
        values: Values of make Series from.
        dtype: (Narwhals) dtype. If not provided, the native library
            may auto-infer it from `values`.
        native_namespace: The native library to use for DataFrame creation.

    Returns:
        A new Series

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> from narwhals.typing import IntoFrameT, IntoSeriesT
        >>> data = {"a": [1, 2, 3], "b": [4, 5, 6]}

        Let's define a dataframe-agnostic function:

        >>> def agnostic_new_series(df_native: IntoFrameT) -> IntoSeriesT:
        ...     values = [4, 1, 2, 3]
        ...     native_namespace = nw.get_native_namespace(df_native)
        ...     return nw.new_series(
        ...         name="a",
        ...         values=values,
        ...         dtype=nw.Int32,
        ...         native_namespace=native_namespace,
        ...     ).to_native()

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

        >>> agnostic_new_series(pd.DataFrame(data))
        0    4
        1    1
        2    2
        3    3
        Name: a, dtype: int32
        >>> agnostic_new_series(pl.DataFrame(data))  # doctest: +NORMALIZE_WHITESPACE
        shape: (4,)
        Series: 'a' [i32]
        [
           4
           1
           2
           3
        ]
        >>> agnostic_new_series(pa.table(data))
        <pyarrow.lib.ChunkedArray object at ...>
        [
          [
            4,
            1,
            2,
            3
          ]
        ]
    native_namespaceversion)_new_series_implr   MAIN)namevaluesdtyper?   s       r#   
new_seriesrF      s%    F ) r%   c                  t        j                  |      }|t         j                  u r*|rddlm}  |||      }nd }|j                  | ||      }n|t         j                  t         j                  t         j                  hv r>|r'ddl	m}	 t        |j                        }
 |	|d ||
|      }|j                  || |      }nl|t         j                  u r'|rddlm}  |||      }|j                  |g|      }n3|t         j                  u rd}t!        |      	 |j#                  | ||      }t'        |d	
      j)                  |       S # t$        $ r}d}t%        |      |d }~ww xY w)Nr   narwhals_to_native_dtyper@   )rC   rD   rE   )rC   rE   )typezGDask support in Narwhals is lazy-only, so `new_series` is not supportedz@Unknown namespace is expected to implement `Series` constructor.Tseries_only)r   from_native_namespacePOLARSnarwhals._polars.utilsrI   r   PANDASMODINCUDFnarwhals._pandas_like.utilsr   __version__PYARROWnarwhals._arrow.utilschunked_arrayDASKr1   rF   AttributeErrorr   alias)rC   rD   rE   r?   r@   implementationpolars_narwhals_to_native_dtypedtype_plnative_series$pandas_like_narwhals_to_native_dtypebackend_versionarrow_narwhals_to_native_dtyper9   es                 r#   rA   rA     s{    $99:JKN... 7ugNHH(//T&PX/Y	 

  ,,<,H,HIO8t^_gE )//T/O	>11	1 35'JE(66xe6L	>..	.Z!#&&	- -77feLM }$7==dCC  	-TC %1,	-s   E	 		E%E  E%)r?   c               <    t        | ||t        j                        S )u  Instantiate DataFrame from dictionary.

    Indexes (if present, for pandas-like backends) are aligned following
    the [left-hand-rule](../pandas_like_concepts/pandas_index.md/).

    Notes:
        For pandas-like dataframes, conversion to schema is applied after dataframe
        creation.

    Arguments:
        data: Dictionary to create DataFrame from.
        schema: The DataFrame schema as Schema or dict of {name: type}.
        native_namespace: The native library to use for DataFrame creation. Only
            necessary if inputs are not Narwhals Series.

    Returns:
        A new DataFrame.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> from narwhals.typing import IntoFrameT
        >>> data = {"a": [1, 2, 3], "b": [4, 5, 6]}

        Let's create a new dataframe of the same class as the dataframe we started with, from a dict of new data:

        >>> def agnostic_from_dict(df_native: IntoFrameT) -> IntoFrameT:
        ...     new_data = {"c": [5, 2], "d": [1, 4]}
        ...     native_namespace = nw.get_native_namespace(df_native)
        ...     return nw.from_dict(new_data, native_namespace=native_namespace).to_native()

        Let's see what happens when passing pandas, Polars or PyArrow input:

        >>> agnostic_from_dict(pd.DataFrame(data))
           c  d
        0  5  1
        1  2  4
        >>> agnostic_from_dict(pl.DataFrame(data))
        shape: (2, 2)
        ┌─────┬─────┐
        │ c   ┆ d   │
        │ --- ┆ --- │
        │ i64 ┆ i64 │
        ╞═════╪═════╡
        │ 5   ┆ 1   │
        │ 2   ┆ 4   │
        └─────┴─────┘
        >>> agnostic_from_dict(pa.table(data))
        pyarrow.Table
        c: int64
        d: int64
        ----
        c: [[5,2]]
        d: [[1,4]]
    r>   )_from_dict_implr   rB   dataschemar?   s      r#   	from_dictri   O  s"    ~ )	 r%   c                  ddl m} ddlm} | sd}t	        |      |k| j                         D ]   }t        ||      s|j                         } n d}t        |      | j                         D 	ci c]  \  }}	| ||	d       } }}	t        j                  |      }
|
t        j                  u rK|r2ddlm} |j                         D ci c]  \  }}| |||	       }}}nd }|j                  | |
      }n|
t        j                   t        j"                  t        j$                  hv ri }d }| j                         D ]T  \  }}t        ||j                        r4t'        |d      j(                  }||}|||<   =t+        ||      d   ||<   P|||<   V |j,                  j                  |      }|rddlm} t1        |j2                        }|j4                  j                         D ci c]  \  }}| |||   ||
||       }}}|j7                  |      }n}|
t        j8                  u rW|rAddlm} |j=                  |j                         D cg c]  \  }}| |||      f c}}      }|j?                  | |
      }n	 |j                  | |
      }t'        |d      S c c}	}w c c}}w c c}}w c c}}w # t@        $ r}d}tA        |      |d }~ww xY w)Nr   r   )	to_nativez0from_dict cannot be called with empty dictionaryzpCalling `from_dict` without `native_namespace` is only supported if all input values are already Narwhals SeriesT)pass_throughrH   rJ   rh   rL      z@Unknown namespace is expected to implement `from_dict` function.
eager_only)!narwhals.seriesr   narwhals.translaterk   r2   rD   
isinstance__native_namespace__	TypeErrorr8   r   rN   rO   rP   rI   ri   rQ   rR   rS   r   _compliant_seriesr   r   rT   r   rU   dtypesastyperV   rW   rh   tablerZ   )rg   rh   r?   r@   r   rk   r9   valkeyvaluer\   r]   rC   rE   	schema_plnative_framealigned_dataleft_most_seriesr_   compliant_seriesr`   ra   native_typerb   rc   s                            r#   re   re     s1    ',@o;;=C#v&#&#;#;#=  !
 ECC. KO::<X<ZS%Yu488<X#99:JKN... $*<<>#1KD% 5eWMM#1  
 I'11$y1I	 

 "&**,C-)9)@)@A#.!t$## ! $+'7$(5L%(J(*:))L% %2S! #/ (11;;LI ,,<,H,HIO
 *6)<)<)B)B)D	 *E%D+ :4L+~PW  *E	   (..v6L	>11	1 &,, (.||~'5e 9%IJ'5F (--d6-B	- ,55d65JL |55Y YL  	-TC %1,	-s0   1J%J+,J1J7
J= =	KKKc               <    t        | ||t        j                        S )uu  Construct a DataFrame from a NumPy ndarray.

    Notes:
        Only row orientation is currently supported.

        For pandas-like dataframes, conversion to schema is applied after dataframe
        creation.

    Arguments:
        data: Two-dimensional data represented as a NumPy ndarray.
        schema: The DataFrame schema as Schema, dict of {name: type}, or a list of str.
        native_namespace: The native library to use for DataFrame creation.

    Returns:
        A new DataFrame.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> import numpy as np
        >>> from narwhals.typing import IntoFrameT
        >>> data = {"a": [1, 2], "b": [3, 4]}

        Let's create a new dataframe of the same class as the dataframe we started with, from a NumPy ndarray of new data:

        >>> def agnostic_from_numpy(df_native: IntoFrameT) -> IntoFrameT:
        ...     new_data = np.array([[5, 2, 1], [1, 4, 3]])
        ...     df = nw.from_native(df_native)
        ...     native_namespace = nw.get_native_namespace(df)
        ...     return nw.from_numpy(new_data, native_namespace=native_namespace).to_native()

        Let's see what happens when passing pandas, Polars or PyArrow input:

        >>> agnostic_from_numpy(pd.DataFrame(data))
           column_0  column_1  column_2
        0         5         2         1
        1         1         4         3
        >>> agnostic_from_numpy(pl.DataFrame(data))
        shape: (2, 3)
        ┌──────────┬──────────┬──────────┐
        │ column_0 ┆ column_1 ┆ column_2 │
        │ ---      ┆ ---      ┆ ---      │
        │ i64      ┆ i64      ┆ i64      │
        ╞══════════╪══════════╪══════════╡
        │ 5        ┆ 2        ┆ 1        │
        │ 1        ┆ 4        ┆ 3        │
        └──────────┴──────────┴──────────┘
        >>> agnostic_from_numpy(pa.table(data))
        pyarrow.Table
        column_0: int64
        column_1: int64
        column_2: int64
        ----
        column_0: [[5,1]]
        column_1: [[2,4]]
        column_2: [[1,3]]

        Let's specify the column names:

        >>> def agnostic_from_numpy(df_native: IntoFrameT) -> IntoFrameT:
        ...     new_data = np.array([[5, 2, 1], [1, 4, 3]])
        ...     schema = ["c", "d", "e"]
        ...     df = nw.from_native(df_native)
        ...     native_namespace = nw.get_native_namespace(df)
        ...     return nw.from_numpy(
        ...         new_data, native_namespace=native_namespace, schema=schema
        ...     ).to_native()

        Let's see the modified outputs:

        >>> agnostic_from_numpy(pd.DataFrame(data))
           c  d  e
        0  5  2  1
        1  1  4  3
        >>> agnostic_from_numpy(pl.DataFrame(data))
        shape: (2, 3)
        ┌─────┬─────┬─────┐
        │ c   ┆ d   ┆ e   │
        │ --- ┆ --- ┆ --- │
        │ i64 ┆ i64 ┆ i64 │
        ╞═════╪═════╪═════╡
        │ 5   ┆ 2   ┆ 1   │
        │ 1   ┆ 4   ┆ 3   │
        └─────┴─────┴─────┘
        >>> agnostic_from_numpy(pa.table(data))
        pyarrow.Table
        c: int64
        d: int64
        e: int64
        ----
        c: [[5,1]]
        d: [[2,4]]
        e: [[1,3]]

        Let's modify the function so that it specifies the schema:

        >>> def agnostic_from_numpy(df_native: IntoFrameT) -> IntoFrameT:
        ...     new_data = np.array([[5, 2, 1], [1, 4, 3]])
        ...     schema = {"c": nw.Int16(), "d": nw.Float32(), "e": nw.Int8()}
        ...     df = nw.from_native(df_native)
        ...     native_namespace = nw.get_native_namespace(df)
        ...     return nw.from_numpy(
        ...         new_data, native_namespace=native_namespace, schema=schema
        ...     ).to_native()

        Let's see the outputs:

        >>> agnostic_from_numpy(pd.DataFrame(data))
           c    d  e
        0  5  2.0  1
        1  1  4.0  3
        >>> agnostic_from_numpy(pl.DataFrame(data))
        shape: (2, 3)
        ┌─────┬─────┬─────┐
        │ c   ┆ d   ┆ e   │
        │ --- ┆ --- ┆ --- │
        │ i16 ┆ f32 ┆ i8  │
        ╞═════╪═════╪═════╡
        │ 5   ┆ 2.0 ┆ 1   │
        │ 1   ┆ 4.0 ┆ 3   │
        └─────┴─────┴─────┘
        >>> agnostic_from_numpy(pa.table(data))
        pyarrow.Table
        c: int16
        d: float
        e: int8
        ----
        c: [[5,1]]
        d: [[2,4]]
        e: [[1,3]]
    r>   )_from_numpy_implr   rB   rf   s      r#   
from_numpyr     s"    V )	 r%   c                  ddl m} | j                  dk7  rd}t        |      t	        j
                  |      }|t        j                  u rt        |t        |f      r2ddl	m
} |j                         D 	ci c]  \  }}	| ||	|       }}}	n>||j                  |       }
n*t        |t              sdt        |       d}t        |      |j                  | |	      }
n|t        j                   t        j"                  t        j$                  hv rt        |t        |f      r}ddlm
} t)        |j*                        }|j                         D ci c]  \  }}| |||   ||||       }}}|j-                  | |j/                         
      j1                  |      }
nt        |t              r|j-                  | |
      }
n|E|j-                  | t3        | j4                  d         D cg c]  }dt7        |      z    c}
      }
nrdt        |       d}t        |      |t        j8                  u r1| j:                  D cg c]  }|j=                  |       }}t        |t        |f      r_ddlm
} |jA                  |j                         D 	cg c]  \  }}	| ||	|      f c}	}      }|jB                  jE                  ||	      }
nt        |t              r|jB                  jE                  ||      }
n~|N|jB                  jE                  |t3        | j4                  d         D cg c]  }dt7        |      z    c}      }
n.dt        |       d}t        |      	 |j                  | |	      }
tI        |
d      S c c}	}w c c}}w c c}w c c}w c c}	}w c c}w # tF        $ r}d}tG        |      |d }~ww xY w)Nr   r      z)`from_numpy` only accepts 2D numpy arraysrH   rJ   zb`schema` is expected to be one of the following types: dict[str, DType] | Schema | list[str]. Got .rm   )columnsrn   column_)nameszAUnknown namespace is expected to implement `from_numpy` function.Tro   )%narwhals.schemar   ndimr2   r   rN   rO   rs   dictrP   rI   r8   r   r3   rK   ru   rQ   rR   rS   rT   r   rU   r   keysrx   rangeshapestrrV   TarrayrW   rh   Tablefrom_arraysrZ   r   )rg   rh   r?   r@   r   r9   r\   r]   rC   rE   r~   r`   ra   r   xrz   	pa_arraysrb   rc   s                      r#   r   r     s    'yyA~9o#99:JKN...ftVn- $*<<>#1KD% 5eWMM#1   ^+66t<LFD)F|nA' 
 C. '2242G	 

 ftVn- ,,<,H,HIO
 *0	 *8%D+ :4L+~PW  *8	   ,55dFKKM5RYYL %+55dF5KL^+555A;OP;Oay3q61;OP 6 L
F|nA' 
 C. 	>11	1<@FFCFS%++C0F	CftVn- &,, (.||~'5e 9%IJ'5F ,11==iPV=WL%+11==iv=VL^+11==eDJJqM>R!S>R)c!f"4>R!S > L
F|nA' 
 C. 	- ,66tF6KL |55i4 Q D "T  	-UC %1,	-s<   5NN/N
	NN#
4N)
-N. .	O
7OO
c               >   t        | d      sdt        |        d}t        |      t        j                  |      }|t        j
                  u r+t        |j                        dk\  r|j                  |       } nX|t        j                  t        j                  t        j                  t        j
                  hv r	 ddl}t        |j                        dk  rd| }t        |      d|j                  |       }|t        j                  u r|j                         } n|t        j                  u rdd	lm}  ||      } n|t        j                  u r|j                  j#                  |      } ng|t        j
                  u r|j#                  |      } nCd
}t%        |      |t        j&                  u r|j                  |       } n	 |j                  |       } t+        | d      S # t        $ r}d| }t        |      |d}~ww xY w# t(        $ r}d}t)        |      |d}~ww xY w)a  Construct a DataFrame from an object which supports the PyCapsule Interface.

    Arguments:
        native_frame: Object which implements `__arrow_c_stream__`.
        native_namespace: The native library to use for DataFrame creation.

    Returns:
        A new DataFrame.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> from narwhals.typing import IntoFrameT
        >>> data = {"a": [1, 2, 3], "b": [4, 5, 6]}

        Let's define a dataframe-agnostic function which creates a PyArrow
        Table.

        >>> def agnostic_to_arrow(df_native: IntoFrameT) -> IntoFrameT:
        ...     df = nw.from_native(df_native)
        ...     return nw.from_arrow(df, native_namespace=pa).to_native()

        Let's see what happens when passing pandas / Polars input:

        >>> agnostic_to_arrow(pd.DataFrame(data))
        pyarrow.Table
        a: int64
        b: int64
        ----
        a: [[1,2,3]]
        b: [[4,5,6]]
        >>> agnostic_to_arrow(pl.DataFrame(data))
        pyarrow.Table
        a: int64
        b: int64
        ----
        a: [[1,2,3]]
        b: [[4,5,6]]
    r$   zGiven object of type z% does not support PyCapsule interface)rn      r   Nz@PyArrow>=14.0.0 is required for `from_arrow` for object of type )   r   )
from_arrowzCcongratulations, you entered unrecheable code - please report a bugzuUnknown namespace is expected to implement `DataFrame` class which accepts object which supports PyCapsule Interface.Tro   )hasattrrK   ru   r   rN   rO   r   rU   r   rQ   rR   rS   pyarrowModuleNotFoundErrorry   	to_pandasmodin.pandas.utilsr   AssertionErrorrV   rZ   r   )	r~   r?   r9   r\   paexctblr   rc   s	            r#   r   r     s	   X <!56%d<&8%99^_n#99:JKN...=$$4	4 (11,?		 
	4  (72TUeTfgC%c*4hh|$^222==?L~3335%c?L~222+55@@EL~444+66s;LWC %%	>11	1'--l;	- ,55lCL |55? # 	4TUeTfgC%c*3	48  	- JC %1,	-s0   :G  H  	G='G88G= 	H	HHc                     t         j                  j                  dd      } d| fdt         j                  fdt	        j                         ff}t        |      S )zSystem information.

    Returns system and Python version information

    Copied from sklearn

    Returns:
        Dictionary with system info.
    
 python
executablemachine)sysr@   replacer   platformr   )r   blobs     r#   _get_sys_infor   Y  sT     [[  s+F 
6	s~~&	H%%'(D :r%   c                 |    d} ddl m} d|i}ddlm} ddlm} | D ]  }	  ||      ||<    |S # |$ r d||<   Y w xY w)	a  Overview of the installed version of main dependencies.

    This function does not import the modules to collect the version numbers
    but instead relies on standard Python package metadata.

    Returns version information on relevant Python libraries

    This function and show_versions were copied from sklearn and adapted

    Returns:
        Mapping from dependency to version.
    )pandaspolarscudfmodinr   numpyrn   )rU   narwhalsr   )PackageNotFoundErrorrJ    )r   rU   importlib.metadatar   r@   )depsrU   	deps_infor   r@   modnames         r#   _get_deps_infor   n  se    D  	KI 8*	$!(!1Ig 
  $ 	$!#Ig	$s   .
;;c                     t               } t               }t        d       | j                         D ]  \  }}t        |dd|         t        d       |j                         D ]  \  }}t        |dd|         y)zPrint useful debugging information.

    Examples:
        >>> from narwhals import show_versions
        >>> show_versions()  # doctest: +SKIP
    z
System:z>10z: z
Python dependencies:z>13N)r   r   printr8   )sys_infor   kstats       r#   show_versionsr     sz     H I	+>>#43r$ ! $ 

"#??$43r$ ! %r%   c                    | j                   S )a  Level of support Narwhals has for current object.

    Arguments:
        obj: Dataframe or Series.

    Returns:
        This can be one of:

            - 'full': full Narwhals API support
            - 'lazy': only lazy operations are supported. This excludes anything
              which involves iterating over rows in Python.
            - 'interchange': only metadata operations are supported (`df.schema`)
    )_level)objs    r#   	get_levelr     s      ::r%   c                   t        | fd|i|S )u  Read a CSV file into a DataFrame.

    Arguments:
        source: Path to a file.
        native_namespace: The native library to use for DataFrame creation.
        kwargs: Extra keyword arguments which are passed to the native CSV reader.
            For example, you could use
            `nw.read_csv('file.csv', native_namespace=pd, engine='pyarrow')`.

    Returns:
        DataFrame.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> from narwhals.typing import IntoDataFrame
        >>> from types import ModuleType

        Let's create an agnostic function that reads a csv file with a specified native namespace:

        >>> def agnostic_read_csv(native_namespace: ModuleType) -> IntoDataFrame:
        ...     return nw.read_csv("file.csv", native_namespace=native_namespace).to_native()

        Then we can read the file by passing pandas, Polars or PyArrow namespaces:

        >>> agnostic_read_csv(native_namespace=pd)  # doctest:+SKIP
           a  b
        0  1  4
        1  2  5
        2  3  6
        >>> agnostic_read_csv(native_namespace=pl)  # doctest:+SKIP
        shape: (3, 2)
        ┌─────┬─────┐
        │ a   ┆ b   │
        │ --- ┆ --- │
        │ i64 ┆ i64 │
        ╞═════╪═════╡
        │ 1   ┆ 4   │
        │ 2   ┆ 5   │
        │ 3   ┆ 6   │
        └─────┴─────┘
        >>> agnostic_read_csv(native_namespace=pa)  # doctest:+SKIP
        pyarrow.Table
        a: int64
        b: int64
        ----
        a: [[1,2,3]]
        b: [[4,5,6]]
    r?   )_read_csv_implsourcer?   kwargss      r#   read_csvr     s    r &N3CNvNNr%   c                  t        j                  |      }|t         j                  t         j                  t         j                  t         j
                  fv r |j                  | fi |}nA|t         j                  u rddlm	}  |j                  | fi |}n	  |j                  dd| i|}t        |d      S # t        $ r}d}t        |      |d }~ww xY w)Nr   csvr   z?Unknown namespace is expected to implement `read_csv` function.Tro   r    )r   rN   rO   rQ   rR   rS   r   rV   r   r   rZ   r   r   r?   r   r\   r~   r   rc   r9   s           r#   r   r     s     $99:JKN	  1'00B6B	>11	1#s||F5f5	- 5+44MFMfML |55  	-SC %1,	-s   B8 8	CCCc                   t        | fd|i|S )u  Lazily read from a CSV file.

    For the libraries that do not support lazy dataframes, the function reads
    a csv file eagerly and then converts the resulting dataframe to a lazyframe.

    Arguments:
        source: Path to a file.
        native_namespace: The native library to use for DataFrame creation.
        kwargs: Extra keyword arguments which are passed to the native CSV reader.
            For example, you could use
            `nw.scan_csv('file.csv', native_namespace=pd, engine='pyarrow')`.

    Returns:
        LazyFrame.

    Examples:
        >>> import dask.dataframe as dd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> from narwhals.typing import IntoFrame
        >>> from types import ModuleType

        Let's create an agnostic function that lazily reads a csv file with a specified native namespace:

        >>> def agnostic_scan_csv(native_namespace: ModuleType) -> IntoFrame:
        ...     return nw.scan_csv("file.csv", native_namespace=native_namespace).to_native()

        Then we can read the file by passing, for example, Polars or Dask namespaces:

        >>> agnostic_scan_csv(native_namespace=pl).collect()  # doctest:+SKIP
        shape: (3, 2)
        ┌─────┬─────┐
        │ a   ┆ b   │
        │ --- ┆ --- │
        │ i64 ┆ i64 │
        ╞═════╪═════╡
        │ 1   ┆ 4   │
        │ 2   ┆ 5   │
        │ 3   ┆ 6   │
        └─────┴─────┘
        >>> agnostic_scan_csv(native_namespace=dd).compute()  # doctest:+SKIP
           a  b
        0  1  4
        1  2  5
        2  3  6
    r?   )_scan_csv_implr   s      r#   scan_csvr     s    d &N3CNvNNr%   c               0   t        j                  |      }|t         j                  u r |j                  | fi |}n|t         j                  t         j
                  t         j                  t         j                  t         j                  fv r |j                  | fi |}nA|t         j                  u rddlm}  |j                  | fi |}n	  |j                  dd| i|}t        |      j                         S # t        $ r}d}t        |      |d }~ww xY w)Nr   r   r   z?Unknown namespace is expected to implement `scan_csv` function.r    )r   rN   rO   r   rQ   rR   rS   rY   DUCKDBr   rV   r   r   rZ   r   lazyr   s           r#   r   r   F  s    $99:JKN...0'00B6B	 
 1'00B6B	>11	1#s||F5f5	- 5+44MFMfML |$))++  	-SC %1,	-   C9 9	DDDc                   t        | fd|i|S )u  Read into a DataFrame from a parquet file.

    Arguments:
        source: Path to a file.
        native_namespace: The native library to use for DataFrame creation.
        kwargs: Extra keyword arguments which are passed to the native parquet reader.
            For example, you could use
            `nw.read_parquet('file.parquet', native_namespace=pd, engine='pyarrow')`.

    Returns:
        DataFrame.

    Examples:
        >>> import pandas as pd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> from narwhals.typing import IntoDataFrame
        >>> from types import ModuleType

        Let's create an agnostic function that reads a parquet file with a specified native namespace:

        >>> def agnostic_read_parquet(native_namespace: ModuleType) -> IntoDataFrame:
        ...     return nw.read_parquet(
        ...         "file.parquet", native_namespace=native_namespace
        ...     ).to_native()

        Then we can read the file by passing pandas, Polars or PyArrow namespaces:

        >>> agnostic_read_parquet(native_namespace=pd)  # doctest:+SKIP
           a  b
        0  1  4
        1  2  5
        2  3  6
        >>> agnostic_read_parquet(native_namespace=pl)  # doctest:+SKIP
        shape: (3, 2)
        ┌─────┬─────┐
        │ a   ┆ b   │
        │ --- ┆ --- │
        │ i64 ┆ i64 │
        ╞═════╪═════╡
        │ 1   ┆ 4   │
        │ 2   ┆ 5   │
        │ 3   ┆ 6   │
        └─────┴─────┘
        >>> agnostic_read_parquet(native_namespace=pa)  # doctest:+SKIP
        pyarrow.Table
        a: int64
        b: int64
        ----
        a: [[1,2,3]]
        b: [[4,5,6]]
    r?   )_read_parquet_implr   s      r#   read_parquetr   c  s    v fR7GR6RRr%   c                  t        j                  |      }|t         j                  t         j                  t         j                  t         j
                  t         j                  fv r |j                  | fi |}nA|t         j                  u rdd l	m
}  |j                  | fi |}n	  |j                  dd| i|}t        |d      S # t        $ r}d}t        |      |d }~ww xY w)Nr   r   zCUnknown namespace is expected to implement `read_parquet` function.Tro   r    )r   rN   rO   rQ   rR   rS   r   r   rV   pyarrow.parquetparquet
read_tablerZ   r   r   r?   r   r\   r~   pqrc   r9   s           r#   r   r     s     $99:JKN  5'44VFvF	>11	1$$r}}V6v6	- 9+88QQ&QL |55  	-WC %1,	-s   &C 	C#CC#c                   t        | fd|i|S )u  Lazily read from a parquet file.

    For the libraries that do not support lazy dataframes, the function reads
    a parquet file eagerly and then converts the resulting dataframe to a lazyframe.

    Arguments:
        source: Path to a file.
        native_namespace: The native library to use for DataFrame creation.
        kwargs: Extra keyword arguments which are passed to the native parquet reader.
            For example, you could use
            `nw.scan_parquet('file.parquet', native_namespace=pd, engine='pyarrow')`.

    Returns:
        LazyFrame.

    Examples:
        >>> import dask.dataframe as dd
        >>> import polars as pl
        >>> import pyarrow as pa
        >>> import narwhals as nw
        >>> from narwhals.typing import IntoFrame
        >>> from types import ModuleType

        Let's create an agnostic function that lazily reads a parquet file with a specified native namespace:

        >>> def agnostic_scan_parquet(native_namespace: ModuleType) -> IntoFrame:
        ...     return nw.scan_parquet(
        ...         "file.parquet", native_namespace=native_namespace
        ...     ).to_native()

        Then we can read the file by passing, for example, Polars or Dask namespaces:

        >>> agnostic_scan_parquet(native_namespace=pl).collect()  # doctest:+SKIP
        shape: (3, 2)
        ┌─────┬─────┐
        │ a   ┆ b   │
        │ --- ┆ --- │
        │ i64 ┆ i64 │
        ╞═════╪═════╡
        │ 1   ┆ 4   │
        │ 2   ┆ 5   │
        │ 3   ┆ 6   │
        └─────┴─────┘
        >>> agnostic_scan_parquet(native_namespace=dd).compute()  # doctest:+SKIP
           a  b
        0  1  4
        1  2  5
        2  3  6
    r?   )_scan_parquet_implr   s      r#   scan_parquetr     s    h fR7GR6RRr%   c               0   t        j                  |      }|t         j                  u r |j                  | fi |}n|t         j                  t         j
                  t         j                  t         j                  t         j                  fv r |j                  | fi |}nA|t         j                  u rdd lm}  |j                  | fi |}n	  |j                  dd| i|}t        |      j!                         S # t        $ r}d}t        |      |d }~ww xY w)Nr   r   zCUnknown namespace is expected to implement `scan_parquet` function.r    )r   rN   rO   r   rQ   rR   rS   rY   r   r   rV   r   r   r   rZ   r   r   r   s           r#   r   r     s    $99:JKN...4'44VFvF	 
 5'44VFvF	>11	1$$r}}V6v6	- 9+88QQ&QL |$))++  	-WC %1,	-r   )r8   zIterable[FrameT]r-   z-Literal['horizontal', 'vertical', 'diagonal']r&   r   r   )
rC   r   rD   r   rE   DType | type[DType] | Noner?   r   r&   Series[Any])rC   r   rD   r   rE   r   r?   r   r@   r   r&   r   )rg   dict[str, Any]rh    dict[str, DType] | Schema | Noner?   ModuleType | Noner&   DataFrame[Any])
rg   r   rh   r   r?   r   r@   r   r&   r   )rg   
np.ndarrayrh   ,dict[str, DType] | Schema | list[str] | Noner?   r   r&   r   )
rg   r   rh   r   r?   r   r@   r   r&   r   )r~   r   r?   r   r&   r   )r&   zdict[str, str])r&   None)r   z5DataFrame[Any] | LazyFrame[Any] | Series[IntoSeriesT]r&   z&Literal['full', 'lazy', 'interchange'])r   r   r?   r   r   r   r&   r   )r   r   r?   r   r   r   r&   zLazyFrame[Any]):
__future__r   r   r   typingr   r   r   r   r   r	   r
   rT   r   narwhals.dataframer   r   rr   r   narwhals.utilsr   r   r   r   r   typesr   r   npnarwhals.dtypesr   r   r   rq   r   narwhals.typingr   r   r6   rF   rA   ri   re   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r%   r#   <module>r      s   "  
         J ( ( * ) " ( ,
 
y)';!<	=  %&&+  :DXX 
7X 	X| )-I
II &I
 !I I^ )-9D
9D9D &9D
 !9D 9D 9D| 04D +/	D
D,D (	D
 DR 04a6 +/	a6
a6,a6 (	a6
 a6 a6L <@P
P8P !	P
 Pj <@h6
h68h6 !	h6
 h6 h6V^6'^6>H^6^6B*$N"&	>+&9O9O !9O 	9O
 9Ox66&06<?6642O2O&02O<?2O2Oj,,&0,<?,,:;S;S !;S 	;S
 ;S|66&06<?6664S4S&04S<?4S4Sn,,&0,<?,,r%   