B
    ؐ<[<                 @   s  d 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	 ddl
ZddlmZ ddlmZ ddlmZ yddlZW n   ddlZY nX yddlmZ W n   ddlmZ Y nX d	d
dddgZeeZG dd deZG dd deZG dd
 d
eZG dd dZG dd deZG dd deZyddl Z G dd	 d	eeZ!W n& e"k
rn   G dd	 d	eZ!Y nX G dd de!Z#dS )a  
Plugin Manager
--------------

A plugin manager class is used to load plugins, manage the list of
loaded plugins, and proxy calls to those plugins.

The plugin managers provided with nose are:

:class:`PluginManager`
    This manager doesn't implement loadPlugins, so it can only work
    with a static list of plugins.

:class:`BuiltinPluginManager`
    This manager loads plugins referenced in ``nose.plugins.builtin``.

:class:`EntryPointPluginManager`
    This manager uses setuptools entrypoints to load plugins.

:class:`ExtraPluginsPluginManager`
    This manager loads extra plugins specified with the keyword
    `addplugins`.

:class:`DefaultPluginMananger`
    This is the manager class that will be used by default. If
    setuptools is installed, it is a subclass of
    :class:`EntryPointPluginManager` and :class:`BuiltinPluginManager`;
    otherwise, an alias to :class:`BuiltinPluginManager`.

:class:`RestrictedPluginManager`
    This manager is for use in test runs where some plugin calls are
    not available, such as runs started with ``python setup.py test``,
    where the test runner is the default unittest :class:`TextTestRunner`. It
    is a subclass of :class:`DefaultPluginManager`.

Writing a plugin manager
========================

If you want to load plugins via some other means, you can write a
plugin manager and pass an instance of your plugin manager class when
instantiating the :class:`nose.config.Config` instance that you pass to
:class:`TestProgram` (or :func:`main` or :func:`run`).

To implement your plugin loading scheme, implement ``loadPlugins()``,
and in that method, call ``addPlugin()`` with an instance of each plugin
you wish to make available. Make sure to call
``super(self).loadPlugins()`` as well if have subclassed a manager
other than ``PluginManager``.

    N)chain)warn)Failure)IPluginInterface)	sort_list)StringIODefaultPluginManagerPluginManagerEntryPointPluginManagerBuiltinPluginManagerRestrictedPluginManagerc               @   sV   e Zd ZdZeZdd Zdd Zdd Zdd	 Z	d
d Z
dd Zdd ZdddZdS )PluginProxya#  Proxy for plugin calls. Essentially a closure bound to the
    given call and plugin list.

    The plugin proxy also must be bound to a particular plugin
    interface specification, so that it knows what calls are available
    and any special handling that is required for each call.
    c             C   sl   yt | j|| _W n( tk
r:   td|| jjf Y nX | || _g | _x|D ]}| || qTW d S )Nz%s is not a valid %s method)	getattr	interfacemethodAttributeError__name__makeCallcallplugins	addPlugin)selfr   r   p r   3lib/python3.7/site-packages/nose/plugins/manager.py__init__W   s    
zPluginProxy.__init__c             O   s   | j ||S )N)r   )r   argkwr   r   r   __call__b   s    zPluginProxy.__call__c                sV   t ||d}|dk	rR|dkrBtt|d dkrB|  fdd}| j||f dS )z`Add plugin to my list of plugins to call, if it has the attribute
        I'm bound to.
        NZloadTestsFromModuler      c                s    | S )Nr   )modulepathkwargs)	orig_methr   r   <lambda>n   s    z'PluginProxy.addPlugin.<locals>.<lambda>)r   leninspectZ
getargspecr   append)r   pluginr   methr   )r#   r   r   e   s    zPluginProxy.addPluginc                sH   |dkr j S  j}t|ddr, fddS t|ddr> jS  jS d S )NZloadTestsFromNames
generativeFc                 s   t  j| |S )N)listgenerate)r   r   )r   r   r   r$   {   s    z&PluginProxy.makeCall.<locals>.<lambda>Z	chainable)_loadTestsFromNamesr   r   r   simple)r   r   r)   r   )r   r   r   q   s    zPluginProxy.makeCallc             O   sZ   d}dd t t| jdg |D }x2| jD ](\}}|||}|dd }|| q*W |S )zCall plugins in a chain, where the result of each plugin call is
        sent to the next plugin as input. The final output result is returned.
        Nc             S   s   g | ]\}}|r|qS r   r   ).0staticar   r   r   
<listcomp>   s    z%PluginProxy.chain.<locals>.<listcomp>Zstatic_args)zipr   r   r   r'   )r   r   r   resultr0   r   r)   r   r   r   r      s    
zPluginProxy.chainc          
   o   s   xz| j D ]p\}}d}y*|||}|dk	r<x|D ]
}|V  q.W W q ttfk
rX    Y q   t }t| V  wY qX qW dS )zFCall all plugins, yielding each item in each non-None result.
        N)r   KeyboardInterrupt
SystemExitsysexc_infor   )r   r   r   r   r)   r4   rexcr   r   r   r,      s    


zPluginProxy.generatec             O   s.   x(| j D ]\}}|||}|dk	r|S qW dS )z?Call all plugins, returning the first non-None result.
        N)r   )r   r   r   r   r)   r4   r   r   r   r.      s    
zPluginProxy.simpleNc             C   sJ   g }x<| j D ]2\}}|||d}|dk	r|\}}|r|| qW ||fS )a
  Chainable but not quite normal. Plugins return a tuple of
        (tests, names) after processing the names. The tests are added
        to a suite that is accumulated throughout the full call, while
        names are input for the next plugin in the chain.
        )r    N)r   extend)r   namesr    Zsuiter   r)   r4   Z
suite_partr   r   r   r-      s    zPluginProxy._loadTestsFromNames)N)r   
__module____qualname____doc__r   r   r   r   r   r   r   r,   r.   r-   r   r   r   r   r   N   s   r   c               @   sd   e Zd ZdZe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S )	NoPluginsz(Null Plugin manager that has no plugins.c             C   s   d | _ | _d S )Nr   )_pluginsr   )r   r   r   r   r      s    zNoPlugins.__init__c             C   s   dS )Nr   r   )r   r   r   r   __iter__   s    zNoPlugins.__iter__c             O   s   d S )Nr   )r   argskwdsr   r   r   
_doNothing   s    zNoPlugins._doNothingc             O   s   dS )Nr   r   )r   rC   rD   r   r   r   _emptyIterator   s    zNoPlugins._emptyIteratorc             C   s(   t | j|}t |ddr| jS | jS d S )Nr*   F)r   r   rF   rE   )r   r   r   r   r   r   __getattr__   s    zNoPlugins.__getattr__c             C   s
   t  d S )N)NotImplementedError)r   plugr   r   r   r      s    zNoPlugins.addPluginc             C   s
   t  d S )N)rH   )r   r   r   r   r   
addPlugins   s    zNoPlugins.addPluginsc             C   s   d S )Nr   )r   optionsconfigr   r   r   	configure   s    zNoPlugins.configurec             C   s   d S )Nr   )r   r   r   r   loadPlugins   s    zNoPlugins.loadPluginsc             C   s   d S )Nr   )r   r   r   r   sort   s    zNoPlugins.sortN)r   r=   r>   r?   r   r   r   rB   rE   rF   rG   r   rJ   rM   rN   rO   r   r   r   r   r@      s   r@   c               @   sv   e Zd ZdZeZdddZdd Zdd	 Zd
d Z	dddZ
dd Zdd Zdd Zdd Zdd ZeeeddZdS )r	   a  Base class for plugin managers. PluginManager is intended to be
    used only with a static list of plugins. The loadPlugins() implementation
    only reloads plugins from _extraplugins to prevent those from being
    overridden by a subclass.

    The basic functionality of a plugin manager is to proxy all unknown
    attributes through a ``PluginProxy`` to a list of plugins.

    Note that the list of plugins *may not* be changed after the first plugin
    call.
    r   Nc             C   s2   g | _ d| _i | _|r | | |d k	r.|| _d S )Nr   )rA   _extraplugins_proxiesrJ   
proxyClass)r   r   rR   r   r   r   r      s    
zPluginManager.__init__c             C   s<   y
| j | S  tk
r6   | || j}|| j |< Y nX |S )N)rQ   KeyErrorrR   rA   )r   r   proxyr   r   r   rG      s    
zPluginManager.__getattr__c             C   s
   t | jS )N)iterr   )r   r   r   r   rB      s    zPluginManager.__iter__c                s<   t |dt   fdd| jD | jd d < | j| d S )Nnamec                s    g | ]}t |d d kr|qS )rV   N)r   )r/   r   )new_namer   r   r2     s    z+PluginManager.addPlugin.<locals>.<listcomp>)r   objectrA   r'   )r   rI   r   )rW   r   r     s    zPluginManager.addPluginc             C   s(   || _ xt||D ]}| | qW dS )zextraplugins are maintained in a separate list and
        re-added by loadPlugins() to prevent their being overwritten
        by plugins added by a subclass of PluginManager
        N)rP   	iterchainr   )r   r   ZextrapluginsrI   r   r   r   rJ     s    zPluginManager.addPluginsc             C   sT   t d || _td| j}||| dd | jD }|| _|   t d| dS )zConfigure the set of plugins with the given options
        and config instance. After configuration, disabled plugins
        are removed from the plugins list.
        zConfiguring pluginsrM   c             S   s   g | ]}|j r|qS r   )enabled)r/   rI   r   r   r   r2     s    z+PluginManager.configure.<locals>.<listcomp>zPlugins enabled: %sN)logdebugrL   r   rA   r   rO   )r   rK   rL   ZcfgrZ   r   r   r   rM     s    

zPluginManager.configurec             C   s   x| j D ]}| | qW d S )N)rP   r   )r   rI   r   r   r   rN   "  s    zPluginManager.loadPluginsc             C   s   t | jdd ddS )Nc             S   s   t | ddS )NZscore   )r   )xr   r   r   r$   '  s    z$PluginManager.sort.<locals>.<lambda>T)reverse)r   rA   )r   r   r   r   rO   &  s    zPluginManager.sortc             C   s   | j S )N)rA   )r   r   r   r   _get_plugins)  s    zPluginManager._get_pluginsc             C   s   g | _ | | d S )N)rA   rJ   )r   r   r   r   r   _set_plugins,  s    zPluginManager._set_pluginszPAccess the list of plugins managed by
                       this plugin manager)r   N)r   r   )r   r=   r>   r?   r   rR   r   rG   rB   r   rJ   rM   rN   rO   r`   ra   propertyr   r   r   r   r   r	      s   
	
	c               @   s^   e Zd ZdZdd Zejf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S )ZeroNinePluginz>Proxy for 0.9 plugins, adapts 0.10 calls to 0.9 standard.
    c             C   s
   || _ d S )N)r(   )r   r(   r   r   r   r   8  s    zZeroNinePlugin.__init__c             C   s   | j || d S )N)r(   Zadd_options)r   parserenvr   r   r   rK   ;  s    zZeroNinePlugin.optionsc       	      C   s   t | jdsd S ddlm}m} |\}}}t||rRt | jdsDd S | j|jS t||rzt | jdsld S | j|jS |j	}| j
|j||S )NaddErrorr   )SkipTestDeprecatedTestaddSkipaddDeprecated)hasattrr(   Znose.excrg   rh   
issubclassri   testrj   capturedOutputrf   )	r   rm   errrg   rh   ZecZevtbcaptr   r   r   rf   >  s    


zZeroNinePlugin.addErrorc             C   s   t | jdr| j|S d S )NloadTestsFromPath)rk   r(   rr   )r   filenamer   r   r   loadTestsFromFileP  s    z ZeroNinePlugin.loadTestsFromFilec             C   s0   t | jdsd S |j}|j}| j|j|||S )N
addFailure)rk   r(   rn   tbinforu   rm   )r   rm   ro   rq   rv   r   r   r   ru   T  s
    zZeroNinePlugin.addFailurec             C   s*   t | jdsd S |j}| j|j| d S )N
addSuccess)rk   r(   rn   rw   rm   )r   rm   rq   r   r   r   rw   \  s    zZeroNinePlugin.addSuccessc             C   s   t | jdsd S | j|jS )N	startTest)rk   r(   rx   rm   )r   rm   r   r   r   rx   b  s    zZeroNinePlugin.startTestc             C   s   t | jdsd S | j|jS )NstopTest)rk   r(   ry   rm   )r   rm   r   r   r   ry   g  s    zZeroNinePlugin.stopTestc             C   s   t | j|S )N)r   r(   )r   valr   r   r   rG   l  s    zZeroNinePlugin.__getattr__N)r   r=   r>   r?   r   osenvironrK   rf   rt   ru   rw   rx   ry   rG   r   r   r   r   rc   5  s   rc   c                   s,   e Zd ZdZddeffZ fddZ  ZS )r
   zhPlugin manager that loads plugins from the `nose.plugins` and
    `nose.plugins.0.10` entry points.
    )znose.plugins.0.10Nznose.pluginsc       	         s   ddl m} i }x| jD ]\}}x||D ]}|j|kr:q*d||j< td| jj| y| }W nJ t	k
rx    Y n6 t
k
r } ztd||f t w*W dd}~X Y nX |r|| }n| }| | q*W qW tt|   dS )zBLoad plugins by iterating the `nose.plugins` entry point.
        r   )iter_entry_pointsTz%s load plugin %szUnable to load plugin %s: %sN)pkg_resourcesr}   entry_pointsrV   r[   r\   	__class__r   loadr5   	Exceptionr   RuntimeWarningr   superr
   rN   )	r   r}   ZloadedZentry_pointZadaptZepZplugclserI   )r   r   r   rN   w  s*    

z#EntryPointPluginManager.loadPlugins)r   r=   r>   r?   rc   r   rN   __classcell__r   r   )r   r   r
   p  s   
c                   s    e Zd ZdZ fddZ  ZS )r   zSPlugin manager that loads plugins from the list in
    `nose.plugins.builtin`.
    c                s:   ddl m} x|jD ]}| |  qW tt|   dS )z-Load plugins in nose.plugins.builtin
        r   )builtinN)Znose.pluginsr   r   r   r   r   rN   )r   r   rI   )r   r   r   rN     s    z BuiltinPluginManager.loadPlugins)r   r=   r>   r?   rN   r   r   r   )r   r   r     s   c               @   s   e Zd ZdS )r   N)r   r=   r>   r   r   r   r   r     s   c               @   s   e Zd ZdS )r   N)r   r=   r>   r   r   r   r   r     s   c               @   s*   e Zd ZdZdddZdd Zdd	 Zd
S )r   zPlugin manager that restricts the plugin list to those not
    excluded by a list of exclude methods. Any plugin that implements
    an excluded method will be removed from the manager's plugin list
    after plugins are loaded.
    r   Tc             C   s(   t | | || _|| _g | _d | _d S )N)r   r   r   excludeexcluded_excludedOpts)r   r   r   r   r   r   r   r     s
    z RestrictedPluginManager.__init__c             C   sR   | j d krBddlm} |dd| _ x| jD ]}|j| j i d q*W | j d| S )Nr   )OptionParserF)Zadd_help_option)re   z--)r   Zoptparser   r   rK   Z
get_option)r   rV   r   r(   r   r   r   excludedOption  s    
z&RestrictedPluginManager.excludedOptionc             C   sl   | j rt|  g }xL| jD ]B}d}x*| jD ] }t||r,d}| j| P q,W |r|| qW || _d S )NTF)r   r   rN   r   r   rk   r   r'   )r   Zallowr(   okr   r   r   r   rN     s    

z#RestrictedPluginManager.loadPluginsN)r   r   T)r   r=   r>   r?   r   r   rN   r   r   r   r   r     s   
)$r?   r&   Zloggingr{   r7   	itertoolsr   rY   warningsr   Znose.configZnoseZnose.failurer   Znose.plugins.baser   Znose.pyversionr   pickleior   __all__Z	getLoggerr   r[   rX   r   r@   r	   rc   r
   r   r~   r   ImportErrorr   r   r   r   r   <module>2   sB   
m&T;%