U
    Cvf                     @  s  d dl mZ d dlZd dlZd dlZd dlmZmZ d dlm	Z	 d dl
mZmZ d dlmZ d dlmZ d dl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 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,m-Z-m.Z.m/Z/ er.d dl0m1Z1 d dl2m3Z3 d dl4m5Z5 eG dd dZ6dddddZ7dddddddZ8dddd dd!d"d#Z9d$d% Z:d&d' Z;d(d) Z<d*d+ Z=d,d- Z>G d.d/ d/Z?d0d1 Z@d2d3 ZAG d4d5 d5e?ZBG d6d7 d7e?ZCG d8d9 d9e?ZDG d:d; d;ZEG d<d= d=e,eEZFG d>d? d?e,ZGG d@dA dAeFZHeHZIG dBdC dCeFZJdDdE ZKG dFdG dGeFZLG dHdI dIeFZMdJdK ZNdLdM ZOdNdO ZPdPdQ ZQejRG dRdS dSejSZTd/dTdSdUd dVdWdXZUd/dTdSdYdZd[d\ZVd]d^ ZWd9dTdSdYdZd_d`ZXdadTdSdYdZdbdcZYddde ZZdfdg Z[dhdi Z\ddjdkZ]ddldmZ^dndo Z_dpdq Z`d drdsdtduZaG dvdw dweFZbG dxdy dyebZcG dzd{ d{eFZdG d|d} d}eFZeG d~d deFZfG dd defZgdS )    )annotationsN)Counterdefaultdict)suppress)	dataclassfield)	timedelta)escape)TYPE_CHECKINGAnyCallableHashableIterableMapping)Version)duck_array_ops)NumpyVIndexAdapter)OPTIONS)
array_typeinteger_typesis_duck_dask_arraymod_version)T_Xarray)NDArrayMixineither_dict_or_kwargsget_valid_numpy_dtypeto_0d_array)	DTypeLike)Index)Variablec                   @  s|   e Zd ZU dZded< eedZded< eedZded< ee	dZ
d	ed
< ee	dZd	ed< eedZded< dd ZdS )IndexSelResulta  Index query results.

    Attributes
    ----------
    dim_indexers: dict
        A dictionary where keys are array dimensions and values are
        location-based indexers.
    indexes: dict, optional
        New indexes to replace in the resulting DataArray or Dataset.
    variables : dict, optional
        New variables to replace in the resulting DataArray or Dataset.
    drop_coords : list, optional
        Coordinate(s) to drop in the resulting DataArray or Dataset.
    drop_indexes : list, optional
        Index(es) to drop in the resulting DataArray or Dataset.
    rename_dims : dict, optional
        A dictionary in the form ``{old_dim: new_dim}`` for dimension(s) to
        rename in the resulting DataArray or Dataset.

    zdict[Any, Any]dim_indexers)default_factoryzdict[Any, Index]indexeszdict[Any, Variable]	variableszlist[Hashable]drop_coordsdrop_indexeszdict[Any, Hashable]rename_dimsc                 C  s   | j | j| j| j| j| jfS )zrUnlike ``dataclasses.astuple``, return a shallow copy.

        See https://stackoverflow.com/a/51802661

        )r!   r#   r$   r%   r&   r'   self r*   8/tmp/pip-unpacked-wheel-h316xyqg/xarray/core/indexing.pyas_tupleG   s    zIndexSelResult.as_tupleN)__name__
__module____qualname____doc____annotations__r   dictr#   r$   listr%   r&   r'   r,   r*   r*   r*   r+   r    )   s   
r    zlist[IndexSelResult])resultsreturnc                 C  s   t dd | D }dd | D }|rPdd | D }tdd| d i }i }i }g }g }i }	| D ]H}
||
j ||
j ||
j ||
j7 }||
j	7 }|	|
j
 qlt||||||	S )	Nc                 S  s   g | ]}|j D ]}|qqS r*   r!   ).0resdimr*   r*   r+   
<listcomp>X   s       z%merge_sel_results.<locals>.<listcomp>c                 S  s   i | ]\}}|d kr||qS    r*   )r7   kvr*   r*   r+   
<dictcomp>Y   s       z%merge_sel_results.<locals>.<dictcomp>c                 S  s    g | ]\}}|d | dqS ): z indexes involvedr*   )r7   r9   countr*   r*   r+   r:   ^   s   zhXarray does not support label-based selection with more than one index over the following dimension(s):

z>
Suggestion: use a multi-index for each of those dimension(s).)r   items
ValueErrorjoinupdater!   r#   r$   r%   r&   r'   r    )r4   Zall_dims_countZduplicate_dimsZfmt_dimsr!   r#   r$   r%   r&   r'   r8   r*   r*   r+   merge_sel_resultsW   sD    

     rG   r   zMapping[Any, Any]zMapping[str, Any]z"list[tuple[Index, dict[Any, Any]]])objindexersoptionsr5   c                   s   i t t | D ]\}}| j|d}|dk	rPt|}||< | | |< q|| jkrjtd|q|| jkrt|dqt	|rt
d|d|dqdd< | d |< q fddD S )	zBReturns a list of unique indexes and their corresponding indexers.Nzno index found for coordinate z' is not a valid dimension or coordinatez cannot supply selection options z for dimension z*that has no associated coordinate or indexc                   s   g | ]}|  | fqS r*   r*   r7   r=   grouped_indexersZunique_indexesr*   r+   r:      s     z+group_indexers_by_index.<locals>.<listcomp>)r   r2   rC   ZxindexesgetidZcoordsKeyErrorZdimslenrD   )rH   rI   rJ   keylabelindexZindex_idr*   rL   r+   group_indexers_by_index}   s&    

rU   r   )rH   rI   indexers_kwargsr5   c                   s   ddl m} |dkr"|dkr"i }n
||d}t||d}t| ||}g }|D ]4\}	}
|	dkrl|t|
 qL||	j|
f| qLt|  j	 D ]J\}}t
||r||jkr||} fdd|jD }|| j|< q S )zzExecute index queries from a DataArray / Dataset and label-based indexers
    and return the (merged) query results.

    r   )	DataArrayN)method	tolerancemap_index_queriesc                   s   g | ]}| j kr|qS r*   r6   )r7   namemergedr*   r+   r:      s     
 z%map_index_queries.<locals>.<listcomp>)Zxarray.core.dataarrayrW   r   rU   appendr    selrG   r!   rC   
isinstanceZ_indexesZreset_indexZ_coordsZ	drop_vars)rH   rI   rX   rY   rV   rW   rJ   rM   r4   rT   labelsr=   r>   r%   r*   r\   r+   rZ      s&    



rZ   c                 C  s   t | ts| f} g }d}| D ]P}|tkrb|sR||d t|  tdg  d}ql|td q|| qt||krtd||t| tdg  t|S )aM  Given a key for indexing an ndarray, return an equivalent key which is a
    tuple with length equal to the number of dimensions.

    The expansion is done by replacing all `Ellipsis` items with the right
    number of full slices and then padding the key with full slices so that it
    reaches the appropriate dimensionality.
    Fr<   NTztoo many indices)r`   tupleEllipsisextendrQ   slicer^   
IndexError)rR   ndimnew_keyZfound_ellipsisr=   r*   r*   r+   expanded_indexer   s    
 ri   c                 C  s   t j| | S N)nparangeindices)Zslice_sizer*   r*   r+   _expand_slice   s    ro   c                 C  s   t | | S )zEnsure that given slice only contains positive start and stop values
    (stop can be -1 for full-size slices with negative steps, e.g. [-10::-1]))re   rm   )slrn   r*   r*   r+   _normalize_slice   s    rq   c                 C  s   t | |} tt| j| j| j}|dkr0tdS t ||}| j|j| j  }|dk r\tdS | j|j| j  }|dk rzd}| j|j }t|||S )zGiven a slice and the size of the dimension to which it will be applied,
    index it with another slice to return a new slice equivalent to applying
    the slices sequentially
    r   N)rq   rQ   rangestartstopstepre   )Z	old_sliceZapplied_slicern   Zsize_after_old_slicers   rt   ru   r*   r*   r+   slice_slice   s    

rv   c                 C  sp   t |tttjf stt |tr2|td kr2| S t | trdt |trTt| ||}qlt| || }n| | }|S rj   )r`   r   re   rk   ndarrayAssertionErrorrv   ro   )Zold_indexerZapplied_indexerrn   indexerr*   r*   r+   _index_indexer_1d  s    

rz   c                   @  s0   e Zd ZdZdZdd Zedd Zdd Zd	S )
ExplicitIndexeraz  Base class for explicit indexer objects.

    ExplicitIndexer objects wrap a tuple of values given by their ``tuple``
    property. These tuples should always have length equal to the number of
    dimensions on the indexed array.

    Do not instantiate BaseIndexer objects directly: instead, use one of the
    sub-classes BasicIndexer, OuterIndexer or VectorizedIndexer.
    _keyc                 C  s"   t | tkrtdt|| _d S )Nz/cannot instantiate base ExplicitIndexer objects)typer{   	TypeErrorrb   r}   r)   rR   r*   r*   r+   __init__.  s    zExplicitIndexer.__init__c                 C  s   | j S rj   r|   r(   r*   r*   r+   rb   3  s    zExplicitIndexer.tuplec                 C  s   t | j d| j dS )N())r~   r-   rb   r(   r*   r*   r+   __repr__7  s    zExplicitIndexer.__repr__N)	r-   r.   r/   r0   	__slots__r   propertyrb   r   r*   r*   r*   r+   r{   !  s   

r{   c                 C  s   | d krd S t | S rj   )operatorrT   )valuer*   r*   r+   as_integer_or_none;  s    r   c                 C  s*   t | j}t | j}t | j}t|||S rj   )r   rs   rt   ru   re   )r   rs   rt   ru   r*   r*   r+   as_integer_slice?  s    


r   c                      s$   e Zd ZdZdZ fddZ  ZS )BasicIndexerzTuple for basic indexing.

    All elements should be int or slice objects. Indexing follows NumPy's
    rules for basic indexing: each axis is independently sliced and axes
    indexed with an integer are dropped from the result.
    r*   c                   s   t |tstd|g }|D ]P}t |tr8t|}n.t |trLt|}ntdt| j d||	| q t
 | d S )Nkey must be a tuple: unexpected indexer type for r@   )r`   rb   r   r   intre   r   r~   r-   r^   superr   r)   rR   rh   r=   	__class__r*   r+   r   P  s    




zBasicIndexer.__init__r-   r.   r/   r0   r   r   __classcell__r*   r*   r   r+   r   F  s   r   c                      s$   e Zd ZdZdZ fddZ  ZS )OuterIndexera9  Tuple for outer/orthogonal indexing.

    All elements should be int, slice or 1-dimensional np.ndarray objects with
    an integer dtype. Indexing is applied independently along each axis, and
    axes indexed with an integer are dropped from the result. This type of
    indexing works like MATLAB/Fortran.
    r*   c                   s   t |tstd|g }|D ]}t |tr8t|}nt |trLt|}nzt |tjrt	|j
tjsvtd||jdkrtdt| j d|tj|tjd}ntdt| j d||| q t | d S )	Nr   4invalid indexer array, does not have integer dtype: r<   zinvalid indexer array for z!; must have exactly 1 dimension: dtyper   r@   )r`   rb   r   r   r   re   r   rk   rw   
issubdtyper   integerrg   r~   r-   asarrayint64r^   r   r   r   r   r*   r+   r   n  s.    





zOuterIndexer.__init__r   r*   r*   r   r+   r   c  s   r   c                      s$   e Zd ZdZdZ fddZ  ZS )VectorizedIndexera  Tuple for vectorized indexing.

    All elements should be slice or N-dimensional np.ndarray objects with an
    integer dtype and the same number of dimensions. Indexing follows proposed
    rules for np.ndarray.vindex, which matches NumPy's advanced indexing rules
    (including broadcasting) except sliced axes are always moved to the end:
    https://github.com/numpy/numpy/pull/6256
    r*   c                   s   t |tstd|g }d }|D ]}t |tr<t|}nt |tjrt|jtj	sftd||d krv|j
}n&||j
krdd |D }td| tj|tjd}ntdt| j d||| q$t | d S )	Nr   r   c                 S  s   g | ]}t |tjr|jqS r*   )r`   rk   rw   rg   rK   r*   r*   r+   r:     s      z.VectorizedIndexer.__init__.<locals>.<listcomp>zMinvalid indexer key: ndarray arguments have different numbers of dimensions: r   r   r@   )r`   rb   r   re   r   rk   rw   r   r   r   rg   rD   r   r   r~   r-   r^   r   r   )r)   rR   rh   rg   r=   Zndimsr   r*   r+   r     s2    



zVectorizedIndexer.__init__r   r*   r*   r   r+   r     s   	r   c                   @  s   e Zd ZdZdZdS )ExplicitlyIndexedz9Mixin to mark support for Indexer subclasses in indexing.r*   N)r-   r.   r/   r0   r   r*   r*   r*   r+   r     s   r   c                   @  s   e Zd ZdZdddZdS )ExplicitlyIndexedNDArrayMixinr*   Nc                 C  s&   t td f| j }tj| | |dS Nr   )r   re   rg   rk   r   )r)   r   rR   r*   r*   r+   	__array__  s    z'ExplicitlyIndexedNDArrayMixin.__array__)N)r-   r.   r/   r   r   r*   r*   r*   r+   r     s   r   c                   @  s2   e Zd ZdZdZefddZd
ddZdd	 ZdS )!ImplicitToExplicitIndexingAdapterzEWrap an array, converting tuples into the indicated explicit indexer.)arrayindexer_clsc                 C  s   t || _|| _d S rj   )as_indexabler   r   )r)   r   r   r*   r*   r+   r     s    
z*ImplicitToExplicitIndexingAdapter.__init__Nc                 C  s   t j| j|dS r   rk   r   r   r)   r   r*   r*   r+   r     s    z+ImplicitToExplicitIndexingAdapter.__array__c                 C  s>   t || j}| j| | }t|tr6t| || jS |S d S rj   )ri   rg   r   r   r`   r   r~   )r)   rR   resultr*   r*   r+   __getitem__  s
    
z-ImplicitToExplicitIndexingAdapter.__getitem__)N)	r-   r.   r/   r0   r   r   r   r   r   r*   r*   r*   r+   r     s
   
r   c                   @  sb   e Zd ZdZdZdddZdd Zedd	d
dZdddZ	dd Z
dd Zdd Zdd ZdS )LazilyIndexedArrayz4Wrap an array to make basic and outer indexing lazy.r   rR   Nc                 C  sR   t |t| r"|dkr"|j}|j}|dkr>ttdf|j }t|| _|| _dS )a  
        Parameters
        ----------
        array : array_like
            Array like object to index.
        key : ExplicitIndexer, optional
            Array indexer. If provided, it is assumed to already be in
            canonical expanded form.
        N)r`   r~   rR   r   r   re   rg   r   r)   r   rR   r*   r*   r+   r     s    

zLazilyIndexedArray.__init__c                 C  s   t t|j| j}g }t| jj| jjD ]4\}}t|t	rF|
| q(|
t|t|| q(t|}tdd |D rt|S t|S )Nc                 s  s   | ]}t |ttf V  qd S rj   )r`   r   re   rK   r*   r*   r+   	<genexpr>  s     z2LazilyIndexedArray._updated_key.<locals>.<genexpr>)iterri   rb   rg   zipr   shaperR   r`   r   r^   rz   nextallr   r   )r)   rh   Ziter_new_keyfull_keyrn   r=   r*   r*   r+   _updated_key  s    
zLazilyIndexedArray._updated_keytuple[int, ...]r5   c                 C  sd   g }t | jj| jjD ]D\}}t|trB|tt	|
|  qt|tjr||j qt|S rj   )r   r   r   rR   rb   r`   re   r^   rQ   rr   rm   rk   rw   rn   )r)   r   rn   r=   r*   r*   r+   r     s    
zLazilyIndexedArray.shapec                 C  s   t | j}tj|| j d dS r   )r   r   rk   r   rR   r)   r   r   r*   r*   r+   r     s    
zLazilyIndexedArray.__array__c                 C  s   t | j| j|S rj   )LazilyVectorizedIndexedArrayr   rR   	transposer)   orderr*   r*   r+   r     s    zLazilyIndexedArray.transposec                 C  s6   t |tr t| j| j}|| S t| | j| |S rj   )r`   r   r   r   rR   r~   r   )r)   ry   r   r*   r*   r+   r     s    
zLazilyIndexedArray.__getitem__c                 C  s*   t |trtd| |}|| j|< d S NzvLazy item assignment with the vectorized indexer is not yet implemented. Load your data first by .load() or compute().)r`   r   NotImplementedErrorr   r   )r)   rR   r   r   r*   r*   r+   __setitem__  s    

zLazilyIndexedArray.__setitem__c                 C  s    t | j d| jd| jdS N(array=z, key=r   r~   r-   r   rR   r(   r*   r*   r+   r   %  s    zLazilyIndexedArray.__repr__)N)N)r-   r.   r/   r0   r   r   r   r   r   r   r   r   r   r   r*   r*   r*   r+   r     s   
	
	r   c                   @  s`   e Zd ZdZdZdd ZeddddZdd
dZdd Z	dd Z
dd Zdd Zdd Zd	S )r   z/Wrap an array to make vectorized indexing lazy.r   c                 C  s:   t |ttfrt||j| _nt||j| _t|| _dS )z
        Parameters
        ----------
        array : array_like
            Array like object to index.
        key : VectorizedIndexer
        N)	r`   r   r   _outer_to_vectorized_indexerr   rR   _arrayize_vectorized_indexerr   r   r   r*   r*   r+   r   2  s    z%LazilyVectorizedIndexedArray.__init__r   r   c                 C  s   t j| jj jS rj   )rk   	broadcastrR   rb   r   r(   r*   r*   r+   r   @  s    z"LazilyVectorizedIndexedArray.shapeNc                 C  s   t j| j| j d dS r   )rk   r   r   rR   r   r*   r*   r+   r   D  s    z&LazilyVectorizedIndexedArray.__array__c                 C  s   t | j| j|S rj   )_combine_indexersrR   r   )r)   rh   r*   r*   r+   r   G  s    z)LazilyVectorizedIndexedArray._updated_keyc                   sT   t dd  jD r>tt fdd| jjD }t| j|S t| | j|  S )Nc                 s  s   | ]}t |tV  qd S rj   r`   r   )r7   indr*   r*   r+   r   L  s     z;LazilyVectorizedIndexedArray.__getitem__.<locals>.<genexpr>c                 3  s   | ]}| j  V  qd S rj   rb   rK   ry   r*   r+   r   M  s     )r   rb   r   rR   r   r   r~   r   )r)   ry   rR   r*   r   r+   r   J  s    z(LazilyVectorizedIndexedArray.__getitem__c                   s.   t t fdd| jjD }t| | j|S )Nc                 3  s   | ]}|  V  qd S rj   )r   rK   r   r*   r+   r   R  s     z9LazilyVectorizedIndexedArray.transpose.<locals>.<genexpr>)r   rb   rR   r~   r   )r)   r   rR   r*   r   r+   r   Q  s    z&LazilyVectorizedIndexedArray.transposec                 C  s   t dd S r   )r   r)   rR   r   r*   r*   r+   r   U  s    z(LazilyVectorizedIndexedArray.__setitem__c                 C  s    t | j d| jd| jdS r   r   r(   r*   r*   r+   r   [  s    z%LazilyVectorizedIndexedArray.__repr__)N)r-   r.   r/   r0   r   r   r   r   r   r   r   r   r   r   r*   r*   r*   r+   r   -  s   
r   c                 C  s   t | rt | S | S dS )z Wrap NumPy scalars in 0d arrays.N)rk   Zisscalarr   r   r*   r*   r+   _wrap_numpy_scalars_  s    

r   c                   @  sJ   e Zd ZdZdd Zdd ZdddZd	d
 Zdd Zdd Z	dd Z
dS )CopyOnWriteArray)r   _copiedc                 C  s   t || _d| _d S )NF)r   r   r   r)   r   r*   r*   r+   r   j  s    
zCopyOnWriteArray.__init__c                 C  s"   | j stt| j| _d| _ d S )NT)r   r   rk   r   r(   r*   r*   r+   _ensure_copiedn  s    zCopyOnWriteArray._ensure_copiedNc                 C  s   t j| j|dS r   r   r   r*   r*   r+   r   s  s    zCopyOnWriteArray.__array__c                 C  s   t | t| j| S rj   r~   r   r   r   r*   r*   r+   r   v  s    zCopyOnWriteArray.__getitem__c                 C  s   | j |S rj   r   r   r   r*   r*   r+   r   y  s    zCopyOnWriteArray.transposec                 C  s   |    || j|< d S rj   )r   r   r   r*   r*   r+   r   |  s    zCopyOnWriteArray.__setitem__c                 C  s   t | | jS rj   )r~   r   )r)   memor*   r*   r+   __deepcopy__  s    zCopyOnWriteArray.__deepcopy__)N)r-   r.   r/   r   r   r   r   r   r   r   r   r*   r*   r*   r+   r   g  s   
r   c                   @  sB   e Zd ZdZdd Zdd ZdddZd	d
 Zdd Zdd Z	dS )MemoryCachedArrayr   c                 C  s   t t|| _d S rj   )r   r   r   r   r*   r*   r+   r     s    zMemoryCachedArray.__init__c                 C  s"   t | jtstt| j| _d S rj   )r`   r   NumpyIndexingAdapterrk   r   r(   r*   r*   r+   _ensure_cached  s    z MemoryCachedArray._ensure_cachedNc                 C  s   |    tj| j|dS r   )r   rk   r   r   r   r*   r*   r+   r     s    zMemoryCachedArray.__array__c                 C  s   t | t| j| S rj   r   r   r*   r*   r+   r     s    zMemoryCachedArray.__getitem__c                 C  s   | j |S rj   r   r   r*   r*   r+   r     s    zMemoryCachedArray.transposec                 C  s   || j |< d S rj   r   r   r*   r*   r+   r     s    zMemoryCachedArray.__setitem__)N)
r-   r.   r/   r   r   r   r   r   r   r   r*   r*   r*   r+   r     s   
r   c                 C  s   t | tr| S t | tjr"t| S t | tjr6t| S t| rFt	| S t
| drXt| S t
| drjt| S tdt|  dS )z
    This function always returns a ExplicitlyIndexed subclass,
    so that the vectorized indexing is always possible with the returned
    object.
    __array_function____array_namespace__zInvalid array type: N)r`   r   rk   rw   r   pdr   PandasIndexingAdapterr   DaskIndexingAdapterhasattrNdArrayLikeIndexingAdapterArrayApiIndexingAdapterr   r~   r   r*   r*   r+   r     s    


r   c                 C  s   | j } tdd | D }d}g }t| |D ]\}}t|trX|t|d|  q*t|t	rrtj
|| }|jjdkstd| |jf d|| d   g}||j|  |d7 }q*tt |S )a  Convert an OuterIndexer into an vectorized indexer.

    Parameters
    ----------
    key : Outer/Basic Indexer
        An indexer to convert.
    shape : tuple
        Shape of the array subject to the indexing.

    Returns
    -------
    VectorizedIndexer
        Tuple suitable for use to index a NumPy array with vectorized indexing.
        Each element is an array: broadcasting them together gives the shape
        of the result.
    c                 S  s   g | ]}t |ts|qS r*   r   rK   r*   r*   r+   r:     s     
 z0_outer_to_vectorized_indexer.<locals>.<listcomp>r   r;   >   iur<   )rb   rQ   r   r`   r   r^   rk   r   reshapere   rl   rm   r   kindrx   rn   r   )rR   r   n_dimi_dimrh   r=   rn   r*   r*   r+   r     s    

"
r   c                 C  s.   t dd | jD dkr| jS t| |jS dS )a2  Convert an OuterIndexer into an indexer for NumPy.

    Parameters
    ----------
    key : Basic/OuterIndexer
        An indexer to convert.
    shape : tuple
        Shape of the array subject to the indexing.

    Returns
    -------
    tuple
        Tuple suitable for use to index a NumPy array.
    c                 S  s   g | ]}t |ts|qS r*   r`   re   rK   r*   r*   r+   r:     s     
 z+_outer_to_numpy_indexer.<locals>.<listcomp>r<   N)rQ   rb   r   )rR   r   r*   r*   r+   _outer_to_numpy_indexer  s    r   c                   sv   t | tst| |} t| jdkr& S tj| j j}t  trJt | n
t | tt fddtj	| j D S )a%  Combine two indexers.

    Parameters
    ----------
    old_key : ExplicitIndexer
        The first indexer for the original array
    shape : tuple of ints
        Shape of the original array to be indexed by old_key
    new_key
        The second indexer for indexing original[old_key]
    r   c                 3  s   | ]}| j  V  qd S rj   r   )r7   orh   r*   r+   r     s     z$_combine_indexers.<locals>.<genexpr>)
r`   r   r   rQ   rb   rk   r   r   r   Zbroadcast_arrays)Zold_keyr   rh   Z	new_shaper*   r   r+   r     s    



r   c                   @  s   e Zd ZdZdZdZdZdS )IndexingSupportr   r<         N)r-   r.   r/   BASICOUTEROUTER_1VECTOR
VECTORIZEDr*   r*   r*   r+   r     s   r   r   r   )rR   r   indexing_supportraw_indexing_methodr5   c                 C  s6   t | ||\}}||j}|jr2tt|| }|S )a  Support explicit indexing by delegating to a raw indexing method.

    Outer and/or vectorized indexers are supported by indexing a second time
    with a NumPy array.

    Parameters
    ----------
    key : ExplicitIndexer
        Explicit indexing object.
    shape : Tuple[int, ...]
        Shape of the indexed array.
    indexing_support : IndexingSupport enum
        Form of indexing supported by raw_indexing_method.
    raw_indexing_method : callable
        Function (like ndarray.__getitem__) that when called with indexing key
        in the form of a tuple returns an indexed array.

    Returns
    -------
    Indexing result, in the form of a duck numpy-array.
    )decompose_indexerrb   r   rk   r   )rR   r   r   r   Zraw_keyZnumpy_indicesr   r*   r*   r+   explicit_indexing_adapter  s
    
r   z'tuple[ExplicitIndexer, ExplicitIndexer])ry   r   r   r5   c                 C  sB   t | trt| ||S t | ttfr0t| ||S td|  d S Nunexpected key type: )r`   r   _decompose_vectorized_indexerr   r   _decompose_outer_indexerr   )ry   r   r   r*   r*   r+   r   ;  s
    
r   c                 C  st   |  |\}}}|dkr$| tdfS |t|| d | |  d }|d |d  }}t||| tdddfS dS )z^convert a slice to successive two slices. The first slice always has
    a positive step.
    r   Nr<   )rm   re   r   )rR   rn   rs   rt   ru   r*   r*   r+   _decompose_sliceE  s     r   c                 C  s   t | tst|tjkr$| tdfS g }g }dd t| j|D }t||D ]d\}}t |trt	||\}}	|
| |
|	 qLtj|dd\}
}|
|
 |
|j|j  qLtt|}tt|}|tjkr||fS t|||\}}t|||}||fS )a:  
    Decompose vectorized indexer to the successive two indexers, where the
    first indexer will be used to index backend arrays, while the second one
    is used to index loaded on-memory np.ndarray.

    Parameters
    ----------
    indexer : VectorizedIndexer
    indexing_support : one of IndexerSupport entries

    Returns
    -------
    backend_indexer: OuterIndexer or BasicIndexer
    np_indexers: an ExplicitIndexer (VectorizedIndexer / BasicIndexer)

    Notes
    -----
    This function is used to realize the vectorized indexing for the backend
    arrays that only support basic or outer indexing.

    As an example, let us consider to index a few elements from a backend array
    with a vectorized indexer ([0, 3, 1], [2, 3, 2]).
    Even if the backend array only supports outer indexing, it is more
    efficient to load a subslice of the array than loading the entire array,

    >>> array = np.arange(36).reshape(6, 6)
    >>> backend_indexer = OuterIndexer((np.array([0, 1, 3]), np.array([2, 3])))
    >>> # load subslice of the array
    ... array = NumpyIndexingAdapter(array)[backend_indexer]
    >>> np_indexer = VectorizedIndexer((np.array([0, 2, 1]), np.array([0, 1, 0])))
    >>> # vectorized indexing for on-memory np.ndarray.
    ... NumpyIndexingAdapter(array)[np_indexer]
    array([ 2, 21,  8])
    r*   c                 S  s6   g | ].\}}t |tjr.t|d k || |n|qS )r   )r`   rk   rw   where)r7   r=   sr*   r*   r+   r:     s   z1_decompose_vectorized_indexer.<locals>.<listcomp>TZreturn_inverse)r`   r   rx   r   r   r   r   rb   re   r   r^   rk   uniquer   r   r   r   r   r   )ry   r   r   Zbackend_indexer_elemsZnp_indexer_elemsindexer_elemsr=   r   bk_slicenp_sliceoindvindbackend_indexer
np_indexerZbackend_indexer1Znp_indexer1r*   r*   r+   r   U  s6    '





  r   zBasicIndexer | OuterIndexerc                 C  sx  |t jkr| tdfS t| ttfs(tg }g }g }t| j|D ]^\}}t|tj	rr|
t|dk || | q@t|tr|dk r|
||  q@|
| q@|}|t jkrdd |D }	t|	dkrtt|	nd}
tt||D ]\}\}}t|tj	rF||
krF|
tt|t|d  |
|t|  qt|tj	r|tj|dd\}}|
| |
| qt|tr|
| qt||\}}|
| |
| qtt|tt|fS |t jkrt||D ]\}}t|trt||\}}|
| |
| nt|tr6|
| njt|tj	rrt|dk rr|
| |
td n.tj|dd\}}|
| |
|j|j  qtt|tt|fS |t jkstt||D ]\}}t|tj	r"|
tt|t|d  |
|t|  n:t|tr:|
| n"t||\}}|
| |
| qtt|tt|fS )	ad  
    Decompose outer indexer to the successive two indexers, where the
    first indexer will be used to index backend arrays, while the second one
    is used to index the loaded on-memory np.ndarray.

    Parameters
    ----------
    indexer : OuterIndexer or BasicIndexer
    indexing_support : One of the entries of IndexingSupport

    Returns
    -------
    backend_indexer: OuterIndexer or BasicIndexer
    np_indexers: an ExplicitIndexer (OuterIndexer / BasicIndexer)

    Notes
    -----
    This function is used to realize the vectorized indexing for the backend
    arrays that only support basic or outer indexing.

    As an example, let us consider to index a few elements from a backend array
    with a orthogonal indexer ([0, 3, 1], [2, 3, 2]).
    Even if the backend array only supports basic indexing, it is more
    efficient to load a subslice of the array than loading the entire array,

    >>> array = np.arange(36).reshape(6, 6)
    >>> backend_indexer = BasicIndexer((slice(0, 3), slice(2, 4)))
    >>> # load subslice of the array
    ... array = NumpyIndexingAdapter(array)[backend_indexer]
    >>> np_indexer = OuterIndexer((np.array([0, 2, 1]), np.array([0, 1, 0])))
    >>> # outer indexing for on-memory np.ndarray.
    ... NumpyIndexingAdapter(array)[np_indexer]
    array([[ 2,  3,  2],
           [14, 15, 14],
           [ 8,  9,  8]])
    r*   r   c                 S  sB   g | ]:}t |tjr:t|t| d  tt| ndqS )g      ?r   )r`   rk   rw   maxminrQ   r   rK   r*   r*   r+   r:     s   
(z,_decompose_outer_indexer.<locals>.<listcomp>Nr<   Tr   )r   r   r   r`   r   rx   r   rb   rk   rw   r^   r   r   r   rQ   Zargmaxr   	enumeratere   r  r  r   r   r   Zdiffr   r   r   r   )ry   r   r   r  r  Zpos_indexerr=   r   r   ZgainsZarray_indexr   ZpkeyZekeyr  r  r  r  r*   r*   r+   r     st    )
  


"

 
r   c           	   
   C  s   dd | j D }t|dkr | S dd | j D }t|dkrF|d jnd}d}g }t| j |D ]~\}}t|tjr|t||j	dt|   q^d||  d dt|| d   }|tj
|| | |d7 }q^tt |S )z<Return an identical vindex but slices are replaced by arraysc                 S  s   g | ]}t |tr|qS r*   r   r7   r>   r*   r*   r+   r:   )  s     
 z0_arrayize_vectorized_indexer.<locals>.<listcomp>r   c                 S  s   g | ]}t |tjr|qS r*   )r`   rk   rw   r
  r*   r*   r+   r:   -  s      r;   )r   r<   )rb   rQ   rg   r   r`   rk   rw   r^   r   r   rl   rm   r   )	ry   r   ZslicesZarraysr   r   rh   r>   rn   r*   r*   r+   r   '  s    "$
r   c                 C  s^   ddl m} t|| jk r"tdg }t|| jD ]\}}||dkrJ|nd q2|| |S )zECreate a dask array using the chunks hint for dimensions of size > 1.r   Nznot enough chunks in hintr<   r;   )	Z
dask.arrayr   rQ   rg   rD   r   r   r^   Z
from_array)r   chunksdaZ
new_chunkschunkrn   r*   r*   r+   _dask_array_with_chunks_hint;  s    r  c                 C  s   t tj| S rj   )	functoolsreducer   or_)argsr*   r*   r+   _logical_anyG  s    r  c                 C  s   dd | D } t |dd }g }| D ]j}t|tjrt|rL|t|| qt|tdrvdd l}||j	
| q|| q"|| q"tdd |D }|S )Nc                 s  s   | ]}t |ts|V  qd S rj   r   rK   r*   r*   r+   r   M  s     
 z,_masked_result_drop_slice.<locals>.<genexpr>r  sparser   c                 s  s   | ]}|d kV  qdS r   Nr*   rK   r*   r*   r+   r   ^  s     )getattrr`   rk   rw   r   r^   r  r   r  ZCOOZ
from_numpyr  )rR   dataZchunks_hintZnew_keysr=   r  maskr*   r*   r+   _masked_result_drop_sliceK  s    r  c                 C  s   t | tr8t| |j}tdd |D r,tt||}nt | tr| j}t||}tdd t||D }|t	ft
jft|   }t||j| }n2t | trtdd | jD }ntdt|  |S )a  Create a mask for indexing with a fill-value.

    Parameters
    ----------
    indexer : ExplicitIndexer
        Indexer with -1 in integer or ndarray value to indicate locations in
        the result that should be masked.
    shape : tuple
        Shape of the array being indexed.
    data : optional
        Data for which mask is being created. If data is a dask arrays, its chunks
        are used as a hint for chunks on the resulting mask. If data is a sparse
        array, the returned mask is also a sparse array.

    Returns
    -------
    mask : bool, np.ndarray, SparseArray or dask.array.Array with dtype=bool
        Same type as data. Has the same shape as the indexing result.
    c                 s  s   | ]}t |tV  qd S rj   r   rK   r*   r*   r+   r   x  s     zcreate_mask.<locals>.<genexpr>c                 s  s.   | ]&\}}t |trtj|| jV  qd S rj   )r`   re   rk   rl   rm   rn   )r7   r=   rn   r*   r*   r+   r   ~  s   
c                 s  s   | ]}|d kV  qdS r  r*   rK   r*   r*   r+   r     s     r   )r`   r   r   rb   anyrx   r  r   r   rc   rk   ZnewaxisrQ   r   Zbroadcast_tor   r   r   r~   )ry   r   r  rR   r  Z	base_maskZslice_shapeZexpanded_maskr*   r*   r+   create_maskb  s     



r  c                 C  sb   | dk}t | }|js$t | S t |}t dt ||d }|  }| ||  ||< |S )aH  Convert masked indices in a flat array to the nearest unmasked index.

    Parameters
    ----------
    index : np.ndarray
        One dimensional ndarray with dtype=int.

    Returns
    -------
    np.ndarray
        One dimensional ndarray with all values equal to -1 replaced by an
        adjacent non-masked element.
    r   r   r<   )rk   Zflatnonzerorn   Z
zeros_likemaximumZsearchsortedcopy)rT   ZmaskedZunmasked_locsZmasked_locsZ
prev_valueZ	new_indexr*   r*   r+   _posify_mask_subindexer  s    

r  c                 C  s    t dd | j D }t| |S )a  Convert masked values (-1) in an indexer to nearest unmasked values.

    This routine is useful for dask, where it can be much faster to index
    adjacent points than arbitrary points from the end of an array.

    Parameters
    ----------
    indexer : ExplicitIndexer
        Input indexer.

    Returns
    -------
    ExplicitIndexer
        Same type of input, with all values in ndarray keys equal to -1
        replaced by an adjacent non-masked element.
    c                 s  s2   | ]*}t |tjr&t| |jn|V  qd S rj   )r`   rk   rw   r  Zravelr   r   rK   r*   r*   r+   r     s   
z&posify_mask_indexer.<locals>.<genexpr>)rb   r~   )ry   rR   r*   r*   r+   posify_mask_indexer  s    r  bool)ry   r5   c                 C  sN   t | ttfrdS t | tjr(| jdkS t | trJt| oHt | d t S dS )zReturn False if indexer is a int, slice, a 1-dimensional list, or a 0 or
    1-dimensional ndarray; in all other cases return True
    Fr<   r   T)r`   r   re   rk   rw   rg   r3   r   r   r*   r*   r+   is_fancy_indexer  s    

r!  c                   @  s<   e Zd ZdZdZdd Zdd Zdd Zd	d
 Zdd Z	dS )r   z,Wrap a NumPy array to use explicit indexing.r   c                 C  s(   t |tjstdt||| _d S )Nz=NumpyIndexingAdapter only wraps np.ndarray. Trying to wrap {})r`   rk   rw   r   formatr~   r   r   r*   r*   r+   r     s    zNumpyIndexingAdapter.__init__c                 C  st   t |tr | j}t|| jj}nLt |tr<t| j}|j}n0t |trZ| j}|jt	f }nt
dt| ||fS r   )r`   r   r   r   r   r   r   rb   r   rc   r   r~   r)   rR   r   r*   r*   r+   _indexing_array_and_key  s    



z,NumpyIndexingAdapter._indexing_array_and_keyc                 C  s   | j |S rj   r   r   r*   r*   r+   r     s    zNumpyIndexingAdapter.transposec                 C  s   |  |\}}|| S rj   )r$  r#  r*   r*   r+   r     s    z NumpyIndexingAdapter.__getitem__c                 C  sP   |  |\}}z|||< W n0 tk
rJ   |jjsD|jjsDtdn Y nX d S )NzFAssignment destination is a view.  Do you want to .copy() array first?)r$  rD   flagsZ	writeableZowndata)r)   rR   r   r   r*   r*   r+   r     s    z NumpyIndexingAdapter.__setitem__N)
r-   r.   r/   r0   r   r   r$  r   r   r   r*   r*   r*   r+   r     s   	r   c                   @  s   e Zd ZdZdd ZdS )r   r   c                 C  s   t |dstd|| _d S )Nr   z^NdArrayLikeIndexingAdapter must wrap an object that implements the __array_function__ protocolr   r   r   r   r*   r*   r+   r   	  s
    
z#NdArrayLikeIndexingAdapter.__init__N)r-   r.   r/   r   r   r*   r*   r*   r+   r     s   r   c                   @  s4   e Zd ZdZdZdd Zdd Zdd Zd	d
 ZdS )r   z1Wrap an array API array to use explicit indexing.r   c                 C  s   t |dstd|| _d S )Nr   z\ArrayApiIndexingAdapter must wrap an object that implements the __array_namespace__ protocolr&  r   r*   r*   r+   r     s
    
z ArrayApiIndexingAdapter.__init__c                 C  s   t |tr| j|j S t |trd|j}| j}ttt|D ]"\}}|td f| |t	f  }q<|S t |t
rxtdntd| d S Nz$Vectorized indexing is not supportedzUnrecognized indexer: )r`   r   r   rb   r   reversedr3   r	  re   rc   r   r   )r)   rR   r   axissubkeyr*   r*   r+   r     s    



z#ArrayApiIndexingAdapter.__getitem__c                 C  sB   t |ttfr|| j|j< n"t |tr0tdntd| d S r'  )r`   r   r   r   rb   r   r   r   r*   r*   r+   r   /  s
    

z#ArrayApiIndexingAdapter.__setitem__c                 C  s   | j  }|| j |S rj   )r   r   Zpermute_dims)r)   r   Zxpr*   r*   r+   r   8  s    
z!ArrayApiIndexingAdapter.transposeN	r-   r.   r/   r0   r   r   r   r   r   r*   r*   r*   r+   r     s   	r   c                   @  s4   e Zd ZdZdZdd Zdd Zdd Zd	d
 ZdS )r   z/Wrap a dask array to support explicit indexing.r   c                 C  s
   || _ dS )z`This adapter is created in Variable.__getitem__ in
        Variable._broadcast_indexes.
        Nr   r   r*   r*   r+   r   B  s    zDaskIndexingAdapter.__init__c           	      C  s"  t |ts|d}g }t|jD ]J\}}t |tr\t|t| j	j
| r\|td  d}q|| q|r|t|t|}t |tr| j	|j S t |tr| j	j|j S t |tst|j}z| j	| W S  tk
r   | j	}ttt|D ] \}}|td f| |f  }q| Y S X d S )NFT)r`   r   r	  rb   r   r   Zarray_equivrk   rl   r   r   r^   re   r~   r   vindexr   rx   r   r(  r3   )	r)   rR   Zrewritten_indexerZnew_indexerZidimr=   r   r)  r*  r*   r*   r+   r   H  s4    
 

zDaskIndexingAdapter.__getitem__c                 C  s   t dtdkr~t|tr(|| j|j< qt|trB|| jj|j< qt|trt	dd |jD }|dkrpt
d|| j|j< ntdd S )NZdaskz	2021.04.1c                 s  s    | ]}t |trd ndV  qdS )r   r<   Nr   rK   r*   r*   r+   r   s  s    z2DaskIndexingAdapter.__setitem__.<locals>.<genexpr>r<   z@xarray can't set arrays with multiple array indices to dask yet.a  This variable's data is stored in a dask array, and the installed dask version does not support item assignment. To assign to this variable, you must either upgrade dask orfirst load the variable into memory explicitly using the .load() method or accessing its .values attribute.)r   r   r`   r   r   rb   r   r,  r   sumr   r   )r)   rR   r   Znum_non_slicesr*   r*   r+   r   l  s"    


zDaskIndexingAdapter.__setitem__c                 C  s   | j |S rj   r   r   r*   r*   r+   r     s    zDaskIndexingAdapter.transposeNr+  r*   r*   r*   r+   r   =  s   $r   c                   @  s   e Zd ZdZdZd#dddddZed	d
ddZd$dddddZedd
ddZ	dd Z
dd
ddZdd
ddZdd
ddZd%dd d d!d"ZdS )&r   zDWrap a pandas.Index to preserve dtypes and handle explicit indexing.)r   _dtypeNzpd.Indexr   )r   r   c                 C  s:   ddl m} ||| _|d kr*t|| _nt|| _d S )Nr   )safe_cast_to_index)xarray.core.indexesr/  r   r   r.  rk   r   )r)   r   r   r/  r*   r*   r+   r     s
    
zPandasIndexingAdapter.__init__znp.dtyper   c                 C  s   | j S rj   )r.  r(   r*   r*   r+   r     s    zPandasIndexingAdapter.dtype
np.ndarrayr   r5   c              	   C  sN   |d kr| j }| j}t|tjr>tt |d}W 5 Q R X tj	|j
|dS )Nobjectr   )r   r   r`   r   ZPeriodIndexr   AttributeErrorZastyperk   r   valuesr   r*   r*   r+   r     s    
zPandasIndexingAdapter.__array__r   c                 C  s   t | jfS rj   )rQ   r   r(   r*   r*   r+   r     s    zPandasIndexingAdapter.shapec                 C  sv   |t jkrtdd}nVt|tr8tt|d|d}n6t|t jrTt	|
 }n| jtkrntj	|| jd}t|S )NNaTnsr   r   )r   r6  rk   Z
datetime64r`   r   Ztimedelta64r  Z	Timestampr   Zto_datetime64r   r3  r   )r)   itemr*   r*   r+   _convert_scalar  s    


z%PandasIndexingAdapter._convert_scalarzZPandasIndexingAdapter | NumpyIndexingAdapter | np.ndarray | np.datetime64 | np.timedelta64c                 C  sz   |j }t|t r"t|dkr"|\}t|dddkrDtt| | S | j| }t|tj	rlt
| || jdS | |S d S )Nr<   rg   r   r   )rb   r`   rQ   r  r   rk   r   r   r   r   r~   r   r9  )r)   ry   rR   r   r*   r*   r+   r     s    	
z!PandasIndexingAdapter.__getitem__c                 C  s   | j S rj   r   r   r*   r*   r+   r     s    zPandasIndexingAdapter.transposestrc                 C  s    t | j d| jd| jdS )Nr   , dtype=r   )r~   r-   r   r   r(   r*   r*   r+   r     s    zPandasIndexingAdapter.__repr__Tr   deepr5   c                 C  s(   |r| j jddn| j }t| || jS NT)r=  )r   r  r~   r.  r)   r=  r   r*   r*   r+   r    s    zPandasIndexingAdapter.copy)N)N)T)r-   r.   r/   r0   r   r   r   r   r   r   r9  r   r   r   r  r*   r*   r*   r+   r     s   

r   c                      s   e Zd ZdZdZd#dddd fdd	Zd$dd
d fddZ fddZ fddZdd fddZ	d
dddZ
dddddZddddZd%dd d d!d"Z  ZS )&PandasMultiIndexingAdapterzHandles explicit indexing for a pandas.MultiIndex.

    This allows creating one instance for each multi-index level while
    preserving indexing efficiency (memoized + might reuse another instance with
    the same multi-index).

    )r   r.  leveladapterNzpd.MultiIndexr   z
str | None)r   r   rA  c                   s   t  || || _d S rj   )r   r   rA  )r)   r   r   rA  r   r*   r+   r     s    z#PandasMultiIndexingAdapter.__init__r1  r2  c                   sB   |d kr| j }| jd k	r2tj| j| jj|dS t |S d S r   )	r   rA  rk   r   r   Zget_level_valuesr5  r   r   r   r   r*   r+   r     s    
 z$PandasMultiIndexingAdapter.__array__c                   s<   t |tr0| jd k	r0t| jj| j}|| }t |S rj   )r`   rb   rA  r   namesrT   r   r9  )r)   r8  idxr   r*   r+   r9    s    z*PandasMultiIndexingAdapter._convert_scalarc                   s&   t  |}t|t| r"| j|_|S rj   )r   r   r`   r~   rA  )r)   ry   r   r   r*   r+   r     s    z&PandasMultiIndexingAdapter.__getitem__r:  r   c                   sH   | j d krt  S d| jd| j d| jd}t| j | S d S )Nr   z, level=r;  r   )rA  r   r   r   r   r~   r-   )r)   propsr   r*   r+   r     s
    

z#PandasMultiIndexingAdapter.__repr__c                 C  sb   t dtd d }| j|krT|d }ttd|t| dg}| t|f }n| }t|S )Nd   Zdisplay_values_thresholdr   r   )r  r   rn   rk   Zconcatenaterl   r   r   )r)   	thresholdposrm   Zsubsetr*   r*   r+   _get_array_subset  s    
 z,PandasMultiIndexingAdapter._get_array_subsetr   )	max_widthr5   c                 C  s,   ddl m} | jd krdS ||  |S d S )Nr   )format_array_flatZ
MultiIndex)xarray.core.formattingrK  rA  rI  )r)   rJ  rK  r*   r*   r+   _repr_inline_)  s    
z(PandasMultiIndexingAdapter._repr_inline_c                 C  s(   ddl m} ||  }dt| dS )Nr   )short_numpy_reprz<pre>z</pre>)rL  rN  rI  r	   )r)   rN  Z
array_reprr*   r*   r+   _repr_html_1  s    z&PandasMultiIndexingAdapter._repr_html_Tr   r<  c                 C  s,   |r| j jddn| j }t| || j| jS r>  )r   r  r~   r.  rA  r?  r*   r*   r+   r  7  s    zPandasMultiIndexingAdapter.copy)NN)N)T)r-   r.   r/   r0   r   r   r   r9  r   r   rI  rM  rO  r  r   r*   r*   r   r+   r@    s     	
	r@  )NN)N)N)h
__future__r   enumr  r   collectionsr   r   
contextlibr   Zdataclassesr   r   datetimer   htmlr	   typingr
   r   r   r   r   r   Znumpyrk   Zpandasr   Zpackaging.versionr   Zxarray.corer   Zxarray.core.nputilsr   Zxarray.core.optionsr   Zxarray.core.pycompatr   r   r   r   Zxarray.core.typesr   Zxarray.core.utilsr   r   r   r   Znumpy.typingr   r0  r   Zxarray.core.variabler   r    rG   rU   rZ   ri   ro   rq   rv   rz   r{   r   r   r   r   r   r   r   r   r   ZLazilyOuterIndexedArrayr   r   r   r   r   r   r   r   r   Enumr   r   r   r   r   r   r   r  r  r  r  r  r  r!  r   r   r   r   r   r@  r*   r*   r*   r+   <module>   s    -&&  -),M2 ##
R 

-6+L`