B
    `O                 @   s   d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZm	Z	m
Z
 d dlmZ d dlmZ d dlmZmZ G dd dZG d	d
 d
ZG dd dZdddZdd ZdddZeeG dd dZdd ZdS )    N)implementer)ConfigurationConflictErrorConfigurationErrorConfigurationExecutionError)IActionInfo)undefer)is_nonstr_iterreraisec               @   sH   e Zd Zedd ZdddZdd	 Zd
d ZeeeZeZ	dd Z
dS )ActionConfiguratorMixinc             C   s.   | j }|s*| jr| jd }ntd ddd}|S )Nr    )info_ainfo
ActionInfo)selfr    r   ^/home/kop/projects/devel/pgwui/test_venv/lib/python3.7/site-packages/pyramid/config/actions.pyaction_info   s    z#ActionConfiguratorMixin.action_infoNr   r   c             K   s   t |st|dkri }| j}| j}	| js.d}|r|   z:t| |dk	rV||| x|D ]}
|
| j|	 q\W W d| 	  X n2|}|
t||||||	| j|d | jjf | dS )a  Register an action which will be executed when
        :meth:`pyramid.config.Configurator.commit` is called (or executed
        immediately if ``autocommit`` is ``True``).

        .. warning:: This method is typically only used by :app:`Pyramid`
           framework extension authors, not by :app:`Pyramid` application
           developers.

        The ``discriminator`` uniquely identifies the action.  It must be
        given, but it can be ``None``, to indicate that the action never
        conflicts.  It must be a hashable value.

        The ``callable`` is a callable object which performs the task
        associated with the action when the action is executed.  It is
        optional.

        ``args`` and ``kw`` are tuple and dict objects respectively, which
        are passed to ``callable`` when this action is executed.  Both are
        optional.

        ``order`` is a grouping mechanism; an action with a lower order will
        be executed before an action with a higher order (has no effect when
        autocommit is ``True``).

        ``introspectables`` is a sequence of :term:`introspectable` objects
        (or the empty sequence if no introspectable objects are associated
        with this action).  If this configurator's ``introspection``
        attribute is ``False``, these introspectables will be ignored.

        ``extra`` provides a facility for inserting extra keys and values
        into an action dictionary.
        Nr   )discriminatorcallableargskworderr   includepathintrospectables)hashAssertionError
autocommitr   Zintrospectionbeginr   registerintrospectorendupdatedictr   action_stateaction)r   r   r   r   r   r   r   extrar   r   introspectabler$   r   r   r   r$      s8    ,


zActionConfiguratorMixin.actionc             C   s6   | j }y
|j}W n  tk
r0   t }||_Y nX |S )N)registryr#   AttributeErrorActionState)r   r'   stater   r   r   _get_action_statet   s    
z)ActionConfiguratorMixin._get_action_statec             C   s   || j _d S )N)r'   r#   )r   r*   r   r   r   _set_action_state}   s    z)ActionConfiguratorMixin._set_action_statec             C   s4   |    z| jj| jd W d|   X t | _dS )a  
        Commit any pending configuration actions. If a configuration
        conflict is detected in the pending configuration actions, this method
        will raise a :exc:`ConfigurationConflictError`; within the traceback
        of this error will be information about the source of the conflict,
        usually including file names and line numbers of the cause of the
        configuration conflicts.

        .. warning::
           You should think very carefully before manually invoking
           ``commit()``. Especially not as part of any reusable configuration
           methods. Normally it should only be done by an application author at
           the end of configuration in order to override certain aspects of an
           addon.

        )r   N)r   r#   execute_actionsr   r    r)   )r   r   r   r   commit   s
    
zActionConfiguratorMixin.commit)Nr   Nr   r   )__name__
__module____qualname__propertyr   r$   r+   r,   r#   Z_ctxr.   r   r   r   r   r
      s       
O	
r
   c               @   s0   e Zd Zdd Zdd Zddd	ZdddZdS )r)   c             C   s   g | _ t | _d S )N)actionsset_seen_files)r   r   r   r   __init__   s    zActionState.__init__c             C   s   || j krdS | j | dS )ao  Check whether a callable needs to be processed.  The ``spec``
        refers to a unique identifier for the callable.

        Return True if processing is needed and False otherwise. If
        the callable needs to be processed, it will be marked as
        processed, assuming that the caller will process the callable if
        it needs to be processed.
        FT)r5   add)r   specr   r   r   processSpec   s    	
zActionState.processSpecNr   r   c	             K   s>   |dkri }|	}
|
 t||||||||d | j|
 dS )zKAdd an action with the given discriminator, callable, and
        argumentsN)r   r   r   r   r   r   r   r   )r!   r"   r3   append)r   r   r   r   r   r   r   r   r   r%   r$   r   r   r   r$      s    
zActionState.actionTc          	   C   s,  zg }g }t g }t }x| jrB|| j t| j|d}g | _t|d}|dkrVP |d }|d }	|d }
|d }|dd}y|dk	r||	|
 W nD tk
r   t	 \}}}zt
tt|||| W d~~~X Y nX |dk	rx|D ]}||| qW || qW || _|S |r&g | _X dS )	aJ  Execute the configuration actions

        This calls the action callables after resolving conflicts

        For example:

        >>> output = []
        >>> def f(*a, **k):
        ...    output.append(('f', a, k))
        >>> context = ActionState()
        >>> context.actions = [
        ...   (1, f, (1,)),
        ...   (1, f, (11,), {}, ('x', )),
        ...   (2, f, (2,)),
        ...   ]
        >>> context.execute_actions()
        >>> output
        [('f', (1,), {}), ('f', (2,), {})]

        If the action raises an error, we convert it to a
        ConfigurationExecutionError.

        >>> output = []
        >>> def bad():
        ...    bad.xxx
        >>> context.actions = [
        ...   (1, f, (1,)),
        ...   (1, f, (11,), {}, ('x', )),
        ...   (2, f, (2,)),
        ...   (3, bad, (), {}, (), 'oops')
        ...   ]
        >>> try:
        ...    v = context.execute_actions()
        ... except ConfigurationExecutionError, v:
        ...    pass
        >>> print(v)
        exceptions.AttributeError: 'function' object has no attribute 'xxx'
          in:
          oops

        Note that actions executed before the error still have an effect:

        >>> output
        [('f', (1,), {}), ('f', (2,), {})]

        The execution is re-entrant such that actions may be added by other
        actions with the one caveat that the order of any added actions must
        be equal to or larger than the current action.

        >>> output = []
        >>> def f(*a, **k):
        ...   output.append(('f', a, k))
        ...   context.actions.append((3, g, (8,), {}))
        >>> def g(*a, **k):
        ...    output.append(('g', a, k))
        >>> context.actions = [
        ...   (1, f, (1,)),
        ...   ]
        >>> context.execute_actions()
        >>> output
        [('f', (1,), {}), ('g', (8,), {})]

        )r*   Nr   r   r   r   r   r   )iterConflictResolverStater3   extendresolveConflictsnextget	Exceptionsysexc_infor	   r   r   r:   )r   clearr   Zall_actionsZexecuted_actionsZaction_iterZconflict_stater$   r   r   r   r   r   tvtbr&   r   r   r   r-      sL    @




zActionState.execute_actions)Nr   Nr   r   Nr   )TN)r/   r0   r1   r6   r9   r$   r-   r   r   r   r   r)      s         
r)   c               @   s   e Zd Zdd ZdS )r<   c             C   s   i | _ g | _d | _d| _d S )Nr   )resolved_ainfosremaining_actions	min_orderstart)r   r   r   r   r6   N  s    zConflictResolverState.__init__N)r/   r0   r1   r6   r   r   r   r   r<   M  s   r<   c             #   s  |dkrt  }|jt|  |j} dd }dd }tt| |jd|d}xt||D ]\ }g }i }|j	dk	rވ |j	k rd
 |j	g}x>|D ]6\}	}
x,t|
d	  d
D ]}|d|  qW qW td
|xX|D ]P\}	}
|	|
f}t|
d }||
d< |dkr|| q||g }|| qW i }x8| D ]*\}} fdd}|j|d |d |dd  }}|\}}
|j|}|dk	r|\}}|d |d	  }}|
d }|dt| |ks||kr|||g}||
d	  n
|| |
d |
d	  }}xV|D ]N\}}
|
d }|dt| |ksP||kr |||g}||
d	  q W qHW |rt|xXt|tddD ]B\}	}
|
d |_	|	d |_|j|
 |	|
f|j|
d < |
V  qW qZW dS )a  Resolve conflicting actions

    Given an actions list, identify and try to resolve conflicting actions.
    Actions conflict if they have the same non-None discriminator.

    Conflicting actions can be resolved if the include path of one of
    the actions is a prefix of the includepaths of the other
    conflicting actions and is unequal to the include paths in the
    other conflicting actions.

    Actions are resolved on a per-order basis because some discriminators
    cannot be computed until earlier actions have executed. An action in an
    earlier order may execute successfully only to find out later that it was
    overridden by another action with a smaller include path. This will result
    in a conflict as there is no way to revert the original action.

    ``state`` may be an instance of ``ConflictResolverState`` that
    can be used to resume execution and resolve the new actions against the
    list of executed actions from a previous call.

    Nc             S   s   | \}} | d pd|fS )Nr   r   r   )rF   nr   r   r   orderandpos}  s    z%resolveConflicts.<locals>.orderandposc             S   s   | \}} | d pdS )Nr   r   r   )rF   rL   r   r   r   	orderonly  s    z#resolveConflicts.<locals>.orderonly)rK   )keyz^Actions were added to order={} after execution had moved on to order={}. Conflicting actions: r   
z  r   c                s    | d d | d  }}| |fS )N   r   r   r   )ainfopathi)r   r   r   bypath  s    z resolveConflicts.<locals>.bypathr   rQ   r   r   )r<   rI   r=   normalize_actionssorted	enumeraterK   	itertoolsgroupbyrJ   formatstrrstripsplitr:   r   joinr   
setdefaultitemssortrH   r@   lenr   operator
itemgetterremove)r3   r*   rM   rN   ZsactionsZactiongroupoutputuniquerrT   r$   linerR   r   L	conflictsZainfosrU   rest_Z
prev_ainfoZpactionZbasepathZbaseinfor   r   )r   r   r>   `  sr    	







r>   c             C   s2   g }x(| D ] }t |ts t| }|| q
W |S )z3Convert old-style tuple actions to new-style dicts.)
isinstancer"   expand_action_tupler:   )r3   resultrF   r   r   r   rV     s    

rV   r   c          
   C   s$   |d kri }t | |||||||dS )N)r   r   r   r   r   r   r   r   )r"   )r   r   r   r   r   r   r   r   r   r   r   rp     s    
rp   c               @   s   e Zd Zdd Zdd ZdS )r   c             C   s   || _ || _|| _|| _d S )N)filerj   functionsrc)r   rr   rj   rs   rt   r   r   r   r6     s    zActionInfo.__init__c             C   s2   | j d}ddd |D }d| j| j|f S )NrP   c             s   s   | ]}d | V  qdS )z    %sNr   ).0xr   r   r   	<genexpr>  s    z%ActionInfo.__str__.<locals>.<genexpr>zLine %s of file %s:
%s)rt   r^   r_   rj   rr   )r   Zsrclinesrt   r   r   r   __str__  s    zActionInfo.__str__N)r/   r0   r1   r6   rx   r   r   r   r   r     s   r   c                s,    fdd}t  dr"t|   |_|S )zWrapper to provide the right conflict info report data when a method
    that calls Configurator.action calls another that does the same.  Not a
    documented API but used by some external systems.c                s   | j d krg | _ |dd }|ddd }t|rHt|dkrHt| }|d kry<tjdd}t|d  }|jdkr||  t||   }W n" tk
r   td dd	d	}Y nX | j 	| z | f||}W d | j   X |S )
N_infoZ_backframesr         )limitextract_stackr   )
r   popr   rc   r   	tracebackr~   rs   rA   r:   )r   argr   r   Z
backframesfZ
last_framerq   )wrappedr   r   wrapper$  s(    

zaction_method.<locals>.wrapperr/   )hasattr	functoolsupdate_wrapperZ
__docobj__)r   r   r   )r   r   action_method  s
    
r   )N)Nr   Nr   Nr   r   )r   rY   rd   rB   r   Zzope.interfacer   Zpyramid.exceptionsr   r   r   Zpyramid.interfacesr   Zpyramid.registryr   Zpyramid.utilr   r	   r
   r)   r<   r>   rV   rp   r   r   r   r   r   r   <module>   s4     0
       
