U
    Ձ]<>                  
   @   sn  d dl Z d dlmZ d dlmZ zd dlmZ W n  ek
rP   d dlm	Z Y nX d dl
Z
d dlZddlmZmZ ddlmZ e d	d
ddddddgZdd Zdd Zdd Ze
jddG dd deZdd Zdd Zdd  Zd!d" Zd#d$ Ze
jd%d%d&G d'd( d(eZe
jddG d)d* d*eZe
jd%d%d&G d+d, d,eZ e Z!d-d. Z"G d/d0 d0eZ#dS )1    Nwraps)count)getfullargspec)
getargspec   )Transitioner	Automaton)preserveNameArgSpecargsvarargsvarkwdefaults
kwonlyargskwonlydefaultsannotationsc              
   C   s   t | }tt|j|jtjr"|jn|j|j	r2|j	ndtjrDt|j
ndtjrd|jr`t|j qfdndtjrzt|j nddS )z
    Normalize inspect.ArgSpec across python versions
    and convert mutable attributes to immutable types.

    :param Callable func: A function.
    :return: The function's ArgSpec.
    :rtype: ArgSpec
     )r   r   r   r   r   r   r   )getArgsSpecr   tupler   r   sixZPY3r   keywordsr   r   r   itemsr   )funcspecr   r   5/usr/lib/python3/dist-packages/automat/_methodical.py_getArgSpec   s     	r   c                 C   s2   t | j| j | jrdnd | jr$dnd | j S )a0  
    Get the name of all arguments defined in a function signature.

    The name of * and ** arguments is normalized to "*args" and "**kwargs".

    :param ArgSpec spec: A function to interrogate for a signature.
    :return: The set of all argument names in `func`s signature.
    :rtype: Set[str]
    )z*argsr   )z**kwargs)setr   r   r   r   r   )r   r   r   r   _getArgNames2   s    
r   c                    s   t   fdd}|S )a  
    Decorate a function so all its arguments must be passed by keyword.

    A useful utility for decorators that take arguments so that they don't
    accidentally get passed the thing they're decorating as their first
    argument.

    Only works for methods right now.
    c                    s    | f|S Nr   )selfkwfr   r   gO   s    z_keywords_only.<locals>.gr   )r#   r$   r   r"   r   _keywords_onlyE   s    
r%   T)frozenc                   @   sD   e Zd ZdZejddZe ZejddZe	fddZ
dd ZdS )	MethodicalStatez-
    A state for a L{MethodicalMachine}.
    Freprc                 C   sj   t |j}|D ]B}t |j}||stdj|jj|jjt|jt|jdq| j	| |||| dS )ac  
        Declare a state transition within the :class:`automat.MethodicalMachine`
        associated with this :class:`automat.MethodicalState`:
        upon the receipt of the `input`, enter the `state`,
        emitting each output in `outputs`.

        :param MethodicalInput input: The input triggering a state transition.
        :param MethodicalState enter: The resulting state.
        :param Iterable[MethodicalOutput] outputs: The outputs to be triggered
            as a result of the declared state transition.
        :param Callable collector: The function to be used when collecting
            output return values.

        :raises TypeError: if any of the `outputs` signatures do not match
            the `inputs` signature.
        :raises ValueError: if the state transition from `self` via `input`
            has already been defined.
        zdmethod {input} signature {inputSignature} does not match output {output} signature {outputSignature})inputoutputZinputSignatureZoutputSignatureN)
r   argSpecissubset	TypeErrorformatmethod__name__r   machine_oneTransition)r    r*   Zenteroutputs	collectorZ	inputArgsr+   Z
outputArgsr   r   r   upon^   s    


	zMethodicalState.uponc                 C   s   | j jS r   r0   r1   r    r   r   r   _name   s    zMethodicalState._nameN)r1   
__module____qualname____doc__attribr2   r0   
serializedlistr6   r9   r   r   r   r   r'   U   s   "r'   c                 C   s0   t | |d}|dkr,t||j}t| || |S )z
    Get a L{Transitioner}
    N)getattrr   initialStatesetattr)oselfsymbol	automatontransitionerr   r   r   _transitionerFromInstance   s    rH   c                   C   s   d S r   r   r   r   r   r   _empty   s    rI   c                   C   s   dS )Z	docstringNr   r   r   r   r   
_docstring   s    rJ   c                 C   s$   |j jtj jtj jfkr tdd S )Nzfunction body must be empty)__code__co_coderI   rJ   
ValueError)instZ	attributer#   r   r   r   assertNoCode   s    rO   c                    s   t t|jdd | }jr$| }nfdd|D }t ||D ]\}}||f7 qBt|jddd |jddd }fdd|D }	|	| jr|	}
n*jdd j   fdd|	 D }
||
fS )	a  
    Filter out arguments that were passed to input that output won't accept.

    :param tuple args: The *args that input received.
    :param dict kwargs: The **kwargs that input received.
    :param ArgSpec inputSpec: The input's arg spec.
    :param ArgSpec outputSpec: The output's arg spec.
    :return: The args and kwargs that output will accept.
    :rtype: Tuple[tuple, dict]
    r   Nc                    s   g | ]\}}| j kr|qS r   )r   .0nv)
outputSpecr   r   
<listcomp>   s     
 z_filterArgs.<locals>.<listcomp>c                    s   i | ]\}}| kr||qS r   r   rP   )passed_arg_namesr   r   
<dictcomp>   s       z_filterArgs.<locals>.<dictcomp>c                    s   i | ]\}}| kr||qS r   r   rP   )all_accepted_namesr   r   rX      s     )	r   zipr   r   r   updater   r   r   )r   kwargsZ	inputSpecrT   Z
named_argsZreturn_argsnamevaluer   Zfull_kwargsZreturn_kwargsr   )rY   rT   rW   r   _filterArgs   s    "
r_   F)Zcmphashc                   @   sv   e Zd ZdZejddZejedZejddZ	eje
eddZejdddZejdd Zdd
dZdd Zd	S )MethodicalInputz.
    An input for a L{MethodicalMachine}.
    Fr(   )Z	validator)defaultr)   Zinitr)   c                 C   s
   t | jS r   r   r0   r8   r   r   r   _buildArgSpec   s    zMethodicalInput._buildArgSpecNc                    s8   t  jjtjtj fdd}|S )z
        Return a function that takes no arguments and returns values returned
        by output functions produced by the given L{MethodicalInput} in
        C{oself}'s current state.
        c                     s   j  f| | j}\}}j| }g }|D ]D}|rL||  t| |j|j\}}	| f||	}
||
 q8||S r   )r0   _stateZ
transition
collectorsr9   r_   r,   append)r   r\   ZpreviousStater4   Z	outTracerr5   valuesr+   akr^   rD   r    rG   r   r   doInput   s    
z(MethodicalInput.__get__.<locals>.doInput)rH   rE   rF   r
   r0   r   )r    rD   typerm   r   rl   r   __get__   s    zMethodicalInput.__get__c                 C   s   | j jS r   r7   r8   r   r   r   r9      s    zMethodicalInput._name)N)r1   r:   r;   r<   r=   r>   rF   rO   r0   rE   ZFactorydictrg   r,   rb   re   ro   r9   r   r   r   r   ra      s   

ra   c                   @   sZ   e Zd ZdZejddZe ZejdddZej	dd Z
ddd	Zd
d Zdd ZdS )MethodicalOutputz/
    An output for a L{MethodicalMachine}.
    Fr(   rc   c                 C   s
   t | jS r   rd   r8   r   r   r   re     s    zMethodicalOutput._buildArgSpecNc                 C   s   t dj|j| jjddS )zX
        Outputs are private, so raise an exception when we attempt to get one.
        zf{cls}.{method} is a state-machine output method; to produce this output, call an input method instead.)clsr0   N)AttributeErrorr/   r1   r0   r    rD   rn   r   r   r   ro   
  s    zMethodicalOutput.__get__c                 O   s   | j |f||S )z-
        Call the underlying method.
        )r0   )r    rD   r   r\   r   r   r   __call__  s    zMethodicalOutput.__call__c                 C   s   | j jS r   r7   r8   r   r   r   r9     s    zMethodicalOutput._name)N)r1   r:   r;   r<   r=   r>   r2   r0   r,   rb   re   ro   ru   r9   r   r   r   r   rq      s   

rq   c                   @   s.   e Zd ZejddZejddZdddZdS )MethodicalTracerFr(   Nc                    s    t || j| j  fdd}|S )Nc                    s     |  d S r   )setTrace)ZtracerrG   r   r   rw   )  s    z*MethodicalTracer.__get__.<locals>.setTrace)rH   rE   rF   )r    rD   rn   rw   r   rx   r   ro   &  s
    zMethodicalTracer.__get__)N)r1   r:   r;   r=   r>   rF   rE   ro   r   r   r   r   rv      s   rv   c                   C   s   dt tt S )z,
    Create a unique Python identifier.
    Z_symbol_)strnextcounterr   r   r   r   gensym0  s    r|   c                   @   s|   e Zd ZdZdd ZdddZeddd	Zed
d Zedd Z	dd Z
edd Zedd Zedd Zdd ZdS )MethodicalMachinezj
    A :class:`MethodicalMachine` is an interface to an `Automaton`
    that uses methods on a class.
    c                 C   s   t  | _i | _t | _d S r   )r	   
_automatonZ	_reducersr|   _symbolr8   r   r   r   __init__>  s    zMethodicalMachine.__init__Nc                 C   s   |dk	rt d| S )z
        L{MethodicalMachine} is an implementation detail for setting up
        class-level state; applications should never need to access it on an
        instance.
        Nz.MethodicalMachine is an implementation detail.)rs   rt   r   r   r   ro   D  s
    zMethodicalMachine.__get__Fc                    s    fdd}|S )a  
        Declare a state, possibly an initial state or a terminal state.

        This is a decorator for methods, but it will modify the method so as
        not to be callable any more.

        :param bool initial: is this state the initial state?
            Only one state on this :class:`automat.MethodicalMachine`
            may be an initial state; more than one is an error.

        :param bool terminal: Is this state a terminal state?
            i.e. a state that the machine can end up in?
            (This is purely informational at this point.)

        :param Hashable serialized: a serializable value
            to be used to represent this state to external systems.
            This value should be hashable;
            :py:func:`unicode` is a good type to use.
        c                    s   t | d} r|j_|S )N)r2   r0   r?   )r'   r~   rB   )ZstateMethodstateinitialr    r?   r   r   	decoratorf  s    z*MethodicalMachine.state.<locals>.decoratorr   )r    r   Zterminalr?   r   r   r   r   r   P  s    zMethodicalMachine.statec                    s    fdd}|S )zM
        Declare an input.

        This is a decorator for methods.
        c                    s   t  j|  jdS )N)rF   r0   rE   )ra   r~   r   )ZinputMethodr8   r   r   r   w  s    z*MethodicalMachine.input.<locals>.decoratorr   r    r   r   r8   r   r*   p  s    zMethodicalMachine.inputc                    s    fdd}|S )z
        Declare an output.

        This is a decorator for methods.

        This method will be called when the state machine transitions to this
        state as specified in the decorated `output` method.
        c                    s   t  | dS )N)r2   r0   )rq   )ZoutputMethodr8   r   r   r     s    z+MethodicalMachine.output.<locals>.decoratorr   r   r   r8   r   r+   ~  s    
zMethodicalMachine.outputc                 C   s$   | j |||t| ||j|< dS )z.
        See L{MethodicalState.upon}.
        N)r~   ZaddTransitionr   rg   )r    Z
startStateZ
inputTokenZendStateZoutputTokensr5   r   r   r   r3     s    z MethodicalMachine._oneTransitionc                    s    fdd}|S )


        c                    s   t   fdd}|S )Nc                    s   t | jj} | |jjS r   )rH   r   r~   rf   r?   )rD   rG   	decorateer    r   r   	serialize  s    zBMethodicalMachine.serializer.<locals>.decorator.<locals>.serializer   )r   r   r8   r   r   r     s    z/MethodicalMachine.serializer.<locals>.decoratorr   r   r   r8   r   
serializer  s    zMethodicalMachine.serializerc                    s    fdd}|S )r   c                    s   t   fdd}|S )Nc                    sL    | f||}i }j  D ]}|||j< qt| jj }|| |_d S r   )r~   Zstatesr?   rH   r   rf   )rD   r   r\   r   mappingZ	eachStaterG   r   r   r   unserialize  s      
zFMethodicalMachine.unserializer.<locals>.decorator.<locals>.unserializer   )r   r   r8   r   r   r     s    	z1MethodicalMachine.unserializer.<locals>.decoratorr   r   r   r8   r   unserializer  s    zMethodicalMachine.unserializerc                 C   s   t | j| jS r   )rv   r~   r   r8   r   r   r   	_setTrace  s    zMethodicalMachine._setTracec                 C   s*   ddl m} || jdd dd dd dS )a  
        Generate a L{graphviz.Digraph} that represents this machine's
        states and transitions.

        @return: L{graphviz.Digraph} object; for more information, please
            see the documentation for
            U{graphviz<https://graphviz.readthedocs.io/>}

        r   )makeDigraphc                 S   s   | j jS r   r7   )r   r   r   r   <lambda>      z-MethodicalMachine.asDigraph.<locals>.<lambda>c                 S   s   | j jS r   r7   )r*   r   r   r   r     r   c                 S   s   | j jS r   r7   )r+   r   r   r   r     r   )ZstateAsStringZinputAsStringZoutputAsString)Z
_visualizer   r~   )r    r   r   r   r   	asDigraph  s    
zMethodicalMachine.asDigraph)N)FFN)r1   r:   r;   r<   r   ro   r%   r   r*   r+   r3   r   r   propertyr   r   r   r   r   r   r}   8  s&   
  




r}   )$collections	functoolsr   	itertoolsr   inspectr   r   ImportErrorr   r=   r   Z_corer   r	   Z_introspectionr
   
namedtupler   r   r   r%   sobjectr'   rH   rI   rJ   rO   r_   ra   rq   rv   r{   r|   r}   r   r   r   r   <module>   sF     
.(+
"