B
    DVW>                 @   s   d Z ddlmZmZmZmZ ddl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ZdZdd	 ZG d
d deZdd Zdd Zdd ZdS )a  
Cycler
======

Cycling through combinations of values, producing dictionaries.

You can add cyclers::

    from cycler import cycler
    cc = (cycler(color=list('rgb')) +
          cycler(linestyle=['-', '--', '-.']))
    for d in cc:
        print(d)

Results in::

    {'color': 'r', 'linestyle': '-'}
    {'color': 'g', 'linestyle': '--'}
    {'color': 'b', 'linestyle': '-.'}


You can multiply cyclers::

    from cycler import cycler
    cc = (cycler(color=list('rgb')) *
          cycler(linestyle=['-', '--', '-.']))
    for d in cc:
        print(d)

Results in::

    {'color': 'r', 'linestyle': '-'}
    {'color': 'r', 'linestyle': '--'}
    {'color': 'r', 'linestyle': '-.'}
    {'color': 'g', 'linestyle': '-'}
    {'color': 'g', 'linestyle': '--'}
    {'color': 'g', 'linestyle': '-.'}
    {'color': 'b', 'linestyle': '-'}
    {'color': 'b', 'linestyle': '--'}
    {'color': 'b', 'linestyle': '-.'}
    )absolute_importdivisionprint_functionunicode_literalsN)productcycle)zipreduce)muladdz0.10.0c             C   s`   | dk	rt t| ni }|dk	r,t t|ni }t| }t| }||@ rXtd||B S )a  
    Helper function to compose cycler keys

    Parameters
    ----------
    left, right : iterable of dictionaries or None
        The cyclers to be composed
    Returns
    -------
    keys : set
        The keys in the composition of the two cyclers
    Nz"Can not compose overlapping cycles)nextitersetkeys
ValueError)leftrightZl_peekZr_peekZl_keyZr_key r   %lib/python3.7/site-packages/cycler.py_process_keys7   s    r   c               @   s   e Zd ZdZdd Zd+ddZedd Zd	d
 Zdd Z	e
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& ZeZd'd( Zd)d* ZdS ),Cyclera  
    Composable cycles

    This class has compositions methods:

    ``+``
      for 'inner' products (zip)

    ``+=``
      in-place ``+``

    ``*``
      for outer products (itertools.product) and integer multiplication

    ``*=``
      in-place ``*``

    and supports basic slicing via ``[]``

    Parameters
    ----------
    left : Cycler or None
        The 'left' cycler

    right : Cycler or None
        The 'right' cycler

    op : func or None
        Function which composes the 'left' and 'right' cyclers.

    c             C   s   t | S )N)r   )selfr   r   r   __call__m   s    zCycler.__call__Nc             C   s   t |tr t|j|j|j| _n |dk	r:dd |D | _nd| _t |tr`t|j|j|j| _n |dk	rzdd |D | _nd| _t| j| j| _|| _dS )z\Semi-private init

        Do not use this directly, use `cycler` function instead.
        Nc             S   s   g | ]}t  |qS r   )copy).0vr   r   r   
<listcomp>z   s    z#Cycler.__init__.<locals>.<listcomp>c             S   s   g | ]}t  |qS r   )r   )r   r   r   r   r   r      s    )
isinstancer   _left_right_opr   _keys)r   r   r   opr   r   r   __init__p   s    

zCycler.__init__c             C   s
   t | jS )z2
        The keys this Cycler knows about
        )r   r!   )r   r   r   r   r      s    zCycler.keysc                s    krdS  | j kr(td  f | j krDtd f | j  | j   | jdk	r| jjkr| j  n4t| j	t
r| j	  n fdd| j	D | _	dS )a  
        Change a key in this cycler to a new name.
        Modification is performed in-place.

        Does nothing if the old key is the same as the new key.
        Raises a ValueError if the new key is already a key.
        Raises a KeyError if the old key isn't a key.

        Nz-Can't replace %s with %s, %s is already a keyz)Can't replace %s with %s, %s is not a keyc                s   g | ]} | iqS r   r   )r   entry)newoldr   r   r      s    z%Cycler.change_key.<locals>.<listcomp>)r!   r   KeyErrorremover   r   r   
change_keyr   r   r   )r   r&   r%   r   )r%   r&   r   r)      s    


zCycler.change_keyc             c   sB   x<|  | j| jD ](\}}t }|| || |V  qW dS )z
        Compose the 'left' and 'right' components of this cycle
        with the proper operation (zip or product as of now)
        N)r    r   r   dictupdate)r   aboutr   r   r   _compose   s
    

zCycler._composec                s0   | d}t  fdd|D |_t g|_|S )a  
        Class method to create 'base' Cycler objects
        that do not have a 'right' or 'op' and for which
        the 'left' object is not another Cycler.

        Parameters
        ----------
        label : str
            The property key.

        itr : iterable
            Finite length iterable of the property values.

        Returns
        -------
        cycler : Cycler
            New 'base' `Cycler`
        Nc             3   s   | ]} |iV  qd S )Nr   )r   r   )labelr   r   	<genexpr>   s    z$Cycler._from_iter.<locals>.<genexpr>)listr   r   r!   )clsr0   itrZretr   )r0   r   
_from_iter   s    zCycler._from_iterc                s<   t  tr0|  }tt fddt|D S tdd S )Nc             3   s    | ]\}}t ||  V  qd S )N)_cycler)r   kr   )keyr   r   r1      s   z%Cycler.__getitem__.<locals>.<genexpr>z+Can only use slices with Cycler.__getitem__)r   sliceby_keyr	   r   six	iteritemsr   )r   r8   transr   )r8   r   __getitem__   s
    
zCycler.__getitem__c             C   s&   | j d krtdd | jD S |  S )Nc             s   s   | ]}t |V  qd S )N)r*   )r   lr   r   r   r1      s    z"Cycler.__iter__.<locals>.<genexpr>)r   r   r   r/   )r   r   r   r   __iter__   s    
zCycler.__iter__c             C   s4   t | t |kr(tdt | t |t| |tS )z
        Pair-wise combine two equal length cycles (zip)

        Parameters
        ----------
        other : Cycler
           The second Cycler
        z1Can only add equal length cycles, not {0} and {1})lenr   formatr   r   )r   otherr   r   r   __add__   s    	zCycler.__add__c                sN   t  trt|  tS t  trF|  }tt fddt|D S t	S dS )z
        Outer product of two cycles (`itertools.product`) or integer
        multiplication.

        Parameters
        ----------
        other : Cycler or int
           The second Cycler or integer
        c             3   s    | ]\}}t ||  V  qd S )N)r6   )r   r7   r   )rC   r   r   r1     s   z!Cycler.__mul__.<locals>.<genexpr>N)
r   r   r   intr:   r	   r   r;   r<   NotImplemented)r   rC   r=   r   )rC   r   __mul__   s    


zCycler.__mul__c             C   s   | | S )Nr   )r   rC   r   r   r   __rmul__  s    zCycler.__rmul__c             C   sD   t ttti}| jd kr t| jS t| j}t| j}|| j ||S )N)r   minr   r
   r   rA   r   r    )r   Zop_dictZl_lenZr_lenr   r   r   __len__  s    



zCycler.__len__c             C   sL   t |tstdt| }t||| _|| _t| _t|j|j	|j| _	| S )z
        In-place pair-wise combine two equal length cycles (zip)

        Parameters
        ----------
        other : Cycler
           The second Cycler
        z"Cannot += with a non-Cycler object)
r   r   	TypeErrorr   r   r!   r   r   r    r   )r   rC   old_selfr   r   r   __iadd__  s    	

zCycler.__iadd__c             C   sL   t |tstdt| }t||| _|| _t| _t|j|j	|j| _	| S )z
        In-place outer product of two cycles (`itertools.product`)

        Parameters
        ----------
        other : Cycler
           The second Cycler
        z"Cannot *= with a non-Cycler object)
r   r   rK   r   r   r!   r   r   r    r   )r   rC   rL   r   r   r   __imul__&  s    	

zCycler.__imul__c             C   s<   t | t |krdS | j|jA r$dS tdd t| |D S )z 
        Check equality
        Fc             s   s   | ]\}}||kV  qd S )Nr   )r   r,   r-   r   r   r   r1   B  s    z Cycler.__eq__.<locals>.<genexpr>)rA   r   allr   )r   rC   r   r   r   __eq__9  s
    zCycler.__eq__c                sn   t dtdi}| jd krD| j  t fdd| D }dj |dS || jd}d}|j| j	|| jd	S d S )
N+*c             3   s   | ]}|  V  qd S )Nr   )r   r   )labr   r   r1   H  s    z"Cycler.__repr__.<locals>.<genexpr>zcycler({lab!r}, {itr!r}))rS   r4   ?z({left!r} {op} {right!r}))r   r"   r   )
r   r   r   r   popr2   rB   getr    r   )r   Zop_mapr4   r"   msgr   )rS   r   __repr__D  s    

zCycler.__repr__c             C   s   d}t | jtd}x|D ]}|dj|d7 }qW xBt| D ]6}|d7 }x |D ]}|dj|| d7 }qLW |d7 }q:W |d7 }|S )	Nz<table>)r8   z<th>{key!r}</th>z<tr>z<td>{val!r}</td>)valz</tr>z</table>)sortedr   reprrB   r   )r   outputZsorted_keysr8   dr7   r   r   r   _repr_html_O  s    

zCycler._repr_html_c             C   sJ   | j }tdd |D }x,| D ]$}x|D ]}|| ||  q(W qW |S )a  Values by key

        This returns the transposed values of the cycler.  Iterating
        over a `Cycler` yields dicts with a single value for each key,
        this method returns a `dict` of `list` which are the values
        for the given key.

        The returned value can be used to create an equivalent `Cycler`
        using only `+`.

        Returns
        -------
        transpose : dict
            dict of lists of the values for each key.
        c             s   s   | ]}|t  fV  qd S )N)r2   )r   r7   r   r   r   r1   s  s    z Cycler.by_key.<locals>.<genexpr>)r   r*   append)r   r   r.   r]   r7   r   r   r   r:   ]  s    

zCycler.by_keyc             C   s"   |   }ttdd t|D S )zSimplify the Cycler

        Returned as a composition using only sums (no multiplications)

        Returns
        -------
        simple : Cycler
            An equivalent cycler using only summationc             s   s   | ]\}}t ||V  qd S )N)r6   )r   r7   r   r   r   r   r1     s    z"Cycler.simplify.<locals>.<genexpr>)r:   r	   r   r;   r<   )r   r=   r   r   r   simplify}  s    zCycler.simplifyc             C   s
   t | |S )aF  Concatenate this cycler and an other.

        The keys must match exactly.

        This returns a single Cycler which is equivalent to
        `itertools.chain(self, other)`

        Examples
        --------

        >>> num = cycler('a', range(3))
        >>> let = cycler('a', 'abc')
        >>> num.concat(let)
        cycler('a', [0, 1, 2, 'a', 'b', 'c'])

        Parameters
        ----------
        other : `Cycler`
            The `Cycler` to concatenate to this one.

        Returns
        -------
        ret : `Cycler`
            The concatenated `Cycler`
        )concat)r   rC   r   r   r   ra     s    zCycler.concat)NN)__name__
__module____qualname____doc__r   r#   propertyr   r)   r/   classmethodr5   r>   r@   rD   rG   rH   rJ   rM   rN   rP   rX   r^   r:   Z
_transposer`   ra   r   r   r   r   r   M   s,   
#	r   c                sj   | j |j kr>ddddgj| j |j @ | j |j A d}t||   | tt fdd| j D S )a  Concatenate two cyclers.

    The keys must match exactly.

    This returns a single Cycler which is equivalent to
    `itertools.chain(left, right)`

    Examples
    --------

    >>> num = cycler('a', range(3))
    >>> let = cycler('a', 'abc')
    >>> num.concat(let)
    cycler('a', [0, 1, 2, 'a', 'b', 'c'])

    Parameters
    ----------
    left, right : `Cycler`
        The two `Cycler` instances to concatenate

    Returns
    -------
    ret : `Cycler`
        The concatenated `Cycler`
    z
	zKeys do not match:zIntersection: {both!r}zDisjoint: {just_one!r})ZbothZjust_onec             3   s$   | ]}t | | |  V  qd S )N)r6   )r   r7   )_l_rr   r   r1     s    zconcat.<locals>.<genexpr>)r   joinrB   r   r:   r	   r   )r   r   rW   r   )rh   ri   r   ra     s    
ra   c              O   s   | r|rt dt| dkr>t| d ts2t dt| d S t| dkrRt|  S t| dkrft d|rttdd t|D S t d	d
S )a  
    Create a new `Cycler` object from a single positional argument,
    a pair of positional arguments, or the combination of keyword arguments.

    cycler(arg)
    cycler(label1=itr1[, label2=iter2[, ...]])
    cycler(label, itr)

    Form 1 simply copies a given `Cycler` object.

    Form 2 composes a `Cycler` as an inner product of the
    pairs of keyword arguments. In other words, all of the
    iterables are cycled simultaneously, as if through zip().

    Form 3 creates a `Cycler` from a label and an iterable.
    This is useful for when the label cannot be a keyword argument
    (e.g., an integer or a name that has a space in it).

    Parameters
    ----------
    arg : Cycler
        Copy constructor for Cycler (does a shallow copy of iterables).

    label : name
        The property key. In the 2-arg form of the function,
        the label can be any hashable object. In the keyword argument
        form of the function, it must be a valid python identifier.

    itr : iterable
        Finite length iterable of the property values.
        Can be a single-property `Cycler` that would
        be like a key change, but as a shallow copy.

    Returns
    -------
    cycler : Cycler
        New `Cycler` for the given property

    zBcyl() can only accept positional OR keyword arguments -- not both.   r   zEIf only one positional argument given, it must  be a Cycler instance.   zdOnly a single Cycler can be accepted as the lone positional argument. Use keyword arguments instead.c             s   s   | ]\}}t ||V  qd S )N)r6   )r   r7   r   r   r   r   r1     s    zcycler.<locals>.<genexpr>z4Must have at least a positional OR keyword argumentsN)	rK   rA   r   r   r6   r	   r   r;   r<   )argskwargsr   r   r   cycler  s    (ro   c                sN   t |trB|j}t|dkr(d}t||   fdd|D }t| |S )aI  
    Create a new `Cycler` object from a property name and
    iterable of values.

    Parameters
    ----------
    label : hashable
        The property key.

    itr : iterable
        Finite length iterable of the property values.

    Returns
    -------
    cycler : Cycler
        New `Cycler` for the given property
    rk   z2Can not create Cycler from a multi-property Cyclerc             3   s   | ]}|  V  qd S )Nr   )r   r   )rS   r   r   r1   ,  s    z_cycler.<locals>.<genexpr>)r   r   r   rA   r   rU   r5   )r0   r4   r   rW   r   )rS   r   r6     s    
r6   )re   Z
__future__r   r   r   r   r;   	itertoolsr   r   Z	six.movesr   r	   operatorr
   r   r   __version__r   objectr   ra   ro   r6   r   r   r   r   <module>)   s     a(=