U
    Cvf                     @  s  d dl m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 d dlZd dlZd dlmZmZmZ d dlmZ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"m#Z# dZ$dZ%er8d dl&m'Z' d dl(m)Z) eeedf ee*e*f Z+eedf Z,e
ee#f Z-eeef Z.ee/e	e df Z0ee)e'f Z1G dd dej2Z3G dd dej2Z4dddddZ5dSddddddZ6dddddZ7ddddd Z8dTdd!d"d#d$Z9dUddd%dd&d'Z:d(d)d*d+Z;dVddddd,d-Z<dWdd/ddd0d1d2Z=dXd3dd/d/d/d/d/d4d4dd5
d6d7Z>d8d%d9d:d;Z?d8d%d9d<d=Z@dYd8d>d/d/d/d/d?d4d4d@dA
dBdCZAdZdDd/d/d/d/d?d4d4dEdF	dGdHZBd[d8d>d/d/d/dIdJdKdLZCdMdN ZDdOdP ZEdQdR ZFdS )\    )annotationsN)defaultdict)TYPE_CHECKINGAnyHashableIterableMappingMutableMappingTupleUnion)stringstimes	variables)SerializationWarningpop_to)duck_array_opsindexing)_contains_datetime_like_objectscontains_cftime_datetimes)is_duck_dask_array)IndexVariableVariable)
boundsZgrid_mappingZclimatologyZgeometryZnode_coordinatesZ
node_countZpart_node_countZinterior_ringcell_measuresformula_terms)r   r   AbstractDataStoreDataset.c                   @  s0   e Zd ZdZdZdd Zedd Zdd Zd	S )
NativeEndiannessArraya  Decode arrays on the fly from non-native to native endianness

    This is useful for decoding arrays from netCDF3 files (which are all
    big endian) into native endianness, so they can be used with Cython
    functions, such as those found in bottleneck and pandas.

    >>> x = np.arange(5, dtype=">i2")

    >>> x.dtype
    dtype('>i2')

    >>> NativeEndiannessArray(x).dtype
    dtype('int16')

    >>> indexer = indexing.BasicIndexer((slice(None),))
    >>> NativeEndiannessArray(x)[indexer].dtype
    dtype('int16')
    arrayc                 C  s   t || _d S Nr   Zas_indexabler!   selfr!    r&   6/tmp/pip-unpacked-wheel-h316xyqg/xarray/conventions.py__init__Q   s    zNativeEndiannessArray.__init__c                 C  s   t | jjjt| jjj S r"   )npdtyper!   kindstritemsizer%   r&   r&   r'   r*   T   s    zNativeEndiannessArray.dtypec                 C  s   t j| j| | jdS Nr*   r)   Zasarrayr!   r*   r%   keyr&   r&   r'   __getitem__X   s    z!NativeEndiannessArray.__getitem__N	__name__
__module____qualname____doc__	__slots__r(   propertyr*   r4   r&   r&   r&   r'   r   ;   s   
r   c                   @  s0   e Zd ZdZdZdd Zedd Zdd Zd	S )
BoolTypeArraya  Decode arrays on the fly from integer to boolean datatype

    This is useful for decoding boolean arrays from integer typed netCDF
    variables.

    >>> x = np.array([1, 0, 1, 1, 0], dtype="i1")

    >>> x.dtype
    dtype('int8')

    >>> BoolTypeArray(x).dtype
    dtype('bool')

    >>> indexer = indexing.BasicIndexer((slice(None),))
    >>> BoolTypeArray(x)[indexer].dtype
    dtype('bool')
    r    c                 C  s   t || _d S r"   r#   r$   r&   r&   r'   r(   q   s    zBoolTypeArray.__init__c                 C  s
   t dS )Nbool)r)   r*   r.   r&   r&   r'   r*   t   s    zBoolTypeArray.dtypec                 C  s   t j| j| | jdS r/   r1   r2   r&   r&   r'   r4   x   s    zBoolTypeArray.__getitem__Nr5   r&   r&   r&   r'   r<   \   s   
r<   r   
T_VarTuple)varreturnc                 C  s   | j | j| j | j fS r"   )dimsdataattrscopyencodingr?   r&   r&   r'   _var_as_tuple|   s    rG   T_Name)r?   namer@   c                 C  s   d| j kr| j d dtfkrt| \}}}}t|d}|| jkrt|tjrt| jtjrd| j	krd| j	krt
jd| dtdd t|}|j|d	}t||||d
d} | S )Nr*   S1
_FillValueZmissing_valuezsaving variable zT with floating point data as an integer dtype without any _FillValue to use for NaNs
   
stacklevelr0   Tfastpath)rE   r,   rG   r)   r*   pop
issubdtypeintegerfloatingrC   warningswarnr   Zaroundastyper   )r?   rI   rA   rB   rC   rE   r*   r&   r&   r'   maybe_encode_nonstring_dtype   s(    


rX   c                 C  s<   d| j kr8d| jkr8t| jtjr8| jtj| j d< | S )NrK   )rC   rE   r)   rR   r*   rT   typenanrF   r&   r&   r'   maybe_default_fill_value   s    r[   c                 C  s\   | j tkrXd| jkrXd| jkrXt| \}}}}d|d< tj|ddd}t||||dd} | S )Nr*   r=   i1T)r*   rD   rO   )r*   r=   rE   rC   rG   r   rW   r   )r?   rA   rB   rC   rE   r&   r&   r'   maybe_encode_bools   s    r]   znp.dtype)rI   r@   c                 C  s   | j jdkrtd| jdkr(t tS | d| j  }t|trJt	
tS t|tr^t	
tS t|j }|jdkrx|S td|dS )z]Given an object array with no missing values, infer its dtype from its
    first element
    Oz1infer_type must be called on a dtype=object arrayr   )r   zXunable to infer dtype on variable {!r}; xarray cannot serialize arbitrary Python objectsN)r*   r+   	TypeErrorsizer)   floatndim
isinstancebytesr   Zcreate_vlen_dtyper,   r!   
ValueErrorformat)r!   rI   elementr*   r&   r&   r'   _infer_dtype   s"    






rh   Nonec                 C  s,   t | tr(t |  tjr(td|d S )Nzvariable {!r} is a MultiIndex, which cannot yet be serialized to netCDF files (https://github.com/pydata/xarray/issues/1077). Use reset_index() to convert MultiIndex levels into coordinate variables instead.)rc   r   Zto_indexpdZ
MultiIndexNotImplementedErrorrf   )r?   rI   r&   r&   r'   ensure_not_multiindex   s    rl   znp.typing.DTypeLiker0   c                 C  s   t | j|}| |d< |S )zCreate a copy of an array with the given dtype.

    We use this instead of np.array() to ensure that custom object dtypes end
    up on the resulting array.
    .)r)   emptyshape)rB   r*   resultr&   r&   r'   _copy_with_dtype   s    rp   c           
      C  s   | j jdkrt| \}}}}t|r>td|t | }t	
|}| r||  }t||}t|rtd}	n4t|rd}	n$t|tjst t}|tj}	t||d}|	||< nt|t||d}|j jdks|j jstt||||dd} | S )Nr^   a  variable {} has data in the form of a dask array with dtype=object, which means it is being loaded into memory to determine a data type that can be safely stored on disk. To avoid this, coerce this variable to a fixed-size dtype with astype() before saving it.     r0   TrO   )r*   r+   rG   r   rU   rV   rf   r   Zcomputerj   Zisnullanyrh   r   Zis_bytes_dtypeZis_unicode_dtyper)   rR   rT   ra   rY   rZ   rp   metadataAssertionErrorr   )
r?   rI   rA   rB   rC   rE   missingZnon_missing_valuesZinferred_dtypeZ
fill_valuer&   r&   r'   ensure_dtype_not_object   s6    






rw   Tr=   )r?   
needs_copyrI   r@   c                 C  s   t | |d t t t t t fD ]}|j| |d} q.t	| |d} t
| } t| } t| |d} tD ]}t| j| j| qn| S )a  
    Converts an Variable into an Variable which follows some
    of the CF conventions:

        - Nans are masked using _FillValue (or the deprecated missing_value)
        - Rescaling via: scale_factor and add_offset
        - datetimes are converted to the CF 'units since time' format
        - dtype encodings are enforced.

    Parameters
    ----------
    var : Variable
        A variable holding un-encoded data.

    Returns
    -------
    out : Variable
        A variable which has been encoded as described above.
    rI   )rl   r   CFDatetimeCoderCFTimedeltaCoderr   CFScaleOffsetCoderCFMaskCoderUnsignedIntegerCoderencoderX   r[   r]   rw   CF_RELATED_DATAr   rE   rC   )r?   rx   rI   coder	attr_namer&   r&   r'   encode_cf_variable  s    r   r   zbool | None)
rI   r?   concat_charactersmask_and_scaledecode_timesdecode_endiannessstack_char_dim
use_cftimedecode_timedeltar@   c	                 C  s$  t |r|S |j}	|dkr|}|rF|r8t j|| d}t |}|rtt t t	 fD ]}
|
j|| d}q`|rt
 j|| d}|rt
j|dj|| d}t|\}}}}|r|jjst|}|j}	|d|	 d|kr|d dkr|d= t|}t|st|}t||||ddS )a  
    Decodes a variable which may hold CF encoded information.

    This includes variables that have been masked and scaled, which
    hold CF style time variables (this is almost always the case if
    the dataset has been serialized) and which have strings encoded
    as character arrays.

    Parameters
    ----------
    name : str
        Name of the variable. Used for better error messages.
    var : Variable
        A variable holding potentially CF encoded information.
    concat_characters : bool
        Should character arrays be concatenated to strings, for
        example: ["h", "e", "l", "l", "o"] -> "hello"
    mask_and_scale : bool
        Lazily scale (using scale_factor and add_offset) and mask
        (using _FillValue). If the _Unsigned attribute is present
        treat integer arrays as unsigned.
    decode_times : bool
        Decode cf times ("hours since 2000-01-01") to np.datetime64.
    decode_endianness : bool
        Decode arrays from non-native to native endianness.
    stack_char_dim : bool
        Whether to stack characters into bytes along the last dimension of this
        array. Passed as an argument because we need to look at the full
        dataset to figure out if this is appropriate.
    use_cftime : bool, optional
        Only relevant if encoded dates come from a standard calendar
        (e.g. "gregorian", "proleptic_gregorian", "standard", or not
        specified).  If None (default), attempt to decode times to
        ``np.datetime64[ns]`` objects; if this is not possible, decode times to
        ``cftime.datetime`` objects. If True, always decode times to
        ``cftime.datetime`` objects, regardless of whether or not they can be
        represented using ``np.datetime64[ns]`` objects.  If False, always
        decode times to ``np.datetime64[ns]`` objects; if this is not possible
        raise an error.

    Returns
    -------
    out : Variable
        A variable holding the decoded equivalent of var.
    Nry   )r   r*   r=   T)rE   rP   )r   r*   r   ZCharacterArrayCoderdecodeZEncodedStringCoderr   r~   r}   r|   r   r{   rz   Zunpack_for_decodingZisnativer   
setdefaultr<   r   r   ZLazilyIndexedArrayr   )rI   r?   r   r   r   r   r   r   r   Zoriginal_dtyper   Z
dimensionsrB   
attributesrE   r&   r&   r'   decode_cf_variable<  s<    9

r   T_Variables)r   r@   c                 C  s   |   D ]t}|j}|d}t|to,d|k}|rd|kr|d | kr| |d  j}|d|d  d|kr|d|d  qdS )a  Adds time attributes to time bounds variables.

    Variables handling time bounds ("Cell boundaries" in the CF
    conventions) do not necessarily carry the necessary attributes to be
    decoded. This copies the attributes from the time variable to the
    associated boundaries.

    See Also:

    http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/
         cf-conventions.html#cell-boundaries

    https://github.com/pydata/xarray/issues/2565
    unitssincer   calendarN)valuesrC   getrc   r,   r   )r   vrC   r   has_date_unitsZbounds_attrsr&   r&   r'   _update_bounds_attributes  s    
r   c                 C  s   |   D ]\}}|j}|j}d|ko.d|d k}t|jtjpFt|}|r||s|d|kr||d | kr|t	d
||d t |rd|kr|d | kr| |d  j}|d|d  d|kr|d|d  qdS )a  Adds time encoding to time bounds variables.

    Variables handling time bounds ("Cell boundaries" in the CF
    conventions) do not necessarily carry the necessary attributes to be
    decoded. This copies the encoding from the time variable to the
    associated bounds variable so that we write CF-compliant files.

    See Also:

    http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/
         cf-conventions.html#cell-boundaries

    https://github.com/pydata/xarray/issues/2565
    r   r   r   a3  Variable '{0}' has datetime type and a bounds variable but {0}.encoding does not have units specified. The units encodings for '{0}' and '{1}' will be determined independently and may not be equal, counter to CF-conventions. If this is a concern, specify a units encoding for '{0}' before writing to a file.r   N)itemsrC   rE   r)   rR   r*   Z
datetime64r   rU   rV   rf   UserWarningr   )r   rI   r   rC   rE   r   Zis_datetime_typeZbounds_encodingr&   r&   r'   _update_bounds_encoding  s>     
 r   T_AttrsT_DropVariablesz*tuple[T_Variables, T_Attrs, set[Hashable]])
r   r   r   r   r   decode_coordsdrop_variablesr   r   r@   c	                   s  t t  D ]}	|	jD ]}
 |
 |	 qqddd fdd}t }t|tr^|g}n|dkrjg }t|}|r~t i }	 D ]\}}	||krq|o|	j
dko|	jdko||	jd	 }z t||	||||||d
||< W n< tk
r  } zt|d|d| W 5 d}~X Y nX |dkr|| j}d|kr|d }| }tfdd|D r||| jd< |d= || |dkrtD ]}||kr|| }|tkr| }nLdd |dD }t|d dkrtjd|dddd |ddd }tfdd|D r:||| j|< || n.fdd|D }tjd|dd|dd ||= qq|rt|ddtrt|}|d}||  |||fS ) zK
    Decode several CF encoded variables.

    See: decode_cf_variable
    r   r=   )dimr@   c                   s>   | krdS  |  D ]$}|j jdks2| |jd kr dS qdS )NFST)r*   r+   rA   )r   r   Zdimensions_used_byr   r&   r'   	stackable  s    z&decode_cf_variables.<locals>.stackableNrJ   r   r   )r   r   r   r   r   r   zFailed to decode variable z: )Tcoordinatesallr   c                 3  s   | ]}| kV  qd S r"   r&   ).0kr   r&   r'   	<genexpr>8  s     z&decode_cf_variables.<locals>.<genexpr>r   c                 S  s   g | ]}|  D ]}|qqS r&   )split)r   partZrole_or_namer&   r&   r'   
<listcomp>D  s   
 z'decode_cf_variables.<locals>.<listcomp>:      z
Attribute sz
 malformed   rM   c                 3  s   | ]}| kV  qd S r"   r&   )r   var_namer   r&   r'   r   N  s     c                   s   g | ]}| kr|qS r&   r&   )r   Z	proj_namer   r&   r'   r   R  s   zVariable(s) referenced in z not in variables: )r   listr   rA   appendsetrc   r,   r   r   r*   rb   r   	ExceptionrY   rC   r   r   rE   updater   CF_RELATED_DATA_NEEDS_PARSINGlenrU   rV   r   dictrQ   )r   r   r   r   r   r   r   r   r   r   dr   coord_namesnew_varsr   r   eZ	var_attrsZ	coord_strZvar_coord_namesr   Zattr_valZ	var_namesZroles_and_namesZ referenced_vars_not_in_variablesZcrdsr&   r   r'   decode_cf_variables  s    
	

*






 

r   T_DatasetOrAbstractstorer   )	objr   r   r   r   r   r   r   r@   c                 C  s   ddl m} ddlm}	 t| |	rF| j}
| j}t| j}| j	}| j
}n4t| |rr|  \}
}t }| j}|  }ntdt|
||||||||d	\}
}}|	|
|d}||||
}|| ||_
|S )a  Decode the given Dataset or Datastore according to CF conventions into
    a new Dataset.

    Parameters
    ----------
    obj : Dataset or DataStore
        Object to decode.
    concat_characters : bool, optional
        Should character arrays be concatenated to strings, for
        example: ["h", "e", "l", "l", "o"] -> "hello"
    mask_and_scale : bool, optional
        Lazily scale (using scale_factor and add_offset) and mask
        (using _FillValue).
    decode_times : bool, optional
        Decode cf times (e.g., integers since "hours since 2000-01-01") to
        np.datetime64.
    decode_coords : bool or {"coordinates", "all"}, optional
        Controls which variables are set as coordinate variables:

        - "coordinates" or True: Set variables referred to in the
          ``'coordinates'`` attribute of the datasets or individual variables
          as coordinate variables.
        - "all": Set variables referred to in  ``'grid_mapping'``, ``'bounds'`` and
          other attributes as coordinate variables.
    drop_variables : str or iterable, optional
        A variable or list of variables to exclude from being parsed from the
        dataset. This may be useful to drop variables with problems or
        inconsistent values.
    use_cftime : bool, optional
        Only relevant if encoded dates come from a standard calendar
        (e.g. "gregorian", "proleptic_gregorian", "standard", or not
        specified).  If None (default), attempt to decode times to
        ``np.datetime64[ns]`` objects; if this is not possible, decode times to
        ``cftime.datetime`` objects. If True, always decode times to
        ``cftime.datetime`` objects, regardless of whether or not they can be
        represented using ``np.datetime64[ns]`` objects.  If False, always
        decode times to ``np.datetime64[ns]`` objects; if this is not possible
        raise an error.
    decode_timedelta : bool, optional
        If True, decode variables and coordinates with time units in
        {"days", "hours", "minutes", "seconds", "milliseconds", "microseconds"}
        into timedelta objects. If False, leave them encoded as numbers.
        If None (default), assume the same value of decode_time.

    Returns
    -------
    decoded : Dataset
    r   r   r   z,can only decode Dataset or DataStore objects)r   r   r   )rC   )xarray.backends.commonr   xarray.core.datasetr   rc   
_variablesrC   r   coords_closerE   loadcloseZget_encodingr_   r   Z
set_coordsunionintersectionZ	set_close)r   r   r   r   r   r   r   r   r   r   varsrC   Zextra_coordsr   rE   r   Zdsr&   r&   r'   	decode_cfe  s<    :




r   ztuple[T_Variables, T_Attrs])r   r   r   r   r   r@   c                 C  s   t | ||||\} }}| |fS )a{  
    Decode a set of CF encoded variables and attributes.

    Parameters
    ----------
    variables : dict
        A dictionary mapping from variable name to xarray.Variable
    attributes : dict
        A dictionary mapping from attribute name to value
    concat_characters : bool
        Should character arrays be concatenated to strings, for
        example: ["h", "e", "l", "l", "o"] -> "hello"
    mask_and_scale : bool
        Lazily scale (using scale_factor and add_offset) and mask
        (using _FillValue).
    decode_times : bool
        Decode cf times ("hours since 2000-01-01") to np.datetime64.

    Returns
    -------
    decoded_variables : dict
        A dictionary mapping from variable name to xarray.Variable objects.
    decoded_attributes : dict
        A dictionary mapping from attribute name to values.

    See Also
    --------
    decode_cf_variable
    )r   )r   r   r   r   r   _r&   r&   r'   
cf_decoder  s    $    
r   c                   sP  t |}t|D ]6}t|trd|krtjd|tdd || q|	 }t
t }t  |D ]~ |   j}|  D ]f\}||kr|jkrt |t jkr||   t fddtD rx  |  qxqbdd |  D } t  }|  D ]\}}	|	j}
|	j}d	|kr:d	|
kr:td
|dd	|krT|d	d ksnd	|
kr|
d	d kr|d	d  |
d	d  qt|
|d	p|d	}|s|| rdfdd|| D }|r||d	< d	|kr||d	   q|| |rHt|}d	|kr4td|dt ndtt||d	< | |fS )N zcoordinate {!r} has a space in its name, which means it cannot be marked as a coordinate on disk and will be saved as a data variable instead   rM   c                 3  s(   | ] }|j ko j |kV  qd S r"   )rE   r   )r   r   )
coord_namer   r&   r'   r     s   z&_encode_coordinates.<locals>.<genexpr>c                 S  s   i | ]\}}||j d dqS )F)deep)rD   r   r   r   r&   r&   r'   
<dictcomp>  s      z'_encode_coordinates.<locals>.<dictcomp>r   z<'coordinates' found in both attrs and encoding for variable .c                 3  s   | ]}| krt |V  qd S r"   )r,   )r   r   )not_technically_coordinatesr&   r'   r   /  s   z$cannot serialize global coordinates zu because the global attribute 'coordinates' already exists. This may prevent faithful roundtrippingof xarray datasets)r   r   rc   r,   rU   rV   rf   r   discardrD   r   rA   r   addrs   r   rE   rC   re   r   rQ   r   joinr   r   difference_updater   map)r   r   non_dim_coord_namesrI   Zglobal_coordinatesZvariable_coordinatesZtarget_dimsr   Zwritten_coordsr?   rE   rC   Z
coords_strZcoordinates_textr&   )r   r   r   r'   _encode_coordinates  s    






r   c                 C  s&   t | jt | j }t| j| j|dS )a1  Encode coordinates on the given dataset object into variable specific
    and global attributes.

    When possible, this is done according to CF conventions.

    Parameters
    ----------
    dataset : Dataset
        Object to encode.

    Returns
    -------
    variables : dict
    attrs : dict
    )r   )r   r   rA   r   r   rC   )Zdatasetr   r&   r&   r'   encode_dataset_coordinatesO  s      r   c                 C  s   t |  dd |  D }| D ]r}d|jkr:|jd nd}|r"||kr"dD ]D}||| jkrN||jkrN|| j| |j| krN|| j| qNq"||fS )a  
    Encode a set of CF encoded variables and attributes.
    Takes a dicts of variables and attributes and encodes them
    to conform to CF conventions as much as possible.
    This includes masking, scaling, character array handling,
    and CF-time encoding.

    Parameters
    ----------
    variables : dict
        A dictionary mapping from variable name to xarray.Variable
    attributes : dict
        A dictionary mapping from attribute name to value

    Returns
    -------
    encoded_variables : dict
        A dictionary mapping from variable name to xarray.Variable,
    encoded_attributes : dict
        A dictionary mapping from attribute name to value

    See Also
    --------
    decode_cf_variable, encode_cf_variable
    c                 S  s   i | ]\}}|t ||d qS )ry   )r   r   r&   r&   r'   r     s      zcf_encoder.<locals>.<dictcomp>r   N)	r   Zstandard_nameZaxisZpositiver   Z	long_nameZ
leap_monthZ	leap_yearZmonth_lengths)r   r   r   rC   rQ   )r   r   r   r?   r   attrr&   r&   r'   
cf_encodere  s    r   )N)N)N)N)TN)TTTTTNN)TTTTNNN)TTTTNNN)TTT)G
__future__r   rU   collectionsr   typingr   r   r   r   r   r	   r
   r   Znumpyr)   Zpandasrj   Zxarray.codingr   r   r   Zxarray.coding.variablesr   r   Zxarray.corer   r   Zxarray.core.commonr   r   Zxarray.core.pycompatr   Zxarray.core.variabler   r   r   r   r   r   r   r   r   r>   rH   r   r   r,   r   r   ZExplicitlyIndexedNDArrayMixinr   r<   rG   rX   r[   r]   rh   rl   rp   rw   r   r   r   r   r   r   r   r   r   r   r&   r&   r&   r'   <module>   s   (! /   /       "g5       "u        c   *`