U
    Cvf                     @  sz  d dl mZ d dlZd dlZd dl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 d dlZd dlZd dlmZmZmZ d dlmZmZmZ d dlmZm Z m!Z!m"Z" erd dl#m$Z$m%Z% d d	l&m'Z' e	ed
f Z(G dd dZ)dddddZ*dddddZ+dd Z,dcddZ-dd Z.dd Z/ddddd d!Z0dd"d#d$Z1ded%d&Z2ed'd(d)Z3G d*d( d(e)Z4dfd,d-d.d/d0Z5dddd1d2Z6G d3d4 d4e4Z7dgd
d5d6d7d8d9Z8ed:e)ej)Z9G d;d< d<ej:je
e9 Z;d,d=d>d?d@dAZ<dhddd
d
dBdCdDdEdFZ=dGdCdHdIdJZ>dKdLd-dMdNdOdPZ?dKdLdMdQdRdSZ@dKdTdMdUdVdWZAdXdYd>dZd[d\ZBdidKd^d-d_d`dadbZCdS )j    )annotationsN)defaultdict)TYPE_CHECKINGAnyDictGenericHashableIterableIteratorMappingSequenceTypeVarcast)
formattingnputilsutils)IndexSelResultPandasIndexingAdapterPandasMultiIndexingAdapter)Frozenget_valid_numpy_dtypeis_dict_like	is_scalar)ErrorOptionsT_IndexVariabler   c                   @  sX  e Zd ZdZeddd dddZedPdd	d
dddddZedd
d dddZddddZdQdddddZ	ddddZ
dd d!d"d#Zd$d%d&d'd(ZdRddd*dd+d,d-Zddd.d/d0d1Zd2d3 Zd4d d5d6d7Zd8d8d d9d:d;Zd dd<d=ZdSd>d d?d@dAZdTddCddDdEdFZdUddCd>ddGdHdIZdJdKdLdMZdNdO ZdS )VIndexz|Base class inherited by all xarray-compatible indexes.

    Do not use this class directly for creating index objects.

    Mapping[Any, Variable]Mapping[str, Any]	variablesoptionsreturnc                C  s
   t  d S NNotImplementedError)clsr!   r"    r(   7/tmp/pip-unpacked-wheel-h316xyqg/xarray/core/indexes.pyfrom_variables-   s    zIndex.from_variablesNztype[T_Index]zSequence[T_Index]r   Iterable[Iterable[int]] | Noner   )r'   indexesdim	positionsr#   c                 C  s
   t  d S r$   r%   )r'   r,   r-   r.   r(   r(   r)   concat6   s    zIndex.concatr!   r-   r#   c                 C  s   t | dd S )Nz< cannot be used for creating an index of stacked coordinatesr%   )r'   r!   r-   r(   r(   r)   stack?   s    zIndex.stack+tuple[dict[Hashable, Index], pd.MultiIndex]r#   c                 C  s
   t  d S r$   r%   selfr(   r(   r)   unstackE   s    zIndex.unstackMapping[Any, Variable] | None	IndexVarsr!   r#   c                 C  s   |d k	rt f |S i S d S r$   )dict)r5   r!   r(   r(   r)   create_variablesH   s    
zIndex.create_variablespd.Indexc                 C  s   t | ddS )zCast this xarray index to a pandas.Index object or raise a TypeError
        if this is not supported.

        This method is used by all xarray operations that expect/require a
        pandas.Index object.

        z( cannot be cast to a pandas.Index objectN)	TypeErrorr4   r(   r(   r)   to_pandas_indexQ   s    zIndex.to_pandas_index1Mapping[Any, int | slice | np.ndarray | Variable]zIndex | Noneindexersr#   c                 C  s   d S r$   r(   )r5   rA   r(   r(   r)   isel[   s    z
Index.iseldict[Any, Any]r   labelsr#   c                 C  s   t | dd S )Nz& doesn't support label-based selectionr%   )r5   rE   r(   r(   r)   sel`   s    z	Index.selinnerstrr5   otherhowr#   c                 C  s   t | dd S )Nz7 doesn't support alignment with inner/outer join methodr%   )r5   rJ   rK   r(   r(   r)   joinc   s    z
Index.joindict[Hashable, Any])r5   rJ   r#   c                 C  s   t | dd S )Nz# doesn't support re-indexing labelsr%   r5   rJ   r(   r(   r)   reindex_likeh   s    zIndex.reindex_likec                 C  s
   t  d S r$   r%   rN   r(   r(   r)   equalsk   s    zIndex.equalsMapping[Any, int]shiftsr#   c                 C  s   d S r$   r(   )r5   rS   r(   r(   r)   rolln   s    z
Index.rollzMapping[Any, Hashable])	name_dict	dims_dictr#   c                 C  s   | S r$   r(   )r5   rU   rV   r(   r(   r)   renameq   s    zIndex.renamec                 C  s   | j ddS )NFdeep_copyr4   r(   r(   r)   __copy__v   s    zIndex.__copy__dict[int, Any] | None)memor#   c                 C  s   | j d|dS )NTrY   r^   rZ   )r5   r^   r(   r(   r)   __deepcopy__y   s    zIndex.__deepcopy__Tbool)r5   rY   r#   c                 C  s   | j |dS )NrX   rZ   )r5   rY   r(   r(   r)   copy|   s    z
Index.copyr5   rY   r^   r#   c                 C  sP   | j }||}|r>| j D ]\}}t||t|| qn|j| j |S r$   )	__class____new____dict__itemssetattrrb   deepcopyupdate)r5   rY   r^   r'   copiedkvr(   r(   r)   r[      s    
zIndex._copyr   indexerc                 C  s
   t  d S r$   r%   r5   ro   r(   r(   r)   __getitem__   s    zIndex.__getitem__c                 C  s   | j jS r$   )rd   __name__)r5   	max_widthr(   r(   r)   _repr_inline_   s    zIndex._repr_inline_)N)N)rG   )N)T)TN)rr   
__module____qualname____doc__classmethodr*   r/   r1   r6   r;   r>   rB   rF   rL   rO   rP   rT   rW   r\   r`   rb   r[   rq   rt   r(   r(   r(   r)   r   &   s6     	
   r   r<   )indexr#   c              	   C  sT   ddl m} t| dkrL| jdkrLz
|| W S  ttfk
rH   |  Y S X n| S d S )Nr   )CFTimeIndexO)Zxarray.coding.cftimeindexrz   lendtypeImportErrorr=   )ry   rz   r(   r(   r)   _maybe_cast_to_cftimeindex   s    
r   r   )arrayr#   c                 C  s   ddl m} ddlm} t| tjr*| }ntt| ||frB|  }n\t| trV|  }nHt| t	rh| j
}n6i }t| dr| jjdkrt|d< tjt| f|}t|S )a9  Given an array, safely cast it to a pandas.Index.

    If it is already a pandas.Index, return it unchanged.

    Unlike pandas.Index, if the array has dtype=object or dtype=timedelta64,
    this function will not attempt to do automatic type conversion but will
    always return an index with dtype=object.
    r   	DataArrayr   r}   r{   )xarray.core.dataarrayr   xarray.core.variabler   
isinstancepdr   Z	_to_indexr>   r   r   hasattrr}   kindobjectnpasarrayr   )r   r   r   ry   kwargsr(   r(   r)   safe_cast_to_index   s    	



r   c                 C  sn   ddl m} ddlm} t| tsBtt| dkrBt	d|  t| ||frV| j
} t| tjrj| d } | S )Nr   r   r   z=cannot use non-scalar arrays in a slice for xarray indexing: r(   )r   r   r   r   r   tupler|   r   shape
ValueErrorvaluesZndarray)xr   r   r(   r(   r)   _sanitize_slice_element   s    r    c                 C  sV   |d k	s|d k	rt d| t|jt|jt|j}t|tsRtd|d|S )Nz@cannot use ``method`` argument if any indexers are slice objectsz<cannot represent labeled-based slice indexer for coordinate zI with a slice over integer positions; the index is unsorted or non-unique)	r&   Zslice_indexerr   startstopstepr   sliceKeyError)ry   label
coord_namemethod	tolerancero   r(   r(   r)   _query_slice   s    

r   c                 C  sL   t | trt| }n2t| }|jdkrHtjt| t	d}| |dd< |S )z
    Convert values into a numpy array of at most 1-dimension, while preserving
    tuples.

    Adapted from pandas.core.common._asarray_tuplesafe
       r}   N)
r   r   r   Zto_0d_object_arrayr   r   ndimemptyr|   r   )r   resultr(   r(   r)   _asarray_tuplesafe   s    


r   c                 C  s   t | totdd | D S )Nc                 s  s   | ]}t |tttfV  qd S r$   )r   r   listr   ).0valuer(   r(   r)   	<genexpr>   s    z#_is_nested_tuple.<locals>.<genexpr>)r   r   any)Zpossible_tupler(   r(   r)   _is_nested_tuple   s    r   z
np.ndarrayr3   c                 C  sH   t | dddkrt| } |d k	rD|jdkrD| jjdkrDtj| |d} | S )Nr      fbr   )getattrr   r   r}   r   r   )r   r}   r(   r(   r)   normalize_label   s
    r   r   c                 C  s   | j jdkr| d S |  S )NZmMr(   )r}   r   itemr   r(   r(   r)   	as_scalar  s    r   c                 C  s*   t |}| j|||d}||j}|S )zXWrapper around :meth:`pandas.Index.get_indexer` supporting n-dimensional
    labels
    )r   r   )r   ravelZget_indexerZreshaper   )ry   rE   r   r   Zflat_labelsZflat_indexerro   r(   r(   r)   get_indexer_nd  s    
r   T_PandasIndexPandasIndex)boundc                   @  sL  e Zd ZU dZded< ded< ded< dZdLdddd
ddZdMddZeddd dddZ	e
dNddddZedOdddd dddZdPddddd Zddd!d"Zd#d$d%d&d'ZdQd(d)d*d+d,Zd-d.d/d0ZdRd d d2d d3d4d5ZdSd d6d7d8d9Zd:d d;d<d=Zd>d? ZdTdAdBdCdAdDdEdFZddGdHdIZdJdK Zd	S )Ur   z2Wrap a pandas.Index as an xarray compatible index.r<   ry   r   r-   r   coord_dtype)ry   r-   r   N)r   r-   r   c                 C  sB   t | }|jd kr||_|| _|| _|d kr8t|}|| _d S r$   )r   rb   namery   r-   r   r   )r5   r   r-   r   ry   r(   r(   r)   __init__"  s    
zPandasIndex.__init__c                 C  s,   |d kr| j }|d kr| j}t| |||S r$   )r-   r   type)r5   ry   r-   r   r(   r(   r)   _replace2  s
    zPandasIndex._replacer   r   r    c          	      C  s   t |dkr tdt | dtt| \}}|jdkrVtd|d|j d|jd }t|jd|j	}t
|jtr|jj}|d k	r|jj|}| |||jd	}t
|jtjrt||j_|S )
Nr   z-PandasIndex only accepts one variable, found z
 variablesz<PandasIndex only accepts a 1-dimensional variable, variable z has z dimensionsr   r   r   )r|   r   nextiterrg   r   dimsr   _datadatar   r   levelr   Zget_level_valuesr}   ry   r   
MultiIndexAssertionErrorr   )	r'   r!   r"   r   varr-   r   r   objr(   r(   r)   r*   9  s&    

zPandasIndex.from_variablesr3   c                   s   | st g }nt fdd| D sNddd | D }td d| dd	 | D }|d
 |dd  }|d k	rtt	|}|
|}|S )Nc                 3  s   | ]}|j  kV  qd S r$   r-   r   idxr   r(   r)   r   h  s     z.PandasIndex._concat_indexes.<locals>.<genexpr>,c                 S  s   h | ]}|j qS r(   r   r   r(   r(   r)   	<setcomp>i  s     z.PandasIndex._concat_indexes.<locals>.<setcomp>z#Cannot concatenate along dimension z indexes with dimensions: c                 S  s   g | ]
}|j qS r(   ry   r   r(   r(   r)   
<listcomp>n  s     z/PandasIndex._concat_indexes.<locals>.<listcomp>r   r   )r   r   allrL   r   appendr   Zinverse_permutationr   ZconcatenateZtake)r,   r-   r.   new_pd_indexr   Z
pd_indexesindicesr(   r   r)   _concat_indexesa  s    
zPandasIndex._concat_indexeszSequence[PandasIndex]r+   r,   r-   r.   r#   c                 C  s:   |  |||}|sd }ntjdd |D  }| |||dS )Nc                 S  s   g | ]
}|j qS r(   r   r   r(   r(   r)   r     s     z&PandasIndex.concat.<locals>.<listcomp>)r-   r   )r   r   result_type)r'   r,   r-   r.   r   r   r(   r(   r)   r/   w  s
    zPandasIndex.concatr7   r8   r9   c                 C  sl   ddl m} | jj}|d k	r:||kr:|| }|j}|j}nd }d }t| j| jd}|| j|||d}||iS )Nr   IndexVariabler   )attrsencoding)	r   r   ry   r   r   r   r   r   r-   )r5   r!   r   r   r   r   r   r   r(   r(   r)   r;     s    zPandasIndex.create_variablesc                 C  s   | j S r$   r   r4   r(   r(   r)   r>     s    zPandasIndex.to_pandas_indexr?   zPandasIndex | Noner@   c                 C  s^   ddl m} || j }t||r8|j| jfkr2d S |j}t|tsNt|rNd S | | j	| S )Nr   r   )
r   r   r-   r   r   r   r   r   r   ry   )r5   rA   r   Zindxrr(   r(   r)   rB     s    

zPandasIndex.iselrC   r   rD   c              
   C  s  ddl m} ddlm} |d k	r2t|ts2tdt|dksBtt	t
| \}}t|trvt| j||||}npt|rtdn\t|| jd}	|	jdkrlt|	}
t| jtjr|d k	rtd|d k	rtd	| j|
}n|d k	r"t| j|	||}t|dk rjtd
|nHz| j|
}W n6 tk
rh } ztd
|d|W 5 d }~X Y nX nB|	jjdkr|	}n.t| j|	||}t|dk rtd
|t||r||j|}nt||r|||j|jd}t | j!|iS )Nr   r   r   z``method`` must be a stringr   zZcannot use a dict-like object for selection on a dimension that does not have a MultiIndexr   zA'method' is not supported when indexing using a CategoricalIndex.zD'tolerance' is not supported when indexing using a CategoricalIndex.not all values found in index zH. Try setting the `method` keyword argument (example: method='nearest').r   coordsr   )"r   r   r   r   r   rH   r=   r|   r   r   r   rg   r   r   ry   r   r   r   r   r   r   r   CategoricalIndexget_locr   r   r   r   r}   r   r   _coordsr   r-   )r5   rE   r   r   r   r   r   r   ro   label_arraylabel_valueer(   r(   r)   rF     sl    

   
zPandasIndex.selr   rJ   c                 C  s(   t |tsdS | j|jo&| j|jkS )NF)r   r   ry   rP   r-   rN   r(   r(   r)   rP     s    
zPandasIndex.equalsrG   rH   rI   c                 C  sJ   |dkr| j |j }n| j |j }t| j|j}t| || j|dS )Nouterr   )ry   unionintersectionr   r   r   r   r-   )r5   rJ   rK   ry   r   r(   r(   r)   rL     s
    zPandasIndex.joinrM   )rJ   r#   c                 C  s2   | j jstd| jd| jt| j |j ||iS )Nz(cannot reindex or align along dimension z0 because the (pandas) index has duplicate values)ry   Z	is_uniquer   r-   r   )r5   rJ   r   r   r(   r(   r)   rO     s
    zPandasIndex.reindex_likerQ   rR   c                 C  sZ   || j  | jjd  }|dkrB| j| d  | jd |  }n| jd d  }| |S )Nr   )r-   ry   r   r   r   )r5   rS   shiftZ
new_pd_idxr(   r(   r)   rT     s
    $zPandasIndex.rollc                 C  sX   | j j|kr| j|kr| S || j j| j j}| j |}|| j| j}| j||dS )Nr   )ry   r   r-   getrW   r   )r5   rU   rV   new_namery   new_dimr(   r(   r)   rW     s    zPandasIndex.renameTr   ra   r]   rc   c                 C  s$   |r| j jdd}n| j }| |S )NTrX   )ry   rb   r   )r5   rY   r^   ry   r(   r(   r)   r[      s    zPandasIndex._copyrn   c                 C  s   |  | j| S r$   )r   ry   rp   r(   r(   r)   rq   +  s    zPandasIndex.__getitem__c                 C  s   dt | j dS )NzPandasIndex())reprry   r4   r(   r(   r)   __repr__.  s    zPandasIndex.__repr__)N)NN)N)N)N)NN)rG   )NN)TN)rr   ru   rv   rw   __annotations__	__slots__r   r   rx   r*   staticmethodr   r/   r;   r>   rB   rF   rP   rL   rO   rT   rW   r[   rq   r   r(   r(   r(   r)   r     sB   

'     B   

   equalr   rH   )r!   all_dimsc                 C  s   t dd |  D rtddd |  D }|dkrdt|dkrdtdd	d
d |  D  |dkrt|t| k rtdd	dd |  D  dS )zCheck that all multi-index variable candidates are 1-dimensional and
    either share the same (single) dimension or each have a different dimension.

    c                 S  s   g | ]}|j d kqS r   )r   r   r   r(   r(   r)   r   7  s     z%_check_dim_compat.<locals>.<listcomp>z5PandasMultiIndex only accepts 1-dimensional variablesc                 S  s   h | ]
}|j qS r(   r   r   r(   r(   r)   r   :  s     z$_check_dim_compat.<locals>.<setcomp>r   r   z/unmatched dimensions for multi-index variables , c                 S  s    g | ]\}}|d |j  qS  r   r   rl   rm   r(   r(   r)   r   ?  s     	differentz9conflicting dimensions for multi-index product variables c                 S  s    g | ]\}}|d |j  qS r   r   r   r(   r(   r)   r   E  s     N)r   r   r   r|   rL   rg   )r!   r   r   r(   r(   r)   _check_dim_compat2  s    r   c                 C  s   t | tjr|  } tdd | jD rg }t| jD ]@\}}t |tjr^|| j|  	 }n|| j|  }|
| q6tjj|| jd} nt | tjr| 	 } | S )zZ
    Remove unused levels from MultiIndex and unused categories from CategoricalIndex
    c                 s  s   | ]}t |tjV  qd S r$   )r   r   r   r   levr(   r(   r)   r   Q  s     z2remove_unused_levels_categories.<locals>.<genexpr>names)r   r   r   Zremove_unused_levelsr   levels	enumerater   codesZremove_unused_categoriesr   from_arraysr   )ry   r   ir   r(   r(   r)   remove_unused_levels_categoriesI  s    r  c                      s  e Zd ZU dZded< dZd7dddd fd	d
Zd8d dddZeddd dddZ	ed9dddd dddZ
eddd dddZddddZedd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/Zd<d1d2d3d4Zd5d6 Z  ZS )=PandasMultiIndexz7Wrap a pandas.MultiIndex as an xarray compatible index.zdict[str, Any]level_coords_dtype)ry   r-   r   r  Nr   r   )r   r-   r  c                   s   t  || g }t| jjD ]B\}}|jp8| d| }||krVtd|d||| q|| j_|d krdd | jjD }|| _	d S )NZ_level_z#conflicting multi-index level name z with dimension c                 S  s   i | ]}|j t|qS r(   )r   r   r   r(   r(   r)   
<dictcomp>z  s     z-PandasMultiIndex.__init__.<locals>.<dictcomp>)
superr   r  ry   r   r   r   r   r   r  )r5   r   r-   r  r   r  r   r   rd   r(   r)   r   k  s    zPandasMultiIndex.__init__r3   c                 C  s2   |d kr| j }||_|d kr"| j}t| |||S r$   )r-   r   r  r   )r5   ry   r-   r  r(   r(   r)   r     s    zPandasMultiIndex._replacer   r   r    c                C  sj   t | tt| jd }tjjdd | D | d}||_	dd |
 D }| |||d}|S )Nr   c                 S  s   g | ]
}|j qS r(   )r   r   r(   r(   r)   r     s     z3PandasMultiIndex.from_variables.<locals>.<listcomp>r   c                 S  s   i | ]\}}||j qS r(   r   )r   r   r   r(   r(   r)   r    s      z3PandasMultiIndex.from_variables.<locals>.<dictcomp>r  )r   r   r   r   r   r   r   r  keysr   rg   )r'   r!   r"   r-   ry   r  r   r(   r(   r)   r*     s     zPandasMultiIndex.from_variableszSequence[PandasMultiIndex]r+   r   c                   sV   |  |||}|sd }n0i }|d jD ]  tj fdd|D  | < q&| |||dS )Nr   c                   s   g | ]}|j   qS r(   r  r   r   r(   r)   r     s     z+PandasMultiIndex.concat.<locals>.<listcomp>r-   r  )r   r  r   r   )r'   r,   r-   r.   r   r  r(   r  r)   r/     s    
zPandasMultiIndex.concatr0   c                 C  s   t |dd dd | D }t||D ]*\}}t|tjr(td|d|dq(tdd |D  \}}tj|d	d
i}dd |D }	tj||	d|	 d}
dd |
 D }| |
||dS )aH  Create a new Pandas MultiIndex from the product of 1-d variables (levels) along a
        new dimension.

        Level variables must have a dimension distinct from each other.

        Keeps levels the same (doesn't refactorize them) so that it gives back the original
        labels after a stack/unstack roundtrip.

        r   )r   c                 S  s   g | ]}t |qS r(   )r   r   r(   r(   r)   r     s     z*PandasMultiIndex.stack.<locals>.<listcomp>z4cannot create a multi-index along stacked dimension z from variable z that wraps a multi-indexc                 S  s   g | ]}|  qS r(   )Z	factorizer   r(   r(   r)   r     s     ZindexingZijc                 S  s   g | ]}|  qS r(   )r   )r   r   r(   r(   r)   r     s     r   )Z	sortorderr   c                 S  s   i | ]\}}||j qS r(   r   r   rl   r   r(   r(   r)   r    s      z*PandasMultiIndex.stack.<locals>.<dictcomp>r  )r   r   zipr   r   r   r   r   Zmeshgridr  rg   )r'   r!   r-   Zlevel_indexesr   r   Zsplit_labelsr   Zlabels_meshrE   ry   r  r(   r(   r)   r1     s    zPandasMultiIndex.stackr2   c                 C  sN   t | j}i }t|j|jD ](\}}t| || j| d}|||< q||fS )Nr   )r  ry   r  r   r   r   rb   r  )r5   Zclean_indexnew_indexesr   r   r   r(   r(   r)   r6     s    
  
zPandasMultiIndex.unstackz"tuple[PandasMultiIndex, IndexVars])r-   current_variablesr!   r#   c                 C  sr  g }g }g }i }t || t|dkrtttt| j}|j}	|	|	j
 |	|	j |	|	j |	j
D ]}
||
 ||
< qpn`t|dkrtt| }| d}|| tj|jdd}||j ||j |||< | D ]B\}
}||
 tj|jdd}||j ||j |||
< qtj|||d}dd | D }| |||d}||}||fS )	zCreate a new multi-index maybe by expanding an existing one with
        new variables as index levels.

        The index and its corresponding coordinates may be created along a new dimension.
        r   Z_level_0T)Zorderedr   c                 S  s   i | ]\}}||j qS r(   r   r  r(   r(   r)   r    s      z@PandasMultiIndex.from_variables_maybe_expand.<locals>.<dictcomp>r  )r   r|   r   r   r   r   r   r   r   extendr   r  r   r   r   ZCategorical
categoriesrg   r   r;   )r'   r-   r  r!   r   r  r   level_variablesr   Zcurrent_indexr   r   Znew_var_namecatry   r  r   
index_varsr(   r(   r)   from_variables_maybe_expand  sF     





z,PandasMultiIndex.from_variables_maybe_expandzPandasMultiIndex | PandasIndex)r  r#   c                   sp   j  fddj jD }t|tjrLfdd|jD }j||dS t|j	j	j
|j dS dS )zpKeep only the provided levels and return a new multi-index with its
        corresponding coordinates.

        c                   s   g | ]}| kr|qS r(   r(   r   rl   )r  r(   r)   r     s      z0PandasMultiIndex.keep_levels.<locals>.<listcomp>c                   s   i | ]}| j | qS r(   r  r  r4   r(   r)   r    s      z0PandasMultiIndex.keep_levels.<locals>.<dictcomp>r  r   N)ry   Z	droplevelr   r   r   r   r   r   rW   r-   r  r   r5   r  ry   r  r(   )r  r5   r)   keep_levels  s    

zPandasMultiIndex.keep_levelsc                   s2    j | } fdd|jD } j||dS )z|Re-arrange index levels using input order and return a new multi-index with
        its corresponding coordinates.

        c                   s   i | ]}| j | qS r(   r  r  r4   r(   r)   r  /  s      z3PandasMultiIndex.reorder_levels.<locals>.<dictcomp>r  )ry   reorder_levelsr  r   r   r  r(   r4   r)   r  '  s    zPandasMultiIndex.reorder_levelsr7   r8   r9   c                 C  s   ddl m} |d kri }i }| jf| jj D ]x}|| jkrDd }d }n|}| j| }||d }|d k	rt|j}|j}	ni }i }	t	| j||d}
|| j|
||	dd||< q,|S )Nr   r   )r}   r   T)r   r   Zfastpath)
r   r   r-   ry   r   r  r   r   r   r   )r5   r!   r   r  r   r   r}   r   r   r   r   r(   r(   r)   r;   2  s2    

z!PandasMultiIndex.create_variablesr   c              	     sp  ddl m} ddlm} |d k	s(|d k	r0tdd i }tfdd|D rXi  | D ]P\}}t|j| d}	zt	|	 |< W q\ tk
r   td|d	Y q\X q\t
d
d   D }
t jjkr|
sjt fddjjD }nXjjt  t  d\}|  |jjdkr| dkrt| dn(t|dkrttt|tjj }td|djjdtt| \}}t|rfdd|D }|rtd| |S t|trt j||}nxt|trt!|r,j"|}nht|jjkrLj|}nHfddt#t|D }jj||d\}|dd t$||D  nt|}	|	j%dkrt	|	}jj|dd\}||jjd < nZ|	jjdkr|	}nF|	j%dkrtd|dt&j|	}t'
|dk r2td|t||rL||j(|}n4t||rfdd|j) D }||||j(d}d k	r^tt*j+rćfddjD }j,|di }g }n.t-j.jj. dj/jj.i}j/g}0 }t1t2t3t4f fd d|D }|}| D ]\}}|g |||< q&t5j/|i||t6|||d!S t5j/|iS d S )"Nr   r   r   z9multi-index does not support ``method`` and ``tolerance``c                   s   g | ]}| j jkqS r(   ry   r   )r   Zlblr4   r(   r)   r   c  s     z(PandasMultiIndex.sel.<locals>.<listcomp>r   z7Vectorized selection is not available along coordinate z (multi-index level)c                 S  s   g | ]}t |tqS r(   )r   r   r   rm   r(   r(   r)   r   p  s     c                 3  s   | ]} | V  qd S r$   r(   r  )label_valuesr(   r)   r   t  s     z'PandasMultiIndex.sel.<locals>.<genexpr>)r   r   z
 not foundr   z*cannot provide labels for both coordinate z7 (multi-index array) and one or more coordinates among z (multi-index levels)c                   s   g | ]}| j jkr|qS r(   r  )r   r   r4   r(   r)   r     s     z invalid multi-index level names c                   s   g | ]} j j| qS r(   r  )r   r  r4   r(   r)   r     s     c                 S  s   i | ]\}}||qS r(   r(   r   r(   r(   r)   r    s      z(PandasMultiIndex.sel.<locals>.<dictcomp>z with a multi-indexr   c                   s"   i | ]\}}| j jkr||qS r(   r  r   r4   r(   r)   r    s    r   c                   s   i | ]}| j | qS r(   r  r  r4   r(   r)   r    s     r  r   c                   s   i | ]
}| qS r(   r(   r  	new_indexr(   r)   r    s      )r,   r!   Zdrop_indexesdrop_coordsZrename_dims)7r   r   r   r   r   r   rg   r   r  r   r   r   r|   ry   Znlevelsr   r   r   Zget_loc_levelr  rj   r}   r   sumr   r   r   setr   rF   r   r   r   r   Zget_locsranger  r   r   r   r   r   r   r   r   r   r   r-   r;   r   r   r   r   r   r   )r5   rE   r   r   r   r   Zscalar_coord_valuesrl   rm   r   Z	has_slicero   r   r   Zinvalid_levelsr   r   r   r  rV   r"  Znew_varsr,   r!   r   valr(   )r  r!  r5   r)   rF   V  s    

 










 
 
zPandasMultiIndex.selrG   rH   )rK   c                   sh   |dkr. j  }d |_| j |}| j|_n| j  j } fdd| j D }t| || j|dS )Nr   c                   s$   i | ]\}}|t | j| qS r(   )r   r   r  )r   rl   Z	lvl_dtyper   r(   r)   r    s    z)PandasMultiIndex.join.<locals>.<dictcomp>r  )	ry   rb   r   r   r-   r   r  rg   r   )r5   rJ   rK   other_indexry   r  r(   r   r)   rL     s    


zPandasMultiIndex.joinc                   s~   t | jjt  @ s"| j|kr"| S  fdd| jjD }| j|}|| j| j}dd t|| j D }| j	|||dS )Nc                   s   g | ]}  ||qS r(   )r   r  rU   r(   r)   r      s     z+PandasMultiIndex.rename.<locals>.<listcomp>c                 S  s   i | ]\}}||qS r(   r(   r   r(   r(   r)   r    s     z+PandasMultiIndex.rename.<locals>.<dictcomp>r  )
r$  ry   r   r-   rW   r   r  r  r   r   )r5   rU   rV   Z	new_namesry   r   Znew_level_coords_dtyper(   r(  r)   rW     s      zPandasMultiIndex.rename)N)NN)N)N)NN)rG   )rr   ru   rv   rw   r   r   r   r   rx   r*   r/   r1   r6   r  r  r  r;   rF   rL   rW   __classcell__r(   r(   r
  r)   r  d  s.   
 6 $ r  z#Mapping | Iterable[Hashable] | Noneztuple[PandasIndex, IndexVars])dim_variableall_variablesr#   c           
        s    dkri  t  ts$dd  D  jd tjdd}t |tjrt|}| } fdd|D }|rt	|t	|j
jk rd}n( fd	d|D }tfd
d|D }|rd|}td| n i}	tj|	i d}||	}||fS )a  Create a default index from a dimension variable.

    Create a PandasMultiIndex if the given variable wraps a pandas.MultiIndex,
    otherwise create a PandasIndex (note that this will become obsolete once we
    depreciate implicitly passing a pandas.MultiIndex as a coordinate).

    Nc                 S  s   i | ]
}|d qS r$   r(   r  r(   r(   r)   r    s      z1create_default_index_implicit.<locals>.<dictcomp>r   r   c                   s    g | ]}| kr|kr|qS r(   r(   r  )r+  r   r(   r)   r   $  s       z1create_default_index_implicit.<locals>.<listcomp>Tc                   s   g | ]} | qS r(   r(   r  )r+  r(   r)   r   -  s     c                 3  s"   | ]}|d kp  | V  qd S r$   rP   r  )r*  r(   r)   r   .  s    z0create_default_index_implicit.<locals>.<genexpr>
z1conflicting MultiIndex level / variable name(s):
)r"   )r   r   r   r   r   r   r   r  r;   r|   ry   r   r   rL   r   r   r*   )
r*  r+  r   ry   r  Zduplicate_namesconflictZduplicate_varsZconflict_strZdim_varr(   )r+  r*  r   r)   create_default_index_implicit  s4    




r/  T_PandasOrXarrayIndexc                   @  sT  e Zd ZU dZded< ded< dZddddd	Zed
dddZeddddZ	eddddZ
eddddZeddddZd dddZddddZdd d!d"d#ZdFdd%d&d'd(d)ZdGdd%dd'd*d+Zd,dd-d.Zd/dd0d1ZdHd d4d5d6d7d8Zd9dd:d;Zd<dd=d>Zd dd?d@ZdAddBdCZdDdE Zd3S )IIndexeszImmutable proxy for Dataset or DataArrary indexes.

    Keys are coordinate names and values may correspond to either pandas or
    xarray indexes.

    Also provides some utility methods.

    z dict[Any, T_PandasOrXarrayIndex]_indexeszdict[Any, Variable]
_variables)r2  r3  _dimsZ__coord_name_idZ
__id_indexZ__id_coord_names)r,   r!   c                 C  s(   || _ || _d| _d| _d| _d| _dS )zConstructor not for public consumption.

        Parameters
        ----------
        indexes : dict
            Indexes held by this object.
        variables : dict
            Indexed coordinate variables in this object.

        N)r2  r3  r4  _Indexes__coord_name_id_Indexes__id_index_Indexes__id_coord_names)r5   r,   r!   r(   r(   r)   r   Y  s    zIndexes.__init__zdict[Any, int]r3   c                 C  s&   | j d kr dd | j D | _ | j S )Nc                 S  s   i | ]\}}|t |qS r(   id)r   rl   r   r(   r(   r)   r  s  s      z*Indexes._coord_name_id.<locals>.<dictcomp>)r5  r2  rg   r4   r(   r(   r)   _coord_name_idp  s    
zIndexes._coord_name_idz dict[int, T_PandasOrXarrayIndex]c                 C  s$   | j d krdd |  D | _ | j S )Nc                 S  s   i | ]}t ||qS r(   r8  r   r(   r(   r)   r  y  s      z%Indexes._id_index.<locals>.<dictcomp>)r6  
get_uniquer4   r(   r(   r)   	_id_indexv  s    
zIndexes._id_indexzdict[int, tuple[Hashable, ...]]c                 C  sN   | j d krHtt}| j D ]\}}|| | qdd | D | _ | j S )Nc                 S  s   i | ]\}}|t |qS r(   )r   r   r(   r(   r)   r    s      z+Indexes._id_coord_names.<locals>.<dictcomp>)r7  r   r   r:  rg   r   )r5   Zid_coord_namesrl   rm   r(   r(   r)   _id_coord_names|  s    
zIndexes._id_coord_nameszMapping[Hashable, Variable]c                 C  s
   t | jS r$   )r   r3  r4   r(   r(   r)   r!     s    zIndexes.variableszMapping[Hashable, int]c                 C  s,   ddl m} | jd kr"|| j| _t| jS )Nr   calculate_dimensions)r   r?  r4  r3  r   )r5   r?  r(   r(   r)   r     s    
zIndexes.dimsc                 C  s   t | t| jt| jS r$   )r   r:   r2  r3  r4   r(   r(   r)   rb     s    zIndexes.copyzlist[T_PandasOrXarrayIndex]c                 C  sB   g }t  }| j D ](}t|}||kr|| || q|S )z2Return a list of unique indexes, preserving order.)r$  r2  r   r9  r   add)r5   Zunique_indexesseenry   Zindex_idr(   r(   r)   r;    s    
zIndexes.get_uniquer   ra   )keyr#   c                 C  s   t | j| j|  dkS )zZReturn True if ``key`` maps to a multi-coordinate index,
        False otherwise.
        r   )r|   r=  r:  r5   rB  r(   r(   r)   is_multi  s    zIndexes.is_multiraiser   zdict[Hashable, Variable])rB  errorsr#   c                   sZ   |dkrt d| jkr8|dkr4t d|dni S  j j|  } fdd|D S )a  Return all coordinates having the same index.

        Parameters
        ----------
        key : hashable
            Index key.
        errors : {"raise", "ignore"}, default: "raise"
            If "raise", raises a ValueError if `key` is not in indexes.
            If "ignore", an empty tuple is returned instead.

        Returns
        -------
        coords : dict
            A dictionary of all coordinate variables having the same index.

        )rE  ignorez)errors must be either "raise" or "ignore"rE  zno index found for z coordinatec                   s   i | ]}| j | qS r(   r3  r  r4   r(   r)   r    s      z*Indexes.get_all_coords.<locals>.<dictcomp>)r   r2  r=  r:  )r5   rB  rF  Zall_coord_namesr(   r4   r)   get_all_coords  s    
zIndexes.get_all_coordsc                 C  s   ddl m} || j||dS )a  Return all dimensions shared by an index.

        Parameters
        ----------
        key : hashable
            Index key.
        errors : {"raise", "ignore"}, default: "raise"
            If "raise", raises a ValueError if `key` is not in indexes.
            If "ignore", an empty tuple is returned instead.

        Returns
        -------
        dims : dict
            A dictionary of all dimensions shared by an index.

        r   r>  )rF  )r   r?  rI  )r5   rB  rF  r?  r(   r(   r)   get_all_dims  s    zIndexes.get_all_dimsz<list[tuple[T_PandasOrXarrayIndex, dict[Hashable, Variable]]]c                   sD   g } j D ]4} j | } fdd j| D }|||f q
|S )zEReturns a list of unique indexes and their corresponding coordinates.c                   s   i | ]}| j | qS r(   rH  r  r4   r(   r)   r    s      z*Indexes.group_by_index.<locals>.<dictcomp>)r<  r=  r   )r5   index_coordsr  ry   r   r(   r4   r)   group_by_index  s    

zIndexes.group_by_indexzIndexes[pd.Index]c                 C  sP   i }| j  D ]4\}}t|tjr,|||< qt|tr| ||< qt|| jS )zReturns an immutable proxy for Dataset or DataArrary pandas indexes.

        Raises an error if this proxy contains indexes that cannot be coerced to
        pandas.Index objects.

        )r2  rg   r   r   r   r>   r1  r3  )r5   r,   rl   r   r(   r(   r)   to_pandas_indexes  s    

zIndexes.to_pandas_indexesTNr]   zFtuple[dict[Hashable, T_PandasOrXarrayIndex], dict[Hashable, Variable]])rY   r^   r#   c           
        s   i }i }|   D ]\}}t|tjrbd}tt| jd }t|tjrVt	||}qft
||}nd}|j||d ||}	|rtt
 j | fdd|D  ||	 q||fS )a  Return a new dictionary with copies of indexes, preserving
        unique indexes.

        Parameters
        ----------
        deep : bool, default: True
            Whether the indexes are deep or shallow copied onto the new object.
        memo : dict if object id to copied objects or None, optional
            To prevent infinite recursion deepcopy stores all copied elements
            in this dict.

        Tr   Fr_   c                   s   i | ]
}| qS r(   r(   r  Znew_idxr(   r)   r  "  s      z(Indexes.copy_indexes.<locals>.<dictcomp>)rL  r   r   r   r   r   r   r   r   r  r   r[   r;   r   ry   rj   )
r5   rY   r^   r  new_index_varsr   r   Zconvert_new_idxr-   Zidx_varsr(   rN  r)   copy_indexes  s"    
zIndexes.copy_indexeszIterator[T_PandasOrXarrayIndex]c                 C  s
   t | jS r$   )r   r2  r4   r(   r(   r)   __iter__'  s    zIndexes.__iter__intc                 C  s
   t | jS r$   )r|   r2  r4   r(   r(   r)   __len__*  s    zIndexes.__len__c                 C  s
   || j kS r$   r2  rC  r(   r(   r)   __contains__-  s    zIndexes.__contains__r0  c                 C  s
   | j | S r$   rT  rC  r(   r(   r)   rq   0  s    zIndexes.__getitem__c                 C  s
   t | S r$   )r   Zindexes_reprr4   r(   r(   r)   r   3  s    zIndexes.__repr__)rE  )rE  )TN)rr   ru   rv   rw   r   r   r   propertyr:  r<  r=  r!   r   rb   r;  rD  rI  rJ  rL  rM  rP  rQ  rS  rU  rq   r   r(   r(   r(   r)   r1  C  s@   
			      (r1  r	   zdict[Hashable, Index])r   r   r#   c                   s\   i }t | }|  D ]B\}}||krt|| \ }t ||kr| fdd|D  q|S )ay  Default indexes for a Dataset/DataArray.

    Parameters
    ----------
    coords : Mapping[Any, xarray.Variable]
        Coordinate variables from which to draw default indexes.
    dims : iterable
        Iterable of dimension names.

    Returns
    -------
    Mapping from indexing keys (levels/dimension names) to indexes used for
    indexing along that dimension.
    c                   s   i | ]
}| qS r(   r(   r  r   r(   r)   r  O  s      z#default_indexes.<locals>.<dictcomp>)r$  rg   r/  rj   )r   r   r,   coord_namesr   r   r  r(   r   r)   default_indexes7  s    rX  z)dict[tuple[int, int], bool | None] | Nonera   )ry   r'  variableother_variablecacher#   c                 C  s   |dkri }t | t |f}d}||krpt| t|krjz| |}W n tk
r^   d}Y qnX |||< qxd}n|| }|dkr||}tt|S )zCheck if two indexes are equal, possibly with cached results.

    If the two indexes are not of the same type or they do not implement
    equality, fallback to coordinate labels equality check.

    N)r9  r   rP   r&   r   ra   )ry   r'  rY  rZ  r[  rB  r   r(   r(   r)   indexes_equalT  s     


r\  z0Sequence[tuple[Index, dict[Hashable, Variable]]])elementsr#   c                   s    fdd}dd  D t fdddd D }|r@d	S t fd
ddd D }|rz"tfdddd D }W q tk
r   | }Y qX n| }| S )zCheck if indexes are all equal.

    If they are not of the same type or they do not implement this check, check
    if their coordinate variables are all equal instead.

    c                     s,   dd D  t  fdd dd  D S )Nc                 S  s   g | ]}|d  qS r   r(   r   r   r(   r(   r)   r     s     z>indexes_all_equal.<locals>.check_variables.<locals>.<listcomp>c                 3  s4   | ],} d  D ]} d  |  ||  V  qqdS r   Nr,  )r   Z
other_varsrl   r!   r(   r)   r     s   
 z=indexes_all_equal.<locals>.check_variables.<locals>.<genexpr>r   )r   r(   )r]  r`  r)   check_variables  s    
z*indexes_all_equal.<locals>.check_variablesc                 S  s   g | ]}|d  qS )r   r(   r^  r(   r(   r)   r     s     z%indexes_all_equal.<locals>.<listcomp>c                 3  s   | ]} d  |kV  qdS r_  r(   r   Z	other_idxr,   r(   r)   r     s     z$indexes_all_equal.<locals>.<genexpr>r   NTc                 3  s"   | ]}t  d  t |kV  qdS r_  )r   rb  rc  r(   r)   r     s     c                 3  s   | ]} d   | V  qdS r_  r,  rb  rc  r(   r)   r     s    )r   r   r&   )r]  ra  Zsame_objectsZ	same_type	not_equalr(   )r]  r,   r)   indexes_all_equal{  s    

re  zIndexes[Index]zMapping[Any, Any]z6tuple[dict[Hashable, Index], dict[Hashable, Variable]])r,   argsfuncr#   c           
        s   dd |   D }i }|  D ]\}}dd | D   fdd|  D }|rt|||d k	r|fdd|D  |}|| q|D ]}	||	d  qq||fS )Nc                 S  s   i | ]\}}||qS r(   r(   r   r(   r(   r)   r    s      z"_apply_indexes.<locals>.<dictcomp>c                 S  s   h | ]}|j D ]}|qqS r(   r   )r   r   dr(   r(   r)   r     s       z!_apply_indexes.<locals>.<setcomp>c                   s   i | ]\}}| kr||qS r(   r(   r   )
index_dimsr(   r)   r    s       c                   s   i | ]
}| qS r(   r(   r  r   r(   r)   r    s      )rg   rL  r   r   rj   r;   pop)
r,   rf  rg  r  Znew_index_variablesry   r  Z
index_argsrO  rl   r(   )ri  r!  r)   _apply_indexes  s    
rk  )r,   rA   r#   c                 C  s   t | |dS )NrB   rk  )r,   rA   r(   r(   r)   isel_indexes  s    rm  rQ   )r,   rS   r#   c                 C  s   t | |dS )NrT   rl  )r,   rS   r(   r(   r)   roll_indexes  s    rn  zMapping[Any, Index]r$  )r,   filtered_coord_namesr#   c                 C  s`   t f | }tt}|  D ]\}}|t| | q| D ]}||ks>|D ]
}||= qNq>|S )zFilter index items given a (sub)set of coordinate names.

    Drop all multi-coordinate related index items for any key missing in the set
    of coordinate names.

    )r:   r   r$  rg   r9  r@  r   )r,   ro  Zfiltered_indexesZindex_coord_namesr   r   Zidx_coord_namesrl   r(   r(   r)   filter_indexes_from_coords  s    


rp  remove coordinate(s)zset[Hashable]None)r,   rW  actionr#   c              
   C  s~   |   D ]p\}}t||@ }|rt|t|krddd |D }ddd |D }td| d| d| d| qd	S )
z@Assert removing coordinates or indexes will not corrupt indexes.r   c                 s  s   | ]}|V  qd S r$   r(   r  r(   r(   r)   r     s     z,assert_no_index_corrupted.<locals>.<genexpr>c                 s  s   | ]}|V  qd S r$   r(   r  r(   r(   r)   r     s     zcannot r   zA, which would corrupt the following index built from coordinates z:
N)rL  r$  r|   rL   r   )r,   rW  rs  ry   rK  Zcommon_namesZcommon_names_strZindex_names_strr(   r(   r)   assert_no_index_corrupted  s    	rt  )r   NN)N)NN)r   )N)N)rq  )D
__future__r   collections.abccollectionsrb   r   typingr   r   r   r   r   r	   r
   r   r   r   r   Znumpyr   Zpandasr   Zxarray.corer   r   r   Zxarray.core.indexingr   r   r   Zxarray.core.utilsr   r   r   r   Zxarray.core.typesr   r   r   r   r8   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r/  r0  abcr1  rX  r\  re  rk  rm  rn  rp  rt  r(   r(   r(   r)   <module>   s`   4l


     - 4 u" '& 