o
    Uݢg3                     @  sr  U d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	m
Z
mZ ddlmZ ddlmZmZmZ ddlZedeeeedZdZd	ed
< dZd	ed< dZd	ed< edZded< edZded< dTddZdUddZ dVd d!Z!e"ej#e$e%ej&fdWd'd(Z'dXd*d+Z(dYdZd/d0Z)d[d1d2Z*eee+eee,e-e%e.e*e e!e'fd\dFdGZ/G dHdI dIej0Z1d]dLdMZ2d,dNd^dRdSZ3dS )_a,  Methods for safely encoding values to json.

The json standard does not permit encoding NaN, but Python will still happily
do it, which can cause problems for other programs.  This module contains code
to fix those values up, as well as convert numpy objects to things which encode
properly in json.
    )annotationsN)Callable	GeneratorIterableIteratorMapping)PurePath)IOAnyTypeVar_T0NaNstr
NAN_STRINGinfPOS_INF_STRINGz-infNEG_INF_STRINGz-Inffloat_NEG_INFz+Inf_POS_INFxreturnfloat | _T0c                 C  s,   | t krtt S | tkrtS | tkrtS | S )zConverts back a special numeric value encoded by json_sanitize.

    Args:
        x: a string encoded value or float

    Returns:
        a float or the original value
    )r   r   r   r   r   r   )r    r   _/oak/stanford/groups/akundaje/marinovg/programs/cellranger-9.0.1/lib/python/tenkit/safe_json.pydesanitize_value#   s   	r   kr
   c                 C  s>   t | tr| S t | tr|  S t | tr| rdS dS t| S )Ntruefalse)
isinstancer   bytesdecodebool)r   r   r   r   _sanitize_key6   s   


r#   data3bytes | PurePath | float | np.integer | np.floatingNone | str | int | floatc                 C  s   t | ttB tB r| S t | tr|  S t | trt| S t | tjr't| S t | t	tj
B rFt| r6tS | tkr<tS | tkrBtS t	| S | S N)r   r   intr"   r    r!   r   npintegerr   floatingmathisnanr   r   r   r   r   r$   r   r   r   _sanitize_scalarA   s"   


r/   dict
type[dict]fields1Callable[[Any], Iterable[dataclasses.Field[Any]]] Iterable[tuple[Any, Any]] | Nonec                   s   t  |r	  S | r fdd| D S | dr@| dr'  S | dr0  S | dr@ fdd  D S d S )Nc                 3  s"    | ]}|j  |j fV  qd S r'   )name).0fieldr$   getattrr   r   	<genexpr>g   s     z_dict_items.<locals>.<genexpr>keys	iteritemsitems__getitem__c                 3  s    | ]	}| | fV  qd S r'   r   )r6   keyr.   r   r   r:   q   s    )r   r=   r<   r;   )r$   r0   r2   r9   hasattris_dataclassr   r8   r   _dict_itemsX   s   




rB   5None | dict[str, Any] | int | str | float | list[Any]c                 C  s   t | r| S t| ttB tB tjB tjB rt| S t	|  }dur(dd |D S t
| dr4dd | D S t
| drD| jdkrDt|  S | S )	a  Convert data into a form that will correctly serialize to json.

    Yuck yuck yuck yuck yuck!
    The default JSON encoders do bad things if you try to encode
    NaN/Infinity/-Infinity as JSON.  This code takes a nested data structure
    composed of: atoms, dicts, or array-like iteratables and finds all of the
    not-really-a-number floats and converts them to an appropriate string for
    subsequent jsonification.

    Note:
        Don't call this and then pass the result to `json.dump`.  It's
        considerably more efficient to use `dump_numpy`, which avoids
        constructing the entire sanitized object in memory.
    Nc                 S  s   i | ]\}}t |t|qS r   )r#   json_sanitize)r6   r   valuer   r   r   
<dictcomp>   s    z!json_sanitize.<locals>.<dictcomp>__iter__c                 S  s   g | ]}t |qS r   )rD   r6   itemr   r   r   
<listcomp>   s    z!json_sanitize.<locals>.<listcomp>shaper   )_is_safer   r    r   r   r)   r+   r*   r/   rB   r@   rK   rI   )r$   
dict_itemsr   r   r   rD   u   s   
rD   Fprettyr"   c                 K  s.   | dd |rt| tj| fdti|S )a  Dump an object to a string as json, after sanitizing it.

    Note:
        Rather than writing the result of this call to a file, it's considerably
        more efficient to use `dump_numpy`, which doesn't build the entire
        string up in memory.

    Args:
        data: The object to encode.
        pretty: If true, set various defaults for pretty-printed json.
        **kwargs: Additional arguments to pass to the json encoder.
    	allow_nanFcls)
setdefault_pretty_kwargsjsondumpsNumpyAwareJSONEncoder)r$   rN   kwargsr   r   r   safe_jsonify   s   rW   c                 C  sv   | du st | ttB tB rdS t | trt| S t | tr)tdd | 	 D S t | t
tB r9tdd | D S dS )a  Returns True if we can use the default encoder.

    This allows us to short-circuit all of the custom logic to use the native
    implementation instead.

    In the case of json_sanitize, this can save quite a bit of ram copying
    objects which don't need to be copied.  In the case of NumpyAwareJSONEncoder,
    it's less important but still means using the native C implementation.

    Args:
        data: The data to check

    Returns:
        True if the object can be safely encoded with the native encoder.
    NTc                 s  s$    | ]\}}t |ot |V  qd S r'   rL   )r6   r?   rE   r   r   r   r:      s   " z_is_safe.<locals>.<genexpr>c                 s  s    | ]}t |V  qd S r'   rX   )r6   rE   r   r   r   r:      s    F)r   r   r(   r"   r   r,   isfiniter0   allr=   listtupler.   r   r   r   rL      s   


rL   enc#Callable[[Any, int], Iterable[str]]indent
str | None	sort_keysitem_separatorkey_separatortype[float]r(   	type[int]	type[str]
type[bool]r    type[bytes]Callable[[Any], bool]Callable[[Any], str])Callable[[Any], None | str | int | float]1Callable[[Any], Iterable[tuple[Any, Any]] | None]0Callable[[Any, int], Generator[str, None, None]]c                   s   t jt jt jt jdfddd	f
d
dd 	
fddS )NobjIterable[Any]depthr(   r   Generator[str, None, None]c                 3  s    | dr| sdV  d S |d7 }dV  r"d|  }|V  nd }d}| D ]}|r/d}nV  |r7|V   ||E d H  q(|d urN|d   V  dV  d S )	N__len__z[]   [
TF]r   )rn   rp   newline_indentfirstrE   )_iterencoder@   r_   rb   lenr   r   _iterencode_iterable   s*   
z._make_iterencode.<locals>._iterencode_iterableIterable[tuple[Any, Any]]c                 3  s    | dr| sdV  d S |d7 }dV  r"d|  }|V  nd }d}r3	fdd| D } | D ]&\}}|r>d	}nV  |rF|V  ||E d H  V   ||E d H  q5|d urj|d   V  d
V  d S )Nrr   z{}rs   {ru   Tc                 3  s     | ]\}} ||fV  qd S r'   r   r6   r   v)r#   r   r   r:     s    z=_make_iterencode.<locals>._iterencode_dict.<locals>.<genexpr>F}r   )rn   rp   rw   rx   r?   rE   )
ry   r#   r]   r@   r_   rb   rc   rz   ra   sortedr   r   _iterencode_dict   s2   
z*_make_iterencode.<locals>._iterencode_dictr
   c                 3  s    | d u ss| rn| fr| |E d H  d S | t B B 	B B r7| |E d H  d S  |  }d urI||E d H  d S | rS| jdksX| 
rf|  |E d H  d S | dru| |E d H  d S | |E d H  d S )Nr   rG   )r   ndimrI   )rn   rp   rM   )rB   rL   r   r{   r/   r"   r    r]   r   float64genericr@   r_   r(   r*   r   ndarrayr   r   r   ry     s   &
z%_make_iterencode.<locals>._iterencode)rn   ro   rp   r(   r   rq   )rn   r|   rp   r(   r   rq   )rn   r
   rp   r(   r   rq   )r)   r   r*   r   r   )r]   r_   ra   rb   rc   r   r(   r   r   r"   r    rz   r@   r   rL   r#   r/   rB   r   )rB   rL   ry   r   r{   r#   r/   r"   r    r]   r   r   r   r@   r_   r(   r*   r   rb   rc   rz   r   ra   r   r   r   _make_iterencode   s    0r   c                      s.   e Zd ZdZdddZdd fddZ  ZS )rU   zThis encoder will convert 1D np.ndarrays to lists.

    For other numpy types, uses obj.item() to extract a python scalar.
    or
   r   c                   s   t  r S t ttB tB tjB tjB rt S t tj	r/ j
dkr(  S tt S t tjr<  S t trLfdd  D S t dr] fdd  D S t trkfdd D S tj S )zConvert a 1D np.ndarray into something json-serializable.

        Returns:
            list, or a single-element array or matrix into its scalar value.
        rs   c                   s    i | ]\}}t | |qS r   r#   defaultr~   selfr   r   rF   @       z1NumpyAwareJSONEncoder.default.<locals>.<dictcomp>r;   c                   s    i | ]}t | | qS r   r   )r6   r   r   r   r   r   rF   C  r   c                   s   g | ]}  |qS r   )r   rH   r   r   r   rJ   F  s    z1NumpyAwareJSONEncoder.default.<locals>.<listcomp>)rL   r   r    r   r   r)   r+   r*   r/   r   r   tolistZasscalarr   r   rI   r   r=   r@   r;   r   rS   JSONEncoder)r   r   r   r   r   r   .  s"   



zNumpyAwareJSONEncoder.defaultF	_one_shotr"   Iterator[str]c                   s   t |rt ||S ttj| jri nd| j| j	rtjj
ntjj| jdu s,t| jtr/| jnd| j  }| j| j| j| j| j	|| j| j| j|dS )zEncode the given object and yield each string as available.

        For example::

            for chunk in JSONEncoder().iterencode(bigobject):
                mysocket.write(chunk)
        N r   )rL   super
iterencoder   rS   encoderc_make_encodercheck_circularr   ensure_asciic_encode_basestring_asciic_encode_basestringr_   r   r   rc   rb   ra   skipkeysrO   )r   r   r   r_   	__class__r   r   r   I  s4   
z NumpyAwareJSONEncoder.iterencode)r   r
   r   r
   F)r   r
   r   r"   r   r   )__name__
__module____qualname____doc__r   r   __classcell__r   r   r   r   rU   (  s    
rU   rV   dict[str, Any]c                 C  s(   |  dd |  dd |  dd dS )z7Update kwargs with defaults for "pretty printing" json.r_      ra   T
separators),:N)rQ   )rV   r   r   r   rR   o  s   rR   )rN   fpIO[str]Nonec                K  s4   | dd |rt| tj| |fdti| dS )zDump object to json, converting numpy objects to reasonable JSON.

    Also handles converting bytes to str, dict-like objects such as h5 tables
    into objects, and non-list/tuple iterables into lists.
    rO   FrP   N)rQ   rR   rS   dumprU   )r$   r   rN   rV   r   r   r   
dump_numpyv  s   r   )r   r   r   r   )r   r
   r   r   )r$   r%   r   r&   )r0   r1   r2   r3   r   r4   )r   rC   r   )r$   r
   rN   r"   r   r   )r$   r
   r   r"   )r]   r^   r_   r`   ra   r"   rb   r   rc   r   r   rd   r(   re   r   rf   r"   rg   r    rh   rL   ri   r#   rj   r/   rk   rB   rl   r   rm   )rV   r   )r$   r
   r   r   rN   r"   r   r   )4r   
__future__r   dataclassesrS   r,   collections.abcr   r   r   r   r   pathlibr   typingr	   r
   r   Znumpyr)   r   r   r(   r"   r   r   __annotations__r   r   r   r   r   r#   r/   r0   r2   r9   r@   rA   rB   rD   rW   rL   r   r    rz   r   r   r   rU   rR   r   r   r   r   r   <module>   sZ   



!
%c
G