o
    ][C                     @   s8  d Z ddlZddlZddlZddlZddlZddlZddlZddl	ZdZ
dZdZedZej r;dd Zd	d
 Zndd Zdd
 Zdd Zdd Zdd Zdd Zd2ddZdd ZejjddZddejdfdd Zd3d"d#Zd4d$d%Z d5d&d'Z!d(d) Z"d*d+ Z#d,d- Z$d.d/ Z%d5d0d1Z&eZ'e Z(e!Z)e"Z*dS )6a  
Toolkit for various string activity.

.. versionchanged:: 1.3.0
   Dropped the get_* prefix from several function names. The old names still
   work, but are deprecated aliases.

**Module Overview:**

::

  crop - shortens string to a given length

  size_label - human readable label for a number of bytes
  time_label - human readable label for a number of seconds
  time_labels - human readable labels for each time unit
  short_time_label - condensed time label output
  parse_short_time_label - seconds represented by a short time label
    N))g      Bz Pbz Petabit)g      @Bz Tbz Terabit)g      Az Gbz Gigabit)g       Az Mbz Megabit)g      `@z Kbz Kilobit)g      ?z bz Bit))g      Cz PBz	 Petabyte)g      pBz TBz	 Terabyte)g      Az GBz	 Gigabyte)g      0Az MBz	 Megabyte)g      @z KBz	 Kilobyte)      ?z Bz Byte))g     @dz day)g      @hz hour)g      N@mz minute)r   sz secondz/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})c                 C   s   t | trt| dd S | S Nreplacer   )
isinstancestrcodecslatin_1_encodemsg r   5/usr/lib/python3/dist-packages/stem/util/str_tools.py_to_bytes_implA   s   
r   c                 C   "   | d urt | ts| ddS | S Nzutf-8r   )r	   r
   decoder   r   r   r   _to_unicode_implG      r   c                 C   s&   | d urt | trt| dd S | S r   )r	   unicoder   r   r   r   r   r   r   M   s   c                 C   r   r   )r	   r   r   r   r   r   r   r   S   r   c                 C      t | S )aW  
  Provides the ASCII bytes for the given string. This is purely to provide
  python 3 compatability, normalizing the unicode/ASCII change in the version
  bump. For an explanation of this see...

  http://python3porting.com/problems.html#nicer-solutions

  :param str,unicode msg: string to be converted

  :returns: ASCII bytes for string
  )r   r   r   r   r   	_to_bytesZ   s   r   c                 C   r   )z
  Provides the unicode string for the given ASCII bytes. This is purely to
  provide python 3 compatability, normalizing the unicode/ASCII change in the
  version bump.

  :param str,unicode msg: string to be converted

  :returns: unicode conversion
  )r   r   r   r   r   _to_unicodej   s   r   c                 C   s0   t | d }t| trdnd}t| ||  S )z.
  Base64 decode, without padding concerns.
        ==)lenr	   bytesbase64Z	b64decode)r   Zmissing_paddingZpadding_chrr   r   r   _decode_b64x   s   r!   c                    sH   t j rt trt fddt D S t fddt D S )z
  Serializes a string to a number.

  :param str msg: string to be serialized

  :returns: **int** representation of the string
  c                    s*   g | ]\}}t d t | d | qS       )powr   .0icr   r   r   
<listcomp>   s   * z_to_int.<locals>.<listcomp>c                    s.   g | ]\}}t d t | d t| qS r"   )r%   r   ordr&   r   r   r   r*      s   . )stemprereqis_python_3r	   r   sum	enumerater   r   r   r   _to_int   s   	r1   _ c                 C   st   g }|  |D ]-}t|dkr|d qt|dkr#||  q||d  |dd    q||S )a*  
  Converts the given string to camel case, ie:

  ::

    >>> _to_camel_case('I_LIKE_PEPPERJACK!')
    'I Like Pepperjack!'

  :param str label: input string to be converted
  :param str divider: word boundary
  :param str joiner: replacement for word boundaries

  :returns: camel cased string
  r    r$   N)splitr   appendupperlowerjoin)labelZdividerZjoinerZwordsentryr   r   r   _to_camel_case   s   $
r<   c                    s     fddt dt D S )a  
  Splits a string into a list of strings up to the given size.

  ::

    >>> _split_by_length('hello', 2)
    ['he', 'll', 'o']

  :param str msg: string to split
  :param int size: number of characters to chunk into

  :returns: **list** with chunked string components
  c                    s   g | ]
} ||  qS r   r   )r'   r(   r   sizer   r   r*      s    z$_split_by_length.<locals>.<listcomp>r   )ranger   r=   r   r=   r   _split_by_length   s    r@   ELLIPSEHYPHENr   Fc                 C   s  t | |kr|r| dfS | S |dk rtd| |r$|dk r$td| |dk r.td| |tjkrD|dk r?|r=d| fS dS |d8 }n|rO|tjkrO|d7 }|du rVtj}| d	d|d }|d
krr||k ro|rmd| fS dS d}nt | d|  }|| d |k}|r|r| 	d	|}|d
krt | }|| d |k}|r| d| | |d }	}
|tjkr|	d
 |
 }
|	dd
  d }	n| d| | |d }	}
|s|	r|	d
 dv r|	dd
 }	|tjkr|	 d }	|r|	|
fS |	S )a  
  Shortens a string to a given length.

  If we crop content then a given ending is included (counting itself toward
  the size limitation). This crops on word breaks so we only include a word if
  we can display at least **min_word_length** characters of it.

  If there isn't room for even a truncated single word (or one word plus the
  ellipse if including those) then this provides an empty string.

  If a cropped string ends with a comma or period then it's stripped (unless
  we're providing the remainder back). For example...

    >>> crop('This is a looooong message', 17)
    'This is a looo...'

    >>> crop('This is a looooong message', 12)
    'This is a...'

    >>> crop('This is a looooong message', 3)
    ''

  The whole point of this method is to provide human friendly croppings, and as
  such details of how this works might change in the future. Callers should not
  rely on the details of how this crops.

  .. versionadded:: 1.3.0

  :param str msg: text to be processed
  :param int size: space available for text
  :param int min_word_length: minimum characters before which a word is
    dropped, requires whole word if **None**
  :param int min_crop: minimum characters that must be dropped if a word is
    cropped
  :param Ending ending: type of ending used when truncating, no special
    truncation is used if **None**
  :param bool get_remainder: returns a tuple with the second part being the
    cropped portion of the message

  :returns: **str** of the text truncated to the given length
  r4   r   z)Crop size can't be negative (received %i)z6Crop's min_word_length can't be negative (received %i)z/Crop's min_crop can't be negative (received %i)   r$   Nr3   T-),.z...)
r   
ValueErrorEndingrA   rB   sysmaxsizerfindrstripfind)r   r>   Zmin_word_lengthZmin_cropZendingZget_remainderZlast_wordbreakZinclude_cropZnext_wordbreakZ
return_msgZ	remainderr   r   r   crop   sP   -



rO   Tc                 C   s$   |r
t t| |||S t t| |||S )a  
  Converts a number of bytes into a human readable label in its most
  significant units. For instance, 7500 bytes would return "7 KB". If the
  is_long option is used this expands unit labels to be the properly pluralized
  full word (for instance 'Kilobytes' rather than 'KB'). Units go up through
  petabytes.

  ::

    >>> size_label(2000000)
    '1 MB'

    >>> size_label(1050, 2)
    '1.02 KB'

    >>> size_label(1050, 3, True)
    '1.025 Kilobytes'

  .. versionchanged:: 1.6.0
     Added round argument.

  :param int byte_count: number of bytes to be converted
  :param int decimal: number of decimal digits to be included
  :param bool is_long: expands units label
  :param bool is_bytes: provides units in bytes if **True**, bits otherwise
  :param bool round: rounds normally if **True**, otherwise rounds down

  :returns: **str** with human readable representation of the size
  )
_get_labelSIZE_UNITS_BYTESSIZE_UNITS_BITS)Z
byte_countdecimalis_longZis_bytesroundr   r   r   
size_label9  s   rV   c                 C   s   t t| ||S )a  
  Converts seconds into a time label truncated to its most significant units.
  For instance, 7500 seconds would return "2h". Units go up through days.

  This defaults to presenting single character labels, but if the is_long
  option is used this expands labels to be the full word (space included and
  properly pluralized). For instance, "4h" would be "4 hours" and "1m" would
  become "1 minute".

  ::

    >>> time_label(10000)
    '2h'

    >>> time_label(61, 1, True)
    '1.0 minute'

    >>> time_label(61, 2, True)
    '1.01 minutes'

  :param int seconds: number of seconds to be converted
  :param int decimal: number of decimal digits to be included
  :param bool is_long: expands units label

  :returns: **str** with human readable representation of the time
  )rP   
TIME_UNITS)secondsrS   rT   r   r   r   
time_label^  s   rY   c                 C   s@   g }t D ]\}}}t| |kr|tt | d| | |; } q|S )a  
  Provides a list of label conversions for each time unit, starting with its
  most significant units on down. Any counts that evaluate to zero are omitted.
  For example...

  ::

    >>> time_labels(400)
    ['6m', '40s']

    >>> time_labels(3640, True)
    ['1 hour', '40 seconds']

  :param int seconds: number of seconds to be converted
  :param bool is_long: expands units label

  :returns: **list** of strings with human readable representations of the time
  r   )rW   absr6   rP   )rX   rT   time_labelscount_per_unitr2   r   r   r   r[   }  s   r[   c                 C   s   | dk r
t d|  i }tD ]\}}}t| | }| |; } ||| < qd|d |d f }|d r?d|d |d |f }|S |d rKd	|d |f }|S )
aQ  
  Provides a time in the following format:
  [[dd-]hh:]mm:ss

  ::

    >>> short_time_label(111)
    '01:51'

    >>> short_time_label(544100)
    '6-07:08:20'

  :param int seconds: number of seconds to be converted

  :returns: **str** with the short representation for the time

  :raises: **ValueError** if the input is negative
  r   z2Input needs to be a non-negative integer, got '%i'z	%02i:%02iZminutesecondZdayz
%i-%02i:%sZhourz%02i:%s)rH   rW   intstrip)rX   	time_compamountr2   r:   countr   r   r   short_time_label  s   rc   c                 C   s   d\}}}}d| v r|  dd\}} |  d}t|dkr#|\}}}nt|dkr.|\}}ntd|  z!tt|}|t|d 7 }|t|d	 7 }|t|d
 7 }|W S  tyb   td|  w )a  
  Provides the number of seconds corresponding to the formatting used for the
  cputime and etime fields of ps:
  [[dd-]hh:]mm:ss or mm:ss.ss

  ::

    >>> parse_short_time_label('01:51')
    111

    >>> parse_short_time_label('6-07:08:20')
    544100

  :param str label: time entry to be parsed

  :returns: **int** with the number of seconds represented by the label

  :raises: **ValueError** if input is malformed
  )0rd   rd   rd   rE   r$   :rC      zDInvalid time format, we expected '[[dd-]hh:]mm:ss' or 'mm:ss.ss': %s<   i  iQ z#Non-numeric value in time entry: %s)r5   r   rH   r^   float)r:   ZdaysZhoursZminutesrX   r`   Ztime_sumr   r   r   parse_short_time_label  s$   

ri   c              	   C   s   t j| stdt|  zdd t|  D }W n ty)   td|  w t		|d |d |d |d |d	 |d
 S )a  
  Parses the date and time that in format like like...

  ::

    2012-11-08 16:48:41

  :param str entry: timestamp to be parsed

  :returns: **datetime** for the time represented by the timestamp

  :raises: **ValueError** if the timestamp is malformed
  z/parse_timestamp() input must be a str, got a %sc                 S   s   g | ]}t |qS r   )r^   )r'   xr   r   r   r*     s    z$_parse_timestamp.<locals>.<listcomp>z9Expected timestamp in format YYYY-MM-DD HH:MM:ss but got r   r$   rf   rC   r      )
r,   util_is_strrH   type_timestamp_rematchgroupsAttributeErrordatetime)r;   timer   r   r   _parse_timestamp  s   ,ru   c                 C   s   t j| stdt|  d| v r| d\}}n| d}}t|dks)| s-tdt|dkrH|d dkrH|dd d	 |d
d  }ntdt|}|t	j
t|d S )a  
  Parses the ISO 8601 standard that provides for timestamps like...

  ::

    2012-11-08T16:48:41.420251

  :param str entry: timestamp to be parsed

  :returns: **datetime** for the time represented by the timestamp

  :raises: **ValueError** if the timestamp is malformed
  z3parse_iso_timestamp() input must be a str, got a %srG   Z000000   z-timestamp's microseconds should be six digits
   TNr3      z<timestamp didn't contain delimeter 'T' between date and time)microseconds)r,   rl   rm   rH   rn   r5   r   isdigitru   rs   Z	timedeltar^   )r;   Ztimestamp_strrz   Z	timestampr   r   r   _parse_iso_timestamp
  s   
r|   c                 C   s   d| }|dk rd| }t |}n|dkr-|r| d d d n| d d }d|| |f S | D ]A\}}}	||krp|sD|||d	|   8 }|||  }
|rj|dkrU||k}n||d k}|
|	 |red   S d
   S |
|   S q/dS )a  
  Provides label corresponding to units of the highest significance in the
  provided set. This rounds down (ie, integer truncation after visible units).

  :param tuple units: type of units to be used for conversion, containing
    (count_per_unit, short_label, long_label)
  :param int count: number of base units being converted
  :param int decimal: decimal precision of label
  :param bool is_long: uses the long label if **True**, short label otherwise
  :param bool round: rounds normally if **True**, otherwise rounds down
  z%%.%ifr   rE   rD   rf   r   r$   z%s%srw   r4   N)rZ   )Zunitsrb   rS   rT   rU   Zlabel_formatZunits_labelr\   Zshort_labelZ
long_labelZcount_labelZ	is_pluralr   r   r   rP   0  s(   
 
rP   )r2   r3   )r   FTF)r   F)F)+__doc__r    r   rs   rerJ   Zstem.prereqr,   Z	stem.utilZstem.util.enumrR   rQ   rW   compilero   r-   r.   r   r   r   r   r!   r1   r<   r@   rl   enumEnumrI   rA   rO   rV   rY   r[   rc   ri   ru   r|   rP   Zget_size_labelZget_time_labelZget_time_labelsZget_short_time_labelr   r   r   r   <module>   sL   		




r
%
(-
&3