3
® h·8  ã               @   sn   d Z ddlZddlmZ ddlmZmZ ddlmZm	Z	 dZ
dd„ Zd	d
„ ZG d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': '-.'}
é    N)Úreduce)ÚproductÚcycle)ÚmulÚaddz0.10.0c             C   s`   | dk	rt t| ƒƒni }|dk	r,t t|ƒƒni }t|jƒ ƒ}t|jƒ ƒ}||@ 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   ú(/tmp/pip-build-fibhr3ey/cycler/cycler.pyÚ_process_keys4   s    r   c                sZ   | j |j kr.tdj| j |j @ | j |j A dƒ‚| jƒ ‰ |jƒ ‰tt‡ ‡fdd„| j D ƒƒS )aS  
    Concatenate `Cycler`\s, as if chained using `itertools.chain`.

    The keys must match exactly.

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

    Returns
    -------
    `Cycler`
        The concatenated cycler.
    zBKeys do not match:
	Intersection: {both!r}
	Disjoint: {just_one!r})ZbothZjust_onec             3   s$   | ]}t |ˆ | ˆ|  ƒV  qd S )N)Ú_cycler)Ú.0Úk)Ú_lÚ_rr   r   ú	<genexpr>e   s    zconcat.<locals>.<genexpr>)r
   r   ÚformatÚby_keyr   r   )r   r   r   )r   r   r   ÚconcatK   s    
r   c               @   sÆ   e Zd ZdZdd„ Zd+dd„Zdd„ Ze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Zd#d$„ Zd%d&„ Zd'd(„ ZeZd)d*„ Ze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, right : Cycler or None
        The 'left' and 'right' cyclers.
    op : func or None
        Function which composes the 'left' and 'right' cyclers.
    c             C   s   t | ƒS )N)r   )Úselfr   r   r   Ú__call__„   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 )zf
        Semi-private init.

        Do not use this directly, use `cycler` function instead.
        Nc             S   s   g | ]}t j |ƒ‘qS r   )Úcopy)r   Úvr   r   r   ú
<listcomp>’   s    z#Cycler.__init__.<locals>.<listcomp>c             S   s   g | ]}t j |ƒ‘qS r   )r   )r   r   r   r   r   r   ›   s    )Ú
isinstancer   Ú_leftÚ_rightÚ_opr   Ú_keys)r   r   r   Úopr   r   r   Ú__init__‡   s    

zCycler.__init__c             C   s
   || j kS )N)r$   )r   r   r   r   r   Ú__contains__¢   s    zCycler.__contains__c             C   s
   t | jƒS )z!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jˆˆ dƒ‚ˆ| j krDtdjˆˆ dƒ‚| j jˆƒ | j jˆ ƒ | jdk	r‚ˆ| jjkr‚| jjˆˆ ƒ n4t	| j
tƒrž| j
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.
        Nz6Can't replace {old} with {new}, {new} is already a key)ÚoldÚnewz2Can't replace {old} with {new}, {old} is not a keyc                s   g | ]}ˆ |ˆ i‘qS r   r   )r   Úentry)r)   r(   r   r   r   Ì   s    z%Cycler.change_key.<locals>.<listcomp>)r$   r   r   ÚKeyErrorÚremover   r"   r
   Ú
change_keyr    r!   r   )r   r(   r)   r   )r)   r(   r   r-   ª   s     	

zCycler.change_keyc                s,   | dƒ}t ‡ fdd„|D ƒƒ|_ˆ h|_|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`
            New 'base' cycler.
        Nc             3   s   | ]}ˆ |iV  qd S )Nr   )r   r   )Úlabelr   r   r   ã   s    z$Cycler._from_iter.<locals>.<genexpr>)Úlistr!   r$   )Úclsr.   ÚitrÚretr   )r.   r   Ú
_from_iterÎ   s    zCycler._from_iterc                s:   t ˆ tƒr.| jƒ }tt‡ fdd„|jƒ D ƒƒS tdƒ‚d S )Nc             3   s    | ]\}}t ||ˆ  ƒV  qd S )N)r   )r   r   r   )Úkeyr   r   r   ë   s    z%Cycler.__getitem__.<locals>.<genexpr>z+Can only use slices with Cycler.__getitem__)r    Úslicer   r   r   Úitemsr   )r   r4   Útransr   )r4   r   Ú__getitem__ç   s    
zCycler.__getitem__c             c   sf   | j d kr&xV| jD ]}t|ƒV  qW n<x:| j| j| j ƒD ]&\}}i }|j|ƒ |j|ƒ |V  q8W d S )N)r"   r!   Údictr#   Úupdate)r   r   ÚaÚbÚoutr   r   r   Ú__iter__ï   s    


zCycler.__iter__c             C   s8   t | ƒt |ƒkr,tdt | ƒ› dt |ƒ› ƒ‚t| |tƒS )z
        Pair-wise combine two equal length cyclers (zip).

        Parameters
        ----------
        other : Cycler
        z&Can only add equal length cycles, not z and )Úlenr   r   Úzip)r   Úotherr   r   r   Ú__add__ú   s    zCycler.__add__c                sL   t ˆ tƒrt| ˆ tƒS t ˆ tƒrD| jƒ }tt‡ fdd„|jƒ D ƒƒS tS dS )z¬
        Outer product of two cyclers (`itertools.product`) or integer
        multiplication.

        Parameters
        ----------
        other : Cycler or int
        c             3   s    | ]\}}t ||ˆ  ƒV  qd S )N)r   )r   r   r   )rA   r   r   r     s    z!Cycler.__mul__.<locals>.<genexpr>N)	r    r   r   Úintr   r   r   r6   ÚNotImplemented)r   rA   r7   r   )rA   r   Ú__mul__  s    	

zCycler.__mul__c             C   s   | | S )Nr   )r   rA   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"   r?   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j| ƒ}t||ƒ| _|| _t| _t|j|j	|jƒ| _	| S )zŠ
        In-place pair-wise combine two equal length cyclers (zip).

        Parameters
        ----------
        other : Cycler
        z"Cannot += with a non-Cycler object)
r    r   Ú	TypeErrorr   r   r$   r!   r@   r#   r"   )r   rA   Úold_selfr   r   r   Ú__iadd__#  s    

zCycler.__iadd__c             C   sL   t |tƒstdƒ‚tj| ƒ}t||ƒ| _|| _t| _t|j|j	|jƒ| _	| S )zŒ
        In-place outer product of two cyclers (`itertools.product`).

        Parameters
        ----------
        other : Cycler
        z"Cannot *= with a non-Cycler object)
r    r   rI   r   r   r$   r!   r   r#   r"   )r   rA   rJ   r   r   r   Ú__imul__5  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 )NFc             s   s   | ]\}}||kV  qd S )Nr   )r   r;   r<   r   r   r   r   L  s    z Cycler.__eq__.<locals>.<genexpr>)r?   r
   Úallr@   )r   rA   r   r   r   Ú__eq__G  s
    zCycler.__eq__c             C   s
   | |k S )Nr   )r   rA   r   r   r   Ú__ne__N  s    zCycler.__ne__c                sr   t dtdi}| jd krH| jjƒ ‰ t‡ fdd„| D ƒƒ}dˆ ›d|›dS |j| jdƒ}d	}|j| j	|| jd
S d S )Nú+Ú*c             3   s   | ]}|ˆ  V  qd S )Nr   )r   r   )Úlabr   r   r   W  s    z"Cycler.__repr__.<locals>.<genexpr>zcycler(z, ú)ú?z({left!r} {op} {right!r}))r   r%   r   )
r@   r   r"   r
   Úpopr/   Úgetr#   r   r!   )r   Zop_mapr1   r%   Úmsgr   )rR   r   Ú__repr__S  s    

zCycler.__repr__c             C   s€   d}t | jtd}x|D ]}|d|›d7 }qW xBt| ƒD ]6}|d7 }x |D ]}|d|| ›d7 }qLW |d7 }q:W |d	7 }|S )
Nz<table>)r4   z<th>z</th>z<tr>z<td>z</td>z</tr>z</table>)Úsortedr
   Úreprr   )r   ÚoutputZsorted_keysr4   Údr   r   r   r   Ú_repr_html_^  s    

zCycler._repr_html_c             C   sF   | j }dd„ |D ƒ}x,| D ]$}x|D ]}|| j|| ƒ 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   i | ]}t ƒ |“qS r   )r/   )r   r   r   r   r   ú
<dictcomp>‚  s    z!Cycler.by_key.<locals>.<dictcomp>)r
   Úappend)r   r
   r=   r\   r   r   r   r   r   l  s    

zCycler.by_keyc             C   s    | j ƒ }ttdd„ |jƒ D ƒƒS )z‡
        Simplify the cycler into a sum (but no products) of cyclers.

        Returns
        -------
        simple : Cycler
        c             s   s   | ]\}}t ||ƒV  qd S )N)r   )r   r   r   r   r   r   r   š  s    z"Cycler.simplify.<locals>.<genexpr>)r   r   r   r6   )r   r7   r   r   r   ÚsimplifyŒ  s    zCycler.simplify)NN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r&   r'   Úpropertyr
   r-   Úclassmethodr3   r8   r>   rB   rE   rF   rH   rK   rL   rN   rO   Ú__hash__rX   r]   r   Z
_transposer`   r   r   r   r   r   r   h   s0   
$r   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ƒ‚|r‚ttdd„ |jƒ 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   zDIf 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)r   )r   r   r   r   r   r   r   Õ  s    zcycler.<locals>.<genexpr>z4Must have at least a positional OR keyword argumentsN)rI   r?   r    r   r   r   r   r6   )ÚargsÚkwargsr   r   r   ÚcyclerŸ  s    &rl   c                sN   t |tƒrB|j}t|ƒdkr(d}t|ƒ‚|jƒ ‰ ‡ fdd„|D ƒ}tj| |ƒS )aD  
    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
    rh   z2Can not create Cycler from a multi-property Cyclerc             3   s   | ]}|ˆ  V  qd S )Nr   )r   r   )rR   r   r   r   ó  s    z_cycler.<locals>.<genexpr>)r    r   r
   r?   r   rU   r3   )r.   r1   r
   rW   r   )rR   r   r   Ú  s    
r   )rd   r   Ú	functoolsr   Ú	itertoolsr   r   Úoperatorr   r   Ú__version__r   r   r   rl   r   r   r   r   r   Ú<module>)   s     9;