U
    SZf8                     @   s   d dl Z d dl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 ZG dd dejZG d	d
 d
eZdd Zdd Zd#ddZdd Zdd Zdd Zd$ddZd%ddZdd  Zd!d" ZdS )&    Nreduce)
get_module)ImageUriValidatorc                 C   s   dd }t || g }|S )z0
    Custom cumsum to avoid a numpy import.
    c                 S   s$   t | dkr|gS | | d | g S Nr   )len)ax r   7/tmp/pip-unpacked-wheel-5ksk5baj/_plotly_utils/utils.py_reducer   s    zcumsum.<locals>._reducerr   )r
   r   retr   r   r   cumsum   s    r   c                       s   e Zd ZdZdd Z fddZdd Zedd	 Zed
d Z	edd Z
edd Zedd Zedd Zedd Zedd Zedd Z  ZS )PlotlyJSONEncodera9  
    Meant to be passed as the `cls` kwarg to json.dumps(obj, cls=..)

    See PlotlyJSONEncoder.default for more implementation information.

    Additionally, this encoder overrides nan functionality so that 'Inf',
    'NaN' and '-Inf' encode to 'null'. Which is stricter JSON than the Python
    version.

    c                 C   s   |dkrdS |S dS )zU
        This is used to ultimately *encode* into strict JSON, see `encode`

        )Infinityz	-InfinityNaNNr   )selfconstr   r   r   coerce_to_strict%   s    z"PlotlyJSONEncoder.coerce_to_strictc                    sx   t t| |}d|ks$d|ks$|S ztj|| jd}W n tk
rT   tdY n X tj|| j| j	| j
| jfdS dS )z
        Load and then dump the result using parse_constant kwarg

        Note that setting invalid separators will cause a failure at this step.

        r   r   )parse_constantzSEncoding into strict JSON failed. Did you set the separators valid JSON separators?)	sort_keysindent
separatorsN)superr   encode_jsonloadsr   
ValueErrordumpsr   r   item_separatorkey_separator)r   oZ	encoded_oZnew_o	__class__r   r   r   0   s    

zPlotlyJSONEncoder.encodec              	   C   sd   | j | j| j| j| j| j| j| j| jf	}|D ](}z||W   S  t	k
rR   Y q,X q,t
j| |S )a  
        Accept an object (of unknown type) and try to encode with priority:
        1. builtin:     user-defined objects
        2. sage:        sage math cloud
        3. pandas:      dataframes/series
        4. numpy:       ndarrays
        5. datetime:    time/datetime objects

        Each method throws a NotEncoded exception if it fails.

        The default method will only get hit if the object is not a type that
        is naturally encoded by json:

            Normal objects:
                dict                object
                list, tuple         array
                str, unicode        string
                int, long, float    number
                True                true
                False               false
                None                null

            Extended objects:
                float('nan')        'NaN'
                float('infinity')   'Infinity'
                float('-infinity')  '-Infinity'

        Therefore, we only anticipate either unknown iterables or values here.

        )encode_as_plotlyencode_as_sageencode_as_numpyencode_as_pandasencode_as_datetimeencode_as_dateencode_as_listencode_as_decimalencode_as_pilNotEncodabler   JSONEncoderdefault)r   objZencoding_methodsZencoding_methodr   r   r   r0   U   s     !zPlotlyJSONEncoder.defaultc                 C   s(   z
|   W S  tk
r"   tY nX dS )z1Attempt to use a builtin `to_plotly_json` method.N)Zto_plotly_jsonAttributeErrorr.   r1   r   r   r   r%      s    
z"PlotlyJSONEncoder.encode_as_plotlyc                 C   s   t | dr|  S tdS )z@Attempt to use `tolist` method to convert to normal Python list.tolistN)hasattrr4   r.   r3   r   r   r   r+      s    
z PlotlyJSONEncoder.encode_as_listc                 C   s<   t d}|st| |jkr"t| S | |jkr4t| S tdS )z@Attempt to convert sage.all.RR to floats and sage.all.ZZ to intszsage.allN)r   r.   ZRRfloatZZZint)r1   Zsage_allr   r   r   r&      s    

z PlotlyJSONEncoder.encode_as_sagec                 C   sB   t ddd}|st| |jkr"dS t|dr:| |jkr:dS tdS )z)Attempt to convert pandas.NaT / pandas.NApandasFZshould_loadNNA)r   r.   ZNaTr5   r:   )r1   r8   r   r   r   r(      s    
z"PlotlyJSONEncoder.encode_as_pandasc                 C   sp   t ddd}|st| |jjjkr*tdS t| |jrh| jj	dkrhz|
|  W S  tk
rf   Y nX tdS )z'Attempt to convert numpy.ma.core.maskednumpyFr9   nanMN)r   r.   macoreZmaskedr6   
isinstanceZndarrayZdtypekindZdatetime_as_stringr4   	TypeError)r1   r;   r   r   r   r'      s    z!PlotlyJSONEncoder.encode_as_numpyc                 C   s(   z
|   W S  tk
r"   tY nX dS )z.Convert datetime objects to iso-format stringsN)	isoformatr2   r.   r3   r   r   r   r)      s    
z$PlotlyJSONEncoder.encode_as_datetimec                 C   s2   z|   }W n tk
r$   tY n
X t|S dS )z=Attempt to convert to utc-iso time string using date methods.N)rC   r2   r.   iso_to_plotly_time_string)r1   Ztime_stringr   r   r   r*      s
    
z PlotlyJSONEncoder.encode_as_datec                 C   s   t | tjrt| S tdS )z3Attempt to encode decimal by converting it to floatN)r@   decimalDecimalr6   r.   r3   r   r   r   r,      s    z#PlotlyJSONEncoder.encode_as_decimalc                 C   s.   t d}|dk	r&t| |jr&t| S tdS )z5Attempt to convert PIL.Image.Image to base64 data uriz	PIL.ImageN)r   r@   ZImager   Zpil_image_to_urir.   )r1   imager   r   r   r-      s    
zPlotlyJSONEncoder.encode_as_pil)__name__
__module____qualname____doc__r   r   r0   staticmethodr%   r+   r&   r(   r'   r)   r*   r,   r-   __classcell__r   r   r#   r   r      s,   %2






	
r   c                   @   s   e Zd ZdS )r.   N)rH   rI   rJ   r   r   r   r   r.      s   r.   c                 C   sj   |  ddd dks(|  dd dkr0td| dd	d
d	} | drZ| dd	S | ddS dS )z=Remove timezone info and replace 'T' delimeter with ' ' (ws).-N   z00:00+r   z]Plotly won't accept timestrings with timezone info.
All timestrings are assumed to be in UTC.z-00:00 z+00:00z	T00:00:00T )split	Exceptionreplaceendswith)Z
iso_stringr   r   r   rD      s    (
rD   c                     s    fdd}|S )Nc                    s0   t jd d dks,| jd k	r,| jjf  | _| S )N   )rO   rX   )sysversion_inforK   format)funcnamesr   r   
_decorator   s    
z template_doc.<locals>._decoratorr   )r^   r_   r   r]   r   template_doc   s    r`   Fc                 C   s   dd }t | ||dS )Nc              	   S   sP   t d| }tt|D ].}zt|| ||< W q tk
rD   Y qX qt|S )Nz(\d+))rerT   ranger   r7   r   tuple)vZv_partsir   r   r   key
  s    z"_natural_sort_strings.<locals>.key)rf   reversesorted)valsrg   rf   r   r   r   _natural_sort_strings	  s    
rk   c                  C   s&   t ddd} | rt| jf}ntf}|S )Nr;   Fr9   )r   r7   integer)npZint_typer   r   r   _get_int_type  s
    rn   c                    s>   t |dkr| S |  tdd t fdd| } t| |S )ar  
    Split all the strings in ss at any of the characters in chars.
    Example:

        >>> ss = ["a.string[0].with_separators"]
        >>> chars = list(".[]_")
        >>> split_multichar(ss, chars)
        ['a', 'string', '0', '', 'with', 'separators']

    :param (list) ss: A list of strings.
    :param (list) chars: Is a list of chars (note: not a string).
    r   c                 S   s   | | S Nr   )r
   yr   r   r   <lambda>0      z!split_multichar.<locals>.<lambda>c                    s
   |   S ro   )rT   )r
   cr   r   rq   0  rr   )r   popr   mapsplit_multichar)sscharsr   rs   r   rw      s
    rw   c                 C   s<   t tdd ttt| tdgt tt| dd  S )a  
    Given a list of strings split using split_multichar, return a list of
    integers representing the indices of the first character of every string in
    the original string.
    Example:

        >>> ss = ["a.string[0].with_separators"]
        >>> chars = list(".[]_")
        >>> ss_split = split_multichar(ss, chars)
        >>> ss_split
        ['a', 'string', '0', '', 'with', 'separators']
        >>> split_string_positions(ss_split)
        [0, 2, 9, 11, 12, 17]

    :param (list) ss: A list of strings.
    c                 S   s   | d | d  S )Nr      r   )tr   r   r   rq   G  rr   z(split_string_positions.<locals>.<lambda>r   Nr   )listrv   ziprb   r   r   )rx   r   r   r   split_string_positions4  s    ,r~   rz   ^Tc                 C   s   dd t t| d | | D }d}|dkr\| D ]&}t |D ]}	|| |	 }|||< q>q2n&t |D ]}	| | | |	 }|||< qdd|}
|r|
d|d  }
|
S )a  
    Return a string that is whitespace except at p[i] which is replaced with char.
    If i is None then all the indices of the string in p are replaced with char.

    Example:

        >>> ss = ["a.string[0].with_separators"]
        >>> chars = list(".[]_")
        >>> ss_split = split_multichar(ss, chars)
        >>> ss_split
        ['a', 'string', '0', '', 'with', 'separators']
        >>> ss_pos = split_string_positions(ss_split)
        >>> ss[0]
        'a.string[0].with_separators'
        >>> display_string_positions(ss_pos,4)
        '            ^'
        >>> display_string_positions(ss_pos,4,offset=1,length=3,char="~",trim=False)
        '             ~~~      '
        >>> display_string_positions(ss_pos)
        '^ ^      ^ ^^    ^'
    :param (list) p: A list of integers.
    :param (integer|None) i: Optional index of p to display.
    :param (integer) offset: Allows adding a number of spaces to the replacement.
    :param (integer) length: Allows adding a replacement that is the char
                             repeated length times.
    :param (str) char: allows customizing the replacement character.
    :param (boolean) trim: trims the remaining whitespace if True.
    c                 S   s   g | ]}d qS )rS   r   ).0_r   r   r   
<listcomp>j  s     z,display_string_positions.<locals>.<listcomp>rz   r   NrQ   )rb   maxjoin)pre   offsetlengthcharZtrimsZmaxaddrZp_lr   r   r   r   display_string_positionsM  s    "

r   c                 C   sx   dd }|r|t || |S t| s*| S ttt| dkrN|t| d  gS G dd d}tttt||| dgS )a  
    Given a list of strings, some of which are the empty string "", replace the
    empty strings with c and combine them with the closest non-empty string on
    the left or "" if it is the first string.
    Examples:
    for c="_"
    ['hey', '', 'why', '', '', 'whoa', '', ''] -> ['hey_', 'why__', 'whoa__']
    ['', 'hi', '', "I'm", 'bob', '', ''] -> ['_', 'hi_', "I'm", 'bob__']
    ['hi', "i'm", 'a', 'good', 'string'] -> ['hi', "i'm", 'a', 'good', 'string']
    Some special cases are:
    [] -> []
    [''] -> ['']
    ['', ''] -> ['_']
    ['', '', '', ''] -> ['___']
    If reverse is true, empty strings are combined with closest non-empty string
    on the right or "" if it is the last string.
    c                 S   s   dd | D d d d S )Nc                 S   s   g | ]}|d d d qS )Nr   r   )r   r   r   r   r   r     s     z5chomp_empty_strings.<locals>._rev.<locals>.<listcomp>r   r   )r   r   r   r   _rev  s    z!chomp_empty_strings.<locals>._revr   rz   c                   @   s   e Zd Zdd Zdd ZdS )z%chomp_empty_strings.<locals>._Chomperc                 S   s
   || _ d S ro   rs   )r   rt   r   r   r   __init__  s    z.chomp_empty_strings.<locals>._Chomper.__init__c                 S   s6   t |dkr(|d d |d | j g S ||g S d S r   )r   rt   )r   r
   rp   r   r   r   __call__  s    z.chomp_empty_strings.<locals>._Chomper.__call__N)rH   rI   rJ   r   r   r   r   r   r   _Chomper  s   r   rQ   )chomp_empty_stringsr   sumrv   r|   filterr   )stringsrt   rg   r   r   r   r   r   r   {  s    r   c                 C   s   t | t |k rt|| S t |dkr.t | S tt |d }t| D ]f\}}|d g}t|D ]F\}}||d  d }|| d }	|| ||k }
|t||	|
 q`|}qF|d S )Nr   rz   r   )r   levenshteinrb   	enumerateappendmin)s1s2Zprevious_rowre   Zc1Zcurrent_rowjc2Z
insertionsZ	deletionsZsubstitutionsr   r   r   r     s    

r   c                    s    fdd}t ||dd S )Nc                    s   t |  | fS ro   )r   )r   stringr   r   _key  s    z!find_closest_string.<locals>._key)rf   r   rh   )r   r   r   r   r   r   find_closest_string  s    r   )F)Nr   rz   r   T)F)rE   jsonr   rY   ra   	functoolsr   Z_plotly_utils.optional_importsr   Z_plotly_utils.basevalidatorsr   r   r/   r   rU   r.   rD   r`   rk   rn   rw   r~   r   r   r   r   r   r   r   r   <module>   s(    R

	
.
0