o
    I^:>                     @   sb  d dl Z d dlmZ d dlmZ zd dlmZ W n ey'   d dlm	Z Y nw d dl
Z
d dlZddlmZmZ ddlmZ e d	g d
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)d* d*eZ#dS )+    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	r|j	ndtjr"t|j
ndtjr2|jr0t|j ndndtjr?t|j dS 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   )getArgsSpecr   tupler   r   six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i |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 ]!}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outputinputSignatureoutputSignatureN)
r    argSpecissubset	TypeErrorformatmethod__name__r   machine_oneTransition)r"   r,   enteroutputs	collector	inputArgsr-   
outputArgsr   r   r   upon^   s   



zMethodicalState.uponc                 C      | j jS r!   r4   r5   r"   r   r   r   _name      zMethodicalState._nameN)r5   
__module____qualname____doc__attribr6   r4   
serializedlistr=   rA   r   r   r   r   r)   U   s    "r)   c                 C   s0   t | |d}|du rt||j}t| || |S )z
    Get a L{Transitioner}
    N)getattrr   initialStatesetattr)oselfsymbol	automatontransitionerr   r   r   _transitionerFromInstance   s   rQ   c                   C   s   d S r!   r   r   r   r   r   _empty   s   rR   c                   C   s   dS )	docstringNr   r   r   r   r   
_docstring   s    rT   c                 C   s$   |j jtj jtj jfvrtdd S )Nzfunction body must be empty)__code__co_coderR   rT   
ValueError)inst	attributer%   r   r   r   assertNoCode   s
   rZ   c                    s   t t|jdd | }jr| }n	fdd|D }t ||D ]
\}}||f7 q!t|jddd |jddd }fdd|D }	|	| jrT|	}
||
fS 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 v r|qS r   )r   .0nv)
outputSpecr   r   
<listcomp>       z_filterArgs.<locals>.<listcomp>c                    s   i | ]\}}| vr||qS r   r   r[   )passed_arg_namesr   r   
<dictcomp>   ra   z_filterArgs.<locals>.<dictcomp>c                    s   i | ]\}}| v r||qS r   r   r[   )all_accepted_namesr   r   rd      s    )	r   zipr   r   r   updater   r   r   )r   kwargs	inputSpecr_   
named_argsreturn_argsnamevaluer   full_kwargsreturn_kwargsr   )re   r_   rc   r   _filterArgs   s    "
rp   F)eq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*   )	validator)defaultr+   initr+   c                 C   
   t | jS r!   r   r4   r@   r   r   r   _buildArgSpec      
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  g| R i | j}\}}j| }g }|D ]%}|r)||  t| |j|j\}}	| g|R i |	}
||
 q||S r!   )r4   _state
transition
collectorsrA   rp   r0   append)r   rh   previousStater9   	outTracerr:   valuesr-   akrm   rM   r"   rP   r   r   doInput   s   
z(MethodicalInput.__get__.<locals>.doInput)rQ   rN   rO   r
   r4   r   )r"   rM   typer   r   r   r   __get__   s   zMethodicalInput.__get__c                 C   r>   r!   r?   r@   r   r   r   rA      rB   zMethodicalInput._namer!   )r5   rC   rD   rE   rF   rG   rO   rZ   r4   rN   Factorydictr~   r0   ru   rz   r   rA   r   r   r   r   rs      s    

rs   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*   rv   c                 C   rx   r!   ry   r@   r   r   r   rz     r{   zMethodicalOutput._buildArgSpecNc                 C   s   t dj|j| jjd)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.)clsr4   )AttributeErrorr3   r5   r4   r"   rM   r   r   r   r   r   
  s   zMethodicalOutput.__get__c                 O   s   | j |g|R i |S )z-
        Call the underlying method.
        )r4   )r"   rM   r   rh   r   r   r   __call__  s   zMethodicalOutput.__call__c                 C   r>   r!   r?   r@   r   r   r   rA     rB   zMethodicalOutput._namer!   )r5   rC   rD   rE   rF   rG   r6   r4   r0   ru   rz   r   r   rA   r   r   r   r   r      s    

r   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)tracerrP   r   r   r   )  s   z*MethodicalTracer.__get__.<locals>.setTrace)rQ   rN   rO   )r"   rM   r   r   r   r   r   r   &  s
   zMethodicalTracer.__get__r!   )r5   rC   rD   rF   rG   rO   rN   r   r   r   r   r   r      s    r   c                   C   s   dt tt S )z,
    Create a unique Python identifier.
    _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	   
_automaton	_reducersr   _symbolr@   r   r   r   __init__>  s   zMethodicalMachine.__init__Nc                 C   s   |du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.)r   r   r   r   r   r   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)r6   r4   rH   )r)   r   rK   )stateMethodstateinitialr"   rH   r   r   	decoratorf  s   z*MethodicalMachine.state.<locals>.decoratorr   )r"   r   terminalrH   r   r   r   r   r   P  s   zMethodicalMachine.statec                        fdd}|S )zM
        Declare an input.

        This is a decorator for methods.
        c                    s   t  j|  jdS )N)rO   r4   rN   )rs   r   r   )inputMethodr@   r   r   r   w  s   z*MethodicalMachine.input.<locals>.decoratorr   r"   r   r   r@   r   r,   p  s   zMethodicalMachine.inputc                    r   )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)r6   r4   )r   )outputMethodr@   r   r   r     s   z+MethodicalMachine.output.<locals>.decoratorr   r   r   r@   r   r-   ~  s   
zMethodicalMachine.outputc                 C   s$   | j |||t| ||j|< dS )z.
        See L{MethodicalState.upon}.
        N)r   addTransitionr   r~   )r"   
startState
inputTokenendStateoutputTokensr:   r   r   r   r7     s   z MethodicalMachine._oneTransitionc                    r   )


        c                       t   fdd}|S )Nc                    s   t | jj} | |jjS r!   )rQ   r   r   r|   rH   )rM   rP   	decorateer"   r   r   	serialize  s   zBMethodicalMachine.serializer.<locals>.decorator.<locals>.serializer   )r   r   r@   r   r   r     s   z/MethodicalMachine.serializer.<locals>.decoratorr   r   r   r@   r   
serializer  s   zMethodicalMachine.serializerc                    r   )r   c                    r   )Nc                    sR    | g|R i |}i }j  D ]}|||j< qt| jj }|| |_d S r!   )r   statesrH   rQ   r   r|   )rM   r   rh   r   mapping	eachStaterP   r   r   r   unserialize  s   

zFMethodicalMachine.unserializer.<locals>.decorator.<locals>.unserializer   )r   r   r@   r   r   r     s   	z1MethodicalMachine.unserializer.<locals>.decoratorr   r   r   r@   r   unserializer  s   zMethodicalMachine.unserializerc                 C   s   t | j| jS r!   )r   r   r   r@   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   r>   r!   r?   )r   r   r   r   <lambda>      z-MethodicalMachine.asDigraph.<locals>.<lambda>c                 S   r>   r!   r?   )r,   r   r   r   r     r   c                 S   r>   r!   r?   )r-   r   r   r   r     r   )stateAsStringinputAsStringoutputAsString)
_visualizer   r   )r"   r   r   r   r   	asDigraph  s   
zMethodicalMachine.asDigraphr!   )FFN)r5   rC   rD   rE   r   r   r'   r   r,   r-   r7   r   r   propertyr   r   r   r   r   r   r   8  s(    





r   )$collections	functoolsr   	itertoolsr   inspectr   r   ImportErrorr   rF   r   _corer   r	   _introspectionr
   
namedtupler   r   r    r'   sobjectr)   rQ   rR   rT   rZ   rp   rs   r   r   r   r   r   r   r   r   r   <module>   s@   
.(
+"