U
    Ha<                     @   s   d dl Z d dlZddlmZ ddlmZ ddlmZmZm	Z	m
Z
 d dlZejdkr`d dlmZ nd dlZdd	 ZG d
d deZG dd deZG dd deZee drdd Zndd ZdS )    N   )_tracing)_Result)HookImpl
_HookRelay_HookCallernormalize_hookimpl_opts)      metadatac                 C   s"   t j| t| |jj|jjd d S )N)linenofilename)warningswarn_explicittype__code__co_firstlinenoco_filename)warningfunction r   2/tmp/pip-unpacked-wheel-xuf3ljf8/pluggy/manager.py_warn_for_function   s    r   c                       s    e Zd ZdZ fddZ  ZS )PluginValidationErrorz plugin failed validation.

    :param object plugin: the plugin which failed validation,
        may be a module or an arbitrary object.
    c                    s   || _ tt| | d S N)pluginsuper	Exception__init__)selfr   message	__class__r   r   r      s    zPluginValidationError.__init__)__name__
__module____qualname____doc__r   __classcell__r   r   r"   r   r      s   r   c                   @   s6   e Zd ZdZdd Zedd ZdddZd	d
 ZdS )
DistFacadez$Emulate a pkg_resources Distributionc                 C   s
   || _ d S r   )_dist)r    distr   r   r   r   &   s    zDistFacade.__init__c                 C   s
   | j d S )Nnamer   r    r   r   r   project_name)   s    zDistFacade.project_nameNc                 C   s   t | j||S r   )getattrr*   )r    attrdefaultr   r   r   __getattr__-   s    zDistFacade.__getattr__c                 C   s   t t| jddg S )Nr*   r.   )sorteddirr*   r-   r   r   r   __dir__0   s    zDistFacade.__dir__)N)	r$   r%   r&   r'   r   propertyr.   r2   r5   r   r   r   r   r)   #   s   

r)   c                   @   s   e Zd ZdZd3ddZdd Zd4ddZd	d
 Zd5d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d6d%d&Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 ZdS )7PluginManagera   Core :py:class:`.PluginManager` class which manages registration
    of plugin objects and 1:N hook calling.

    You can register new hooks by calling :py:meth:`add_hookspecs(module_or_class)
    <.PluginManager.add_hookspecs>`.
    You can register plugin objects (which contain hooks) by calling
    :py:meth:`register(plugin) <.PluginManager.register>`.  The :py:class:`.PluginManager`
    is initialized with a prefix that is searched for in the names of the dict
    of registered plugin objects.

    For debugging purposes you can call :py:meth:`.PluginManager.enable_tracing`
    which will subsequently send debug information to the trace helper.
    Nc                 C   s\   || _ i | _i | _g | _t d| _t | _	|dk	rHt
jdtdd || _dd | _dS )zyIf ``implprefix`` is given implementation functions
        will be recognized if their name matches the ``implprefix``. ZpluginmanageNzySupport for the `implprefix` arg is now deprecated and will be removed in an upcoming release. Please use HookimplMarker.   )
stacklevelc                 S   s$   | j ||| jr| jjdnddS )NfirstresultF)r:   )	multicallspecoptsget)hookmethodskwargsr   r   r   <lambda>T   s   z(PluginManager.__init__.<locals>.<lambda>)r.   _name2plugin_plugin2hookcallers_plugin_distinfor   Z	TagTracerr>   tracer   r?   r   warnDeprecationWarning_implprefix_inner_hookexec)r    r.   Z
implprefixr   r   r   r   C   s    zPluginManager.__init__c                 C   s   |  |||S r   rJ   )r    r?   r@   rA   r   r   r   	_hookexecZ   s    zPluginManager._hookexecc           	      C   s  |p|  |}|| jks"|| jkrL| j|ddkr8dS td||| jf || j|< g  | j|< }t|D ]}| ||}|dk	rlt| t||}t	||||}t| j
|d}|dkrt|| j}t| j
|| n| r| || || || || ql|S )z Register a plugin and return its canonical name or ``None`` if the name
        is blocked from registering.  Raise a :py:class:`ValueError` if the plugin
        is already registered. Nz#Plugin already registered: %s=%s
%s)get_canonical_namerC   rD   r>   
ValueErrorr4   parse_hookimpl_optsr   r/   r   r?   r   rL   setattrhas_spec_verify_hookZ_maybe_apply_history_add_hookimplappend)	r    r   r,   plugin_nameZhookcallersZhookimpl_optsmethodhookimplr?   r   r   r   register_   s6    




zPluginManager.registerc                 C   s   t ||}t|sd S zt || jd d }W n tk
rF   i }Y nX |d k	r`t|ts`d }n,|d kr| jr|| jrt	t
d| i }|S )N_implzhThe `implprefix` system is deprecated please decorate this function using an instance of HookimplMarker.)r/   inspect	isroutiner.   r   
isinstancedictrI   
startswithr   rH   )r    r   r,   rW   resr   r   r   rP      s$    


z!PluginManager.parse_hookimpl_optsc                 C   sj   |dkr"|dk	st d| |}|dkr4| |}| j|rH| j|= | j|g D ]}|| qV|S )zn unregister a plugin object and all its contained hook implementations
        from internal data structures. Nz+one of name or plugin needs to be specified)AssertionErrorget_name
get_pluginrC   r>   rD   popZ_remove_plugin)r    r   r,   Z
hookcallerr   r   r   
unregister   s    

zPluginManager.unregisterc                 C   s   | j |d d| j|< dS )zJ block registrations of the given name, unregister if already registered. r,   N)re   rC   r    r,   r   r   r   set_blocked   s    zPluginManager.set_blockedc                 C   s   || j ko| j | dkS )z6 return ``True`` if the given plugin name is blocked. N)rC   rg   r   r   r   
is_blocked   s    zPluginManager.is_blockedc                 C   s   g }t |D ]~}| ||}|dk	rt| j|d}|dkrZt|| j||}t| j|| n&||| | D ]}| 	|| qn|
| q|std| j|f dS )z add new hook specifications defined in the given ``module_or_class``.
        Functions are recognized if they have been decorated accordingly. Nzdid not find any %r hooks in %r)r4   parse_hookspec_optsr/   r?   r   rL   rQ   Zset_specificationget_hookimplsrS   rU   rO   r.   )r    module_or_classnamesr,   Z	spec_optshcZhookfunctionr   r   r   add_hookspecs   s     zPluginManager.add_hookspecsc                 C   s   t ||}t || jd d S )N_spec)r/   r.   )r    rl   r,   rW   r   r   r   rj      s    
z!PluginManager.parse_hookspec_optsc                 C   s
   t | jS )z' return the set of registered plugins. )setrD   r-   r   r   r   get_plugins   s    zPluginManager.get_pluginsc                 C   s
   || j kS )z6 Return ``True`` if the plugin is already registered. )rD   r    r   r   r   r   is_registered   s    zPluginManager.is_registeredc                 C   s   t |ddptt|S )aW   Return canonical name for a plugin object. Note that a plugin
        may be registered under a different name which was specified
        by the caller of :py:meth:`register(plugin, name) <.PluginManager.register>`.
        To obtain the name of an registered plugin use :py:meth:`get_name(plugin)
        <.PluginManager.get_name>` instead.r$   N)r/   stridrs   r   r   r   rN      s    z PluginManager.get_canonical_namec                 C   s   | j |S )z1 Return a plugin or ``None`` for the given name. )rC   r>   rg   r   r   r   rc      s    zPluginManager.get_pluginc                 C   s   |  |dk	S )z@ Return ``True`` if a plugin with the given name is registered. N)rc   rg   r   r   r   
has_plugin   s    zPluginManager.has_pluginc                 C   s(   | j  D ]\}}||kr
|  S q
dS )zB Return name for registered plugin or ``None`` if not registered. N)rC   items)r    r   r,   valr   r   r   rb      s    zPluginManager.get_namec                 C   s~   |  r&|jr&t|jd|j|jf |jjr>t|jj|j	 t
|jt
|jj }|rzt|jd|j|jt|j	|f d S )Nz6Plugin %r
hook %r
historic incompatible to hookwrapperz~Plugin %r for hook %r
hookimpl definition: %s
Argument(s) %s are declared in the hookimpl but can not be found in the hookspec)Zis_historicZhookwrapperr   r   rV   r,   r<   Zwarn_on_implr   r   rq   argnames
_formatdef)r    r?   rX   Z	notinspecr   r   r   rS      s*    
zPluginManager._verify_hookc                 C   s\   | j jD ]N}|d dkrt| j |}| s| D ] }|js4t|jd||jf q4qdS )z Verify that all hooks which have not been verified against
        a hook specification are optional, otherwise raise :py:class:`.PluginValidationError`.r   _zunknown hook %r in plugin %rN)r?   __dict__r/   rR   rk   Zoptionalhookr   r   )r    r,   r?   rX   r   r   r   check_pending	  s    zPluginManager.check_pendingc                 C   s   d}t  D ]z}|jD ]n}|j|ks|dk	r6|j|ks| |js| |jrPq| }| j||jd | j	
|t|f |d7 }qq|S )a+   Load modules from querying the specified setuptools ``group``.

        :param str group: entry point group to load plugins
        :param str name: if given, loads only plugins with the given ``name``.
        :rtype: int
        :return: return the number of loaded plugins by this call.
        r   Nrf   r   )importlib_metadatadistributionsentry_pointsgroupr,   rc   ri   loadrY   rE   rU   r)   )r    r   r,   countr+   epr   r   r   r   load_setuptools_entrypoints  s&    


z)PluginManager.load_setuptools_entrypointsc                 C   s
   t | jS )zV return list of distinfo/plugin tuples for all setuptools registered
        plugins. )listrE   r-   r   r   r   list_plugin_distinfo1  s    z"PluginManager.list_plugin_distinfoc                 C   s   t | j S )z# return list of name/plugin pairs. )r   rC   rx   r-   r   r   r   list_name_plugin6  s    zPluginManager.list_name_pluginc                 C   s   | j |S )z0 get all hook callers for the specified plugin. )rD   r>   rs   r   r   r   get_hookcallers:  s    zPluginManager.get_hookcallersc                    s.   j  fdd}|_ fdd}|S )aP   add before/after tracing functions for all hooks
        and return an undo function which, when called,
        will remove the added tracers.

        ``before(hook_name, hook_impls, kwargs)`` will be called ahead
        of all hook calls and receive a hookcaller instance, a list
        of HookImpl instances and the keyword arguments for the hook call.

        ``after(outcome, hook_name, hook_impls, kwargs)`` receives the
        same arguments as ``before`` but also a :py:class:`pluggy.callers._Result` object
        which represents the result of the overall hook call.
        c                    s>    j  t fdd}| j  | S )Nc                      s    S r   r   r   )r?   
hook_implsrA   oldcallr   r   rB   O      zPPluginManager.add_hookcall_monitoring.<locals>.traced_hookexec.<locals>.<lambda>)r,   r   Z	from_call
get_result)r?   r   rA   outcome)afterbeforer   )r?   r   rA   r   traced_hookexecM  s    z>PluginManager.add_hookcall_monitoring.<locals>.traced_hookexecc                      s
    _ d S r   rK   r   )r   r    r   r   undoU  s    z3PluginManager.add_hookcall_monitoring.<locals>.undorK   )r    r   r   r   r   r   )r   r   r   r    r   add_hookcall_monitoring>  s
    z%PluginManager.add_hookcall_monitoringc                    s2   | j jd  fdd} fdd}| ||S )z; enable tracing of hook calls and return an undo function. r?   c                    s    j  jd7  _ | | d S )Nr   )rootindent)	hook_namer@   rA   Z	hooktracer   r   r   ^  s    z,PluginManager.enable_tracing.<locals>.beforec                    s0   | j d kr d|d|    j jd8  _d S )Nfinishz-->r   )excinfor   r   r   )r   r   r@   rA   r   r   r   r   b  s    
z+PluginManager.enable_tracing.<locals>.after)rF   r   r>   r   )r    r   r   r   r   r   enable_tracingZ  s    zPluginManager.enable_tracingc                    s~   t | j } fdd|D }|rzt|j|j|jj|jj}| D ]0}|j	}||krD|
| | j|g | qD|S |S )z Return a new :py:class:`.hooks._HookCaller` instance for the named method
        which manages calls to all registered plugins except the
        ones from remove_plugins. c                    s   g | ]}t | r|qS r   )hasattr).0Zplugrf   r   r   
<listcomp>n  s     
 z4PluginManager.subset_hook_caller.<locals>.<listcomp>)r/   r?   r   r,   rL   r<   	namespacer=   rk   r   rT   rD   
setdefaultrU   )r    r,   Zremove_pluginsorigZplugins_to_removern   rX   r   r   rf   r   subset_hook_calleri  s        
z PluginManager.subset_hook_caller)N)N)NN)N)r$   r%   r&   r'   r   rL   rY   rP   re   rh   ri   ro   rj   rr   rt   rN   rc   rw   rb   rS   r~   r   r   r   r   r   r   r   r   r   r   r   r7   4   s2   

%

r7   	signaturec                 C   s   d| j tt| f S Nz%s%s)r$   ru   r[   r   funcr   r   r   r{     s    r{   c                 C   s   d| j tjt|  f S r   )r$   r[   formatargspec
getargspecr   r   r   r   r{     s    )r[   sys r   callersr   hooksr   r   r   r   r   version_info	importlibr   r   r   r   r   objectr)   r7   r   r{   r   r   r   r   <module>   s"   
	  L

