
    /_i*<                       U d Z ddlmZ ddlmZmZmZmZ ddlm	Z	m
Z
mZmZmZmZ ddlmZmZmZmZmZmZmZmZmZmZmZ e	r@ddlZddlZddlZddl Z!ddl"m#Z$ ddl%m&Z&m'Z'm(Z( e$e
e
e
e
e
f   Z) ed	      Z*d
Z+de,d<   e
Z-de,d<   g dZ. G d de      Z/ G d dee/e      Z0 G d de/e      Z1 G d deee
   e      Z2 G d dee      Z3 G d de0e3e      Z4 G d de2e3e      Z5 G d de1e      Z6 G d d e4e      Z7 G d! d"e5e      Z8 G d# d$e/e      Z9 G d% d&e4e      Z: G d' d(e5e      Z; G d) d*e1e      Z<d+Z=de,d,<   d-Z>de,d.<   d/Z?de,d0<   d1Z@de,d2<   d3ZAde,d4<   d5ZBde,d6<   d7ZCde,d8<   d9ZDde,d:<   d;ZEde,d<<   d=ZFde,d><   e<ZGde,d?<   e<ZHde,d@<   dAZIde,dB<   dCZJde,dD<   dEZKde,dF<   dGZLde,dH<   e0ZMde,dI<   	 ee1e9f   ZNde,dJ<   eeMeNf   ZOde,dK<   	 e2ZPde,dL<   	  edMeON      ZQ	  edOeMN      ZR	  edPeNN      ZS edQePN      ZT	 dadRZUdbdSZV edTe      ZWeZXdUe,dV<   eZYdWe,dX<    edYe      ZZ edZe      Z[ ed[e      Z\dcd\Z]ddd]Z^ded^Z_dfd_Z`dgd`Zay)hu  The home for *mostly* [structural] counterparts to [nominal] native types.

If you find yourself being yelled at by a typechecker and ended up here - **do not fear!**

We have 5 funky flavors, which tackle two different problem spaces.

How do we describe [Native types] when ...
- ... **wrapping in** a [Narwhals type]?
- ... **matching to** an [`Implementation`]?

## Wrapping in a Narwhals type
[//]: # (TODO @dangotbanned: Replace `Thing` with a better name)

The following examples use the placeholder type `Thing` which represents one of:
- `DataFrame`: (Eager) 2D data structure representing data as a table with rows and columns.
- `LazyFrame`: (Lazy) Computation graph/query against a DataFrame/database.
- `Series`: 1D data structure representing a single column.

Our goal is to **wrap** a *partially-unknown* native object **in** a [generic class]:

    def wrapping_in_df(native: IntoDataFrameT) -> DataFrame[IntoDataFrameT]: ...
    def wrapping_in_lf(native: IntoLazyFrameT) -> LazyFrame[IntoLazyFrameT]: ...
    def wrapping_in_ser(native: IntoSeriesT) -> Series[IntoSeriesT]: ...

### (1) `Native<Thing>`
Minimal [`Protocol`]s that are [assignable to] *almost any* supported native type of that group:

    class NativeThing(Protocol):
        def something_common(self, *args: Any, **kwargs: Any) -> Any: ...

Note:
    This group is primarily a building block for more useful types.

### (2) `Into<Thing>`
*Publicly* exported [`TypeAlias`]s of **(1)**:

    IntoThing: TypeAlias = NativeThing

**But**, occasionally, there'll be an edge-case which we can spell like:

    IntoThing: TypeAlias = Union[<type that does not fit the protocol>, NativeThing]

Tip:
    Reach for these when there **isn't a need to preserve** the original native type.

### (3) `Into<Thing>T`
*Publicly* exported [`TypeVar`]s, bound to **(2)**:

    IntoThingT = TypeVar("IntoThingT", bound=IntoThing)

Important:
    In most situations, you'll want to use these as they **do preserve** the original native type.

Putting it all together, we can now add a *narwhals-level* wrapper:

    class Thing(Generic[IntoThingT]):
        def to_native(self) -> IntoThingT: ...

## Matching to an `Implementation`
This problem differs as we need to *create* a relationship between *otherwise-unrelated* types.

Comparing the problems side-by-side, we can more clearly see this difference:

    def wrapping_in_df(native: IntoDataFrameT) -> DataFrame[IntoDataFrameT]: ...
    def matching_to_polars(native: pl.DataFrame) -> Literal[Implementation.POLARS]: ...

### (4) `Native<Backend>`
If we want to describe a set of specific types and **match** them in [`@overload`s], then these the tools we need.

For common and easily-installed backends, [`TypeAlias`]s are composed of the native type(s):

    NativePolars: TypeAlias = pl.DataFrame | pl.LazyFrame | pl.Series

Otherwise, we need to define a [`Protocol`] which the native type(s) can **match** against *when* installed:

    class NativeDask(NativeLazyFrame, Protocol):
        _partition_type: type[pd.DataFrame]

Tip:
    The goal is to be as minimal as possible, while still being *specific-enough* to **not match** something else.

Important:
    See [ibis#9276 comment] for a more *in-depth* example that doesn't fit here 😄

### (5) `is_native_<backend>`
[Type guards] for **(4)**, *similar* to those found in `nw.dependencies`.

They differ by checking **all** native types/protocols in a single-call and using ``Native<Backend>`` aliases.

[structural]: https://typing.python.org/en/latest/spec/glossary.html#term-structural
[nominal]: https://typing.python.org/en/latest/spec/glossary.html#term-nominal
[Native types]: https://narwhals-dev.github.io/narwhals/how_it_works/#polars-and-other-implementations
[Narwhals type]: https://narwhals-dev.github.io/narwhals/api-reference/dataframe/
[`Implementation`]: https://narwhals-dev.github.io/narwhals/api-reference/implementation/
[`Protocol`]: https://typing.python.org/en/latest/spec/protocol.html
[assignable to]: https://typing.python.org/en/latest/spec/glossary.html#term-assignable
[`TypeAlias`]: https://mypy.readthedocs.io/en/stable/kinds_of_types.html#type-aliases
[`TypeVar`]: https://mypy.readthedocs.io/en/stable/generics.html#type-variables-with-upper-bounds
[generic class]: https://docs.python.org/3/library/typing.html#user-defined-generic-types
[`@overload`s]: https://typing.python.org/en/latest/spec/overload.html
[ibis#9276 comment]: https://github.com/ibis-project/ibis/issues/9276#issuecomment-3292016818
[Type guards]: https://typing.python.org/en/latest/spec/narrowing.html
    )annotations)Callable
CollectionIterableSized)TYPE_CHECKINGAnyProtocolTypeVarUnioncast)get_cudf	get_modin
get_pandas
get_polarsget_pyarrowis_dask_dataframeis_duckdb_relationis_ibis_tableis_pyspark_connect_dataframeis_pyspark_dataframeis_sqlframe_dataframeN)BaseDataFrame)Self	TypeAliasTypeIsTzCallable[[Any], TypeIs[T]]r   _Guard
Incomplete)+IntoDataFrameIntoDataFrameT	IntoFrame
IntoFrameTIntoLazyFrameIntoLazyFrameT
IntoSeriesIntoSeriesT	NativeAnyNativeArrow
NativeCuDF
NativeDaskNativeDataFrameNativeDuckDBNativeFrame
NativeIbisNativeKnownNativeLazyFrameNativeModinNativePandasNativePandasLikeNativePandasLikeDataFrameNativePandasLikeSeriesNativePolarsNativePySparkNativePySparkConnectNativeSQLFrameNativeSeriesNativeSparkLikeNativeUnknownis_native_arrowis_native_cudfis_native_daskis_native_duckdbis_native_ibisis_native_modinis_native_pandasis_native_pandas_likeis_native_polarsis_native_pysparkis_native_pyspark_connectis_native_spark_likeis_native_sqlframec                  &    e Zd Zedd       ZddZy)r.   c                     y N selfs    O/var/www/html/land_sniper/venv/lib/python3.12/site-packages/narwhals/_native.pycolumnszNativeFrame.columns   s    !    c                     y rM   rN   rP   argskwargss      rQ   joinzNativeFrame.join       rS   Nreturnr	   rV   r	   rW   r	   r[   r	   )__name__
__module____qualname__propertyrR   rX   rN   rS   rQ   r.   r.      s    ! !9rS   r.   c                      e Zd ZddZy)r,   c                     y rM   rN   rU   s      rQ   dropzNativeDataFrame.drop   rY   rS   Nr\   )r]   r^   r_   rc   rN   rS   rQ   r,   r,      s    9rS   r,   c                      e Zd ZddZy)r1   c                     y rM   rN   rU   s      rQ   explainzNativeLazyFrame.explain   rY   rS   Nr\   )r]   r^   r_   rf   rN   rS   rQ   r1   r1      s    <rS   r1   c                  $    e Zd ZddZddZddZy)r;   c                     y rM   rN   rU   s      rQ   filterzNativeSeries.filter   rY   rS   c                     y rM   rN   rU   s      rQ   value_countszNativeSeries.value_counts   rY   rS   c                     y rM   rN   rU   s      rQ   uniquezNativeSeries.unique   rY   rS   Nr\   )r]   r^   r_   ri   rk   rm   rN   rS   rQ   r;   r;      s    ;A;rS   r;   c                  x    e Zd ZU ded<   	 ddZddZddZedd       Zedd       Z	ddd	dd
Z
dddZddZy)_BasePandasLiker	   indexc                    y rM   rN   )rP   keys     rQ   __getitem__z_BasePandasLike.__getitem__   rY   rS   c                    y rM   rN   rP   others     rQ   __mul__z_BasePandasLike.__mul__   rY   rS   c                    y rM   rN   ru   s     rQ   __floordiv__z_BasePandasLike.__floordiv__   rY   rS   c                     y rM   rN   rO   s    rQ   locz_BasePandasLike.loc   s    rS   c                     y rM   rN   rO   s    rQ   shapez_BasePandasLike.shape   s    (+rS   .)axiscopyc                    y rM   rN   )rP   labelsr~   r   s       rQ   set_axisz_BasePandasLike.set_axis   rY   rS   c                     y rM   rN   )rP   deeps     rQ   r   z_BasePandasLike.copy   rY   rS   c                     y)z`mypy` & `pyright` disagree on overloads.

        `Incomplete` used to fix [more important issue](https://github.com/narwhals-dev/narwhals/pull/3016#discussion_r2296139744).
        NrN   rP   rV   kwdss      rQ   renamez_BasePandasLike.rename   rY   rS   N)rr   r	   r[   r	   )rv   z float | Collection[float] | Selfr[   r   rZ   )r[   ztuple[int, ...])r   r	   r~   r	   r   boolr[   r   .)r   r   r[   r   )rV   r	   r   r	   r[   Self | Incomplete)r]   r^   r_   __annotations__rs   rw   ry   r`   r{   r}   r   r   r   rN   rS   rQ   ro   ro      s?    JK2NS + +36SV1rS   ro   c                      e Zd Zy)_BasePandasLikeFrameN)r]   r^   r_   rN   rS   rQ   r   r      s    rS   r   c                  N    e Zd ZU ded<   	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 ddZdd	dZy)
_BasePandasLikeSeries
Any | NonenameNc                     y rM   rN   )rP   datarp   dtyper   rV   rW   s          rQ   __init__z_BasePandasLikeSeries.__init__   s     rS   c                    y rM   rN   )rP   condrv   s      rQ   wherez_BasePandasLikeSeries.where   rY   rS   )NNNN)r   Iterable[Any] | Nonerp   r   r   r   r   r   rV   r	   rW   r	   r[   Noner   )r   r	   rv   r	   r[   r   )r]   r^   r_   r   r   r   rN   rS   rQ   r   r      se    
 &*&* " $ 	
    
 NrS   r   c                      e Zd ZU ded<   y)r+   type[pd.DataFrame]_partition_typeNr]   r^   r_   r   rN   rS   rQ   r+   r+      s    ''rS   r+   c                      e Zd ZddZy)_CuDFDataFramec                     y rM   rN   r   s      rQ   to_pylibcudfz_CuDFDataFrame.to_pylibcudf   rY   rS   NrV   r	   r   r	   r[   r	   r]   r^   r_   r   rN   rS   rQ   r   r          ?rS   r   c                      e Zd ZddZy)_CuDFSeriesc                     y rM   rN   r   s      rQ   r   z_CuDFSeries.to_pylibcudf   rY   rS   Nr   r   rN   rS   rQ   r   r      r   rS   r   c                  ,    e Zd ZddZddZddZddZy)r/   c                     y rM   rN   r   s      rQ   sqlzNativeIbis.sql  rY   rS   c                     y rM   rN   r   s      rQ   __pyarrow_result__zNativeIbis.__pyarrow_result__  rY   rS   c                     y rM   rN   r   s      rQ   __pandas_result__zNativeIbis.__pandas_result__  rY   rS   c                     y rM   rN   r   s      rQ   __polars_result__zNativeIbis.__polars_result__  rY   rS   Nr   )r]   r^   r_   r   r   r   r   rN   rS   rQ   r/   r/     s    6EDDrS   r/   c                      e Zd ZU ded<   y)_ModinDataFramer   _pandas_classNr   rN   rS   rQ   r   r     s    %%rS   r   c                      e Zd ZU ded<   y)_ModinSeriesztype[pd.Series[Any]]r   Nr   rN   rS   rQ   r   r     s    ''rS   r   c                      e Zd ZddZy)_PySparkDataFramec                     y rM   rN   )rP   argrW   s      rQ   dropDuplicatesWithinWatermarkz/_PySparkDataFrame.dropDuplicatesWithinWatermark  rY   rS   N)r   r	   rW   r	   r[   r	   )r]   r^   r_   r   rN   rS   rQ   r   r     s    QrS   r   z'pl.DataFrame | pl.LazyFrame | pl.Seriesr7   zpa.Table | pa.ChunkedArray[Any]r)   zduckdb.DuckDBPyRelationr-   zpd.DataFrame | pd.Series[Any]r3   z_ModinDataFrame | _ModinSeriesr2   z_CuDFDataFrame | _CuDFSeriesr*   z+pd.Series[Any] | _CuDFSeries | _ModinSeriesr6   z/pd.DataFrame | _CuDFDataFrame | _ModinDataFramer5   z2NativePandasLikeDataFrame | NativePandasLikeSeriesr4   z'_BaseDataFrame[Any, Any, Any, Any, Any]r:   r8   r9   z5NativeSQLFrame | NativePySpark | NativePySparkConnectr<   zhNativePolars | NativeArrow | NativePandasLike | NativeSparkLike | NativeDuckDB | NativeDask | NativeIbisr0   z0NativeDataFrame | NativeSeries | NativeLazyFramer=   zNativeKnown | NativeUnknownr(   r    r$   r"   r&   r#   )boundr!   r%   r'   c                |    t               x}d uxr- t        | |j                  |j                  |j                  f      S rM   )r   
isinstance	DataFrameSeries	LazyFrame)objpls     rQ   rF   rF   |  s:    ,Bt+ 
bllBIIr||41 rS   c                f    t               x}d uxr" t        | |j                  |j                  f      S rM   )r   r   TableChunkedArray)r   pas     rQ   r>   r>     s4    -B, bhh(2 rS   z_Guard[NativeDask]z_Guard[NativeDuckDB]rA   z_Guard[NativeSQLFrame]rJ   z_Guard[NativePySpark]z_Guard[NativePySparkConnect]z_Guard[NativeIbis]c                f    t               x}d uxr" t        | |j                  |j                  f      S rM   )r   r   r   r   )r   pds     rQ   rD   rD     s-    ,Bt+Z
3ryy@Y0ZZrS   c                f    t               x}d uxr" t        | |j                  |j                  f      S rM   )r   r   r   r   )r   mpds     rQ   rC   rC     s4    ;Ct+ 
cmmSZZ(1 rS   c                f    t               x}d uxr" t        | |j                  |j                  f      S rM   )r   r   r   r   )r   cudfs     rQ   r?   r?     s4    JDt+ 
dnndkk*1 rS   c                L    t        |       xs t        |       xs t        |       S rM   )rD   r?   rC   r   s    rQ   rE   rE     s!    C ON3$7O?3;OOrS   c                L    t        |       xs t        |       xs t        |       S rM   )rJ   rG   rH   r   s    rQ   rI   rI     s)    3 	*S!	*$S)rS   )r   r	   r[   zTypeIs[NativePolars])r   r	   r[   zTypeIs[NativeArrow])r   r	   r[   zTypeIs[NativePandas])r   r	   r[   zTypeIs[NativeModin])r   r	   r[   zTypeIs[NativeCuDF])r   r	   r[   zTypeIs[NativePandasLike])r   r	   r[   zTypeIs[NativeSparkLike])b__doc__
__future__r   collections.abcr   r   r   r   typingr   r	   r
   r   r   r   narwhals.dependenciesr   r   r   r   r   r   r   r   r   r   r   duckdbpandasr   polarsr   pyarrowr   sqlframe.base.dataframer   _BaseDataFrametyping_extensionsr   r   r   SQLFrameDataFramer   r   r   r   __all__r.   r,   r1   r;   ro   r   r   r+   r   r   r/   r   r   r   r7   r)   r-   r3   r2   r*   r6   r5   r4   r:   r8   r9   r<   r0   r=   r(   r    r$   r"   r&   r#   r!   r%   r'   rF   r>   r@   rA   rJ   rG   rH   rB   rD   rC   r?   rE   rI   rN   rS   rQ   <module>r      s   fP # A A E E    G99&sCc3'>?A4FI4J	,d:( ::e[( :=k8 =<5(3- <eX ( L?OX KNL/8 N(( (@)8 @@' @Eh E&*H &((( (R R Di C:Y :3i 39i 99Y 96
I 6$Q 	 Q'X 9 XR ) RE	 E,y ,"3 i 3T T DY  DMy M4	9 4*y *
 !*!<=y =]M9:	9 : %
I $ \3
 )? )?m:6 *,=>); & ;-B * B02FG  "$@  *M:[PrS   