o
    $&]i9                     @  s  U 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
mZmZ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mZmZmZmZ d dl Z!d dl"m#Z$ d dl%m&Z&m'Z' d dl(m)Z)m*Z* d dl+m,Z, d dl-m.Z. dZ/de0d< dZ1de0d< ed Z2de0d< eddddddd d!d"d#d$d%d&d'd(d)d*d+d,e2f Z3de0d-< 	 d.Z4de0d/< 	 eZ5de0d0< 	 d d1d d2Z6d3e0d4< ed5d6dId;d<Z7G d=d> d>Z8G d?d@ d@edAdBe3f Z9dJdDdEZ:dKdGdHZ;dS )L    )annotationsN)	lru_cache)chain)methodcaller)TYPE_CHECKINGAnyClassVarLiteral)EagerGroupBy)issue_warning)!evaluate_output_names_and_aliases)make_group_by_kwargs)
zip_strict)is_pandas_like_dataframe)CallableIterableIteratorMappingSequence)DataFrameGroupBy)	TypeAliasUnpack)NarwhalsAggregationScalarKwargs)PandasLikeDataFrame)PandasLikeExprz._NativeGroupBy[tuple[str, ...], Literal[True]]r   NativeGroupByz(Callable[[pd.DataFrame], pd.Series[Any]]NativeApply)covskewInefficientNativeAggregationanyallcountidxmaxidxminmaxmeanmedianminmodenthnuniqueprodquantilesemsizestdsumvarNativeAggregationz.Callable[[Any], pd.DataFrame | pd.Series[Any]]
_NativeAggNonStrHashable)firstlast	any_valuez,Mapping[NarwhalsAggregation, Literal[0, -1]]_REMAP_ORDERED_INDEX    )maxsizenamekwdsUnpack[ScalarKwargs]returnc                K  s>   | dkr
t | ddS |r|ddkrt | S t | fi |S )Nr,   F)dropnaddof   )r   get)r>   r?    rF   \/var/www/html/IGF-ODF-V3/venv/lib/python3.10/site-packages/narwhals/_pandas_like/group_by.py_native_aggE   s
   rH   c                   @  s   e Zd ZU dZded< ded< ded< d&d	d
Zd'ddZd(ddZd)ddZd)ddZ	d)ddZ
d)ddZd)ddZd)ddZed*d d!Zd+d#d$Zd%S ),AggExpraM  Wrapper storing the intermediate state per-`PandasLikeExpr`.

    There's a lot of edge cases to handle, so aim to evaluate as little
    as possible - and store anything that's needed twice.

    Warning:
        While a `PandasLikeExpr` can be reused - this wrapper is valid **only**
        in a single `.agg(...)` operation.
    r   exprzSequence[str]output_namesaliasesrA   Nonec                 C  s   || _ d| _d| _d| _d S )NrF    )rJ   rK   rL   
_leaf_name)selfrJ   rF   rF   rG   __init__]   s   
zAggExpr.__init__group_byPandasLikeGroupByc                C  s&   |j }|j}t| j||\| _| _| S )zd**Mutating operation**.

        Stores the results of `evaluate_output_names_and_aliases`.
        )	compliantexcluder   rJ   rK   rL   )rP   rR   dfrU   rF   rF   rG   with_expand_namesc   s   zAggExpr.with_expand_namespd.DataFrame | pd.Series[Any]c          
        s  | j }|  r|  r|j }n|  r-|j |j fdd|D }n|  rr|j}|	| j
}|d }dkrQd| d|j d}t|t|}|j|j|j |  fdd|D }n:|  s~|  s~|  r|  |jg |j| }|j|jd	d
 nt|dkr|d nt|}	|  |j|	 }t|rt| j|_|S | jd |_|S )z8Evaluate the wrapped expression as a group_by operation.c                   s   g | ]}  |jqS rF   )from_nativealiasnative).0r>   )nsresult_singlerF   rG   
<listcomp>{   s    z)AggExpr._getitem_aggs.<locals>.<listcomp>keepr!   z`Expr.mode(keep='z7')` is not implemented in group by context for backend z3

Hint: Use `nw.col(...).mode(keep='any')` instead.c                   sT   g | ]&}j g  |fi  jd d|j  fi | d qS )F)	ascendingrD   )groupbyr0   sort_valuesreset_indexhead
sort_index)r\   col)keyskwargsr[   rF   rG   r_      s     TinplacerD   r   )rK   is_lenis_top_level_function_groupedr0   rT   __narwhals_namespace___concat_horizontalis_mode_kwargsrJ   rE   _implementationNotImplementedErrorlistr[   _keys_group_by_kwargsis_lastis_firstis_any_value
native_agg	set_indexlenr   rL   columnsr>   )
rP   rR   namesresultrT   node_kwargsr`   msgcolsselectrF   )rh   ri   r[   r]   r^   rG   _getitem_aggso   sJ   

zAggExpr._getitem_aggsboolc                 C  
   | j dkS )Nr}   	leaf_namerP   rF   rF   rG   rl         
zAggExpr.is_lenc                 C  r   )Nr9   r   r   rF   rF   rG   rx      r   zAggExpr.is_lastc                 C  r   )Nr8   r   r   rF   rF   rG   ry      r   zAggExpr.is_firstc                 C  r   )Nr*   r   r   rF   rF   rG   rq      r   zAggExpr.is_modec                 C  r   )Nr:   r   r   rF   rF   rG   rz      r   zAggExpr.is_any_valuec                 C  s   t t| jj dkS )NrD   )r}   ru   rJ   	_metadataop_nodes_reversedr   rF   rF   rG   rm      s   zAggExpr.is_top_level_functionNarwhalsAggregation | Anyc                 C  s"   | j  }r|S t | j| _ | j S N)rO   rS   rJ   )rP   r>   rF   rF   rG   r      s   
zAggExpr.leaf_namer5   c                 C  sb   t | j}t| jj }| jtv r(|j	drd}t
|tdt| j dS t|fi |jS )z@Return a partial `DataFrameGroupBy` method, missing only `self`.ignore_nullszd`Expr.any_value(ignore_nulls=True)` is not supported in a `group_by` context for pandas-like backendr+   )n)rS   _remap_expr_namer   nextrJ   r   r   r;   ri   rE   rt   r   rH   )rP   native_name	last_noder   rF   rF   rG   r{      s   
zAggExpr.native_aggN)rJ   r   rA   rM   )rR   rS   rA   rI   )rR   rS   rA   rX   )rA   r   )rA   r   )rA   r5   )__name__
__module____qualname____doc____annotations__rQ   rW   r   rl   rx   ry   rq   rz   rm   propertyr   r{   rF   rF   rF   rG   rI   N   s"   
 




8




rI   c                   @  s   e Zd ZU i ddddddddddddddddd	d
ddddddddddddddddZded< ded< 	 ded< 	 ded< 	 ded< 	 edAdd ZdBd(d)ZdCd,d-ZdDd1d2Z	dEd5d6Z
dFd8d9ZdGd;d<ZdHd>d?Zd@S )IrS   r2   r'   r(   r&   r)   r*   r1   r3   r}   r0   n_uniquer,   r#   r.   r"   r!   r8   r+   r9   r:   z9ClassVar[Mapping[NarwhalsAggregation, NativeAggregation]]_REMAP_AGGStuple[str, ...]_original_columnsz	list[str]rv   _output_key_nameszMapping[str, bool]rw   rA   c                 C  s   | j S )z>Group keys to ignore when expanding multi-output aggregations.)_excluder   rF   rF   rG   rU      s   zPandasLikeGroupBy.excluderV   r   rh   (Sequence[PandasLikeExpr] | Sequence[str]drop_null_keysr   rM   c               C  s   t |j| _|| _| ||\| _| _| _g | j| jR | _| j	j
}t|jj| j	jr4|jdd}t|d| _|j| j fi | j| _d S )NT)drop)r   )tupler~   r   _drop_null_keys_parse_keys_compliant_framerv   r   r   rT   r[   setindexr   intersectionrd   r   rw   rb   copyrn   )rP   rV   rh   r   r[   rF   rF   rG   rQ      s   zPandasLikeGroupBy.__init__exprsr   c                 G  s   d}g }|D ]}| t||  | |sd}q|r<|r,| j }|| |}n| j j	t
| jj| jd}n| jjjrDt | |}|jdd | ||S )NTF)r~   rj   )appendrI   rW   
_is_simplerT   ro   rp   r   __native_namespace__	DataFrameru   rn   groupsrv   r[   emptyempty_results_error_apply_aggsrd   _select_results)rP   r   all_aggs_are_simple	agg_exprsrJ   r]   r   rF   rF   rG   agg  s&   




zPandasLikeGroupBy.aggr   Sequence[AggExpr]pd.DataFramec                C  sJ   t dd |D }| jj|ddjg | j|R  tt| j| j	S )zgResponsible for remapping temp column names back to original.

        See `ParseKeysGroupBy`.
        c                 s  s    | ]}|j V  qd S r   )rL   r\   erF   rF   rG   	<genexpr>1  s    z4PandasLikeGroupBy._select_results.<locals>.<genexpr>F)validate_column_names)
r   from_iterablerT   _with_nativesimple_selectrv   renamedictzipr   )rP   rV   r   	new_namesrF   rF   rG   r   *  s   z!PandasLikeGroupBy._select_resultsIterable[AggExpr]#list[pd.DataFrame | pd.Series[Any]]c                  s    fdd|D S )Nc                   s   g | ]}|  qS rF   )r   r   r   rF   rG   r_   ;  s    z3PandasLikeGroupBy._getitem_aggs.<locals>.<listcomp>rF   )rP   r   rF   r   rG   r   8  s   zPandasLikeGroupBy._getitem_aggsIterable[PandasLikeExpr]c                 C  sH   t   | jj}| |}| jj}| r | dkr ||ddS ||S )a"  Stub issue for `include_groups` [pandas-dev/pandas-stubs#1270].

        - [User guide] mentions `include_groups` 4 times without deprecation.
        - [`DataFrameGroupBy.apply`] doc says the default value of `True` is deprecated since `2.2.0`.
        - `False` is explicitly the only *non-deprecated* option, but entirely omitted since [pandas-dev/pandas-stubs#1268].

        [pandas-dev/pandas-stubs#1270]: https://github.com/pandas-dev/pandas-stubs/issues/1270
        [User guide]: https://pandas.pydata.org/pandas-docs/stable/user_guide/groupby.html
        [`DataFrameGroupBy.apply`]: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.core.groupby.DataFrameGroupBy.apply.html
        [pandas-dev/pandas-stubs#1268]: https://github.com/pandas-dev/pandas-stubs/pull/1268
        )   r   F)include_groups)warn_complex_group_byrT   rs   _apply_exprs_functionrn   apply	is_pandas_backend_version)rP   r   implfuncr   rF   rF   rG   r   =  s   
zPandasLikeGroupBy._apply_aggsr   c                   s*   j  jjd fdd}|S )NrV   r   rA   pd.Series[Any]c                   sF   j |   fddD }|rt| ng g f\}}||djS )Nc                 3  s0    | ]}| D ]}|j jd  |jfV  qqdS )r   N)r[   ilocr>   )r\   rJ   rh   rT   rF   rG   r   W  s    zFPandasLikeGroupBy._apply_exprs_function.<locals>.fn.<locals>.<genexpr>)r   context)rT   r   r   r[   )rV   results	out_group	out_namesr   into_seriesr]   rP   r   rG   fnU  s   
z3PandasLikeGroupBy._apply_exprs_function.<locals>.fn)rV   r   rA   r   )rT   ro   _seriesr   )rP   r   r   rF   r   rG   r   Q  s   

z'PandasLikeGroupBy._apply_exprs_function)Iterator[tuple[Any, PandasLikeDataFrame]]c                 c  sn    t  ( t jddtd | jj}| jD ]\}}|||j| j fV  qW d    d S 1 s0w   Y  d S )Nignorez#.*a length 1 tuple will be returned)messagecategory)	warningscatch_warningsfilterwarningsFutureWarningrT   r   rn   r   r   )rP   with_nativekeygrouprF   rF   rG   __iter__a  s   
"zPandasLikeGroupBy.__iter__N)rA   r   )rV   r   rh   r   r   r   rA   rM   )r   r   rA   r   )r   r   rV   r   rA   r   )r   r   rA   r   )r   r   rA   r   )r   r   rA   r   )rA   r   )r   r   r   r   r   r   rU   rQ   r   r   r   r   r   r   rF   rF   rF   rG   rS      sj   
 	






rS   r   r   
ValueErrorc                  C  s   d} t | S )zJDon't even attempt this, it's way too inconsistent across pandas versions.au  No results for group-by aggregation.

Hint: you were probably trying to apply a non-elementary aggregation with a pandas-like API.
Please rewrite your query such that group-by aggregations are elementary. For example, instead of:

    df.group_by('a').agg(nw.col('b').round(2).mean())

use:

    df.with_columns(nw.col('b').round(2)).group_by('a').agg(nw.col('b').mean())

)r   )r   rF   rF   rG   r   m  s   
r   rM   c                   C  s   t dt d S )Na)  Found complex group-by expression, which can't be expressed efficiently with the pandas API. If you can, please rewrite your query such that group-by aggregations are simple (e.g. mean, std, min, max, ...). 

Please see: https://narwhals-dev.github.io/narwhals/concepts/improve_group_by_operation/)r   UserWarningrF   rF   rF   rG   r   |  s   r   )r>   r4   r?   r@   rA   r5   )rA   r   )rA   rM   )<
__future__r   r   	functoolsr   	itertoolsr   operatorr   typingr   r   r   r	   narwhals._compliantr
   narwhals._exceptionsr   narwhals._expression_parsingr   narwhals._pandas_like.utilsr   narwhals._utilsr   narwhals.dependenciesr   collections.abcr   r   r   r   r   pandaspdpandas.api.typingr   _NativeGroupBytyping_extensionsr   r   narwhals._compliant.typingr   r   narwhals._pandas_like.dataframer   narwhals._pandas_like.exprr   r   r   r   r    r4   r5   r6   r;   rH   rI   rS   r   r   rF   rF   rF   rG   <module>   s     
 
