o
    >hh                     @  sP  d Z ddlmZ ddlZ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 ddlmZmZmZ ddlm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mZ edZG dd deZ G dd deZ!G dd dej"Z#dZ$d*ddZ%d+d d!Z&G d"d# d#eZ'G d$d% d%ej"Z(G d&d' d'ej"Z)G d(d) d)ej"Z*dS ),z"
Tests for Twisted plugin system.
    )annotationsN)invalidate_caches)
ModuleType)Callable	TypedDictTypeVar)	Interface)plugin)FilePath)	EventDictaddObserverremoveObservertextFromEventDict)unittest_Tc                   @     e Zd ZdZdS )ITestPluginzS
    A plugin for use by the plugin system's unit tests.

    Do not use this.
    N__name__
__module____qualname____doc__ r   r   x/var/www/vedio/testing/chatpythonscript.ninositsolution.com/env/lib/python3.10/site-packages/twisted/test/test_plugin.pyr          r   c                   @  r   )ITestPlugin2z
    See L{ITestPlugin}.
    Nr   r   r   r   r   r   &   r   r   c                   @  s   e Zd ZdZd)ddZd)ddZ	d*d+ddZd)ddZd,ddZed)ddZ	d)ddZ
ed)ddZed)ddZed)ddZed)d d!Zed)d"d#Zed)d$d%Zd)d&d'Zd(S )-PluginTestsz_
    Tests which verify the behavior of the current, active Twisted plugins
    directory.
    returnNonec                 C  s   t jdd | _t j | _t|  | _| j	  | j
d| _| j	  | j
dd ttd| j
d d| _t jd| jj ddl}|| _dS )	zV
        Save C{sys.path} and C{sys.modules}, and create a package for tests.
        N	mypackage__init__.py    zplugin_basic.pyztestplugin.py
testpluginr   )syspathoriginalPathmodulescopysavedModulesr
   mktemprootcreateDirectorychildpackage
setContent__file__siblingcopyTooriginalPlugininsertr   module)selfr   r   r   r   setUp2   s   



zPluginTests.setUpc                 C  ,   | j tjdd< tj  tj| j dS zR
        Restore C{sys.path} and C{sys.modules} to their original values.
        Nr%   r#   r$   r&   clearupdater(   r5   r   r   r   tearDownJ      
zPluginTests.tearDownFr4   r   deleteSourceboolc              	   C  s   |j d usJ |jd}d|d d }|d }ttj| | tj|j= ddg|r/dgp0g  D ]}z
t|j |  W q2 t	yG   Y q2w d S )N.co )
r/   r   splitjoindelattrr#   r&   osremoveFileNotFoundError)r5   r4   r?   
modulePathpackageName
moduleNameextr   r   r   _unimportPythonModuleR   s   
z!PluginTests._unimportPythonModulec                 C  s   | j d  dS )z;
        Remove the plugins B{droping.cache} file.
        dropin.cacheN)r-   r,   rJ   r<   r   r   r   _clearCacheb      zPluginTests._clearCachemethCallable[[PluginTests], object]Callable[[PluginTests], None]c                   s   t  d fdd}|S )	z
        This is a paranoid test wrapper, that calls C{meth} 2 times, clear the
        cache, and calls it 2 other times. It's supposed to ensure that the
        plugin system behaves correctly no matter what the state of the cache
        is.
        r5   r   r   r   c                   s,    |   |  |     |   |  d S )N)rR   r<   rT   r   r   wrappedr   s
   z+PluginTests._withCacheness.<locals>.wrappedN)r5   r   r   r   )	functoolswraps)rT   rX   r   rW   r   _withCachenessh   s   
zPluginTests._withCachenessc                 C  s   t | j}|| j }| |jd| j  | d|j dd |jD d }| 	|j
| | |jd | |j d | |jtt jg | }| 	|tjd| j  j ddlm} | 	||j dS )	a	  
        Check that the cache returned by L{plugin.getCache} hold the plugin
        B{testplugin}, and that this plugin has the properties we expect:
        provide L{TestPlugin}, has the good name and description, and can be
        loaded successfully.
        z
mypackage.zI'm a test drop-in.c                 S  s   g | ]	}t |jv r|qS r   )r   provided.0pr   r   r   
<listcomp>   s    z*PluginTests.test_cache.<locals>.<listcomp>r   
TestPluginz*A plugin used solely for testing purposes.N)r	   getCacher4   r2   assertEqualrN   assertIndescriptionpluginsassertIsdropinnamestripr\   r   IPluginloadr#   r&   ra   mypackage.testpluginr"   )r5   cacherh   p1
realPlugintpr   r   r   
test_cache|   s$   

zPluginTests.test_cachec                 C  s>   t | j| j }tdd |jD d }| t|d dS )zm
        L{CachedPlugin} has a helpful C{repr} which contains relevant
        information about it.
        c                 s  s    | ]
}|j d kr|V  qdS )ra   Nri   r]   r   r   r   	<genexpr>   s    z-PluginTests.test_cacheRepr.<locals>.<genexpr>r   zT<CachedPlugin 'TestPlugin'/'mypackage.testplugin' (provides 'ITestPlugin, IPlugin')>N)r	   rb   r4   r2   listrf   rc   repr)r5   cachedDropincachedPluginr   r   r   test_cacheRepr   s   zPluginTests.test_cacheReprc                 C  sL   t tt| j}| t|d ddg}|D ]}||j |	  qdS )a  
        L{plugin.getPlugins} should return the list of plugins matching the
        specified interface (here, L{ITestPlugin2}), and these plugins
        should be instances of classes with a C{test} method, to be sure
        L{plugin.getPlugins} load classes correctly.
           AnotherTestPluginThirdTestPluginN)
ru   r	   
getPluginsr   r4   rc   lenrJ   r   test)r5   rf   namesr_   r   r   r   test_plugins   s   
zPluginTests.test_pluginsc              
   C  s   t td| jd zC| dtj | 	t
tjd dd ttt| j}| t|d dd	g}|D ]}||j |  q9W | tjd d
 dS | tjd d
 w )ze
        Check that L{plugin.getPlugins} is able to detect plugins added at
        runtime.
        plugin_extra1.pypluginextra.pymypackage.pluginextrar   pluginextraz&mypackage still has pluginextra modulerz   ra   FourthTestPluginTN)r
   r/   r0   r1   r-   r,   failIfInr#   r&   assertFalsehasattrru   r	   r}   r   r4   rc   r~   rJ   r   test1rP   r5   plgsr   r_   r   r   r   test_detectNewFiles   s"   

*zPluginTests.test_detectNewFilesc              
   C  s   t td| jd zWttt	| j
}| t|d t td| jd | tjd  ttt	| j
}| t|d g d}|D ]}||j |  qMW | tjd d d	S | tjd d w )
z
        Check that if the content of a plugin change, L{plugin.getPlugins} is
        able to detect the new plugins added.
        r   r   rz   zplugin_extra2.pyr      )ra   r   FifthTestPluginTN)r
   r/   r0   r1   r-   r,   ru   r	   r}   r   r4   rc   r~   rP   r#   r&   rJ   r   r   r   r   r   r   test_detectFilesChanged   s$   


*z#PluginTests.test_detectFilesChangedc              
   C  s   t td| jd zttt	| j
 W | tjd d n
| tjd d w ttt	| j
}| dt| dS )zs
        Check that when a dropin file is removed, L{plugin.getPlugins} doesn't
        return it anymore.
        r   r   r   T   N)r
   r/   r0   r1   r-   r,   ru   r	   r}   r   r4   rP   r#   r&   rc   r~   )r5   r   r   r   r   test_detectFilesRemoved   s   
(z#PluginTests.test_detectFilesRemovedc              	   C  sp   |   }| tj| | jj| ztt	
t| j}| t|d W | jj| dS | jj| w )zy
        Test that getCache skips over any entries in a plugin package's
        C{__path__} which do not exist.
        r   N)r)   r   rI   r$   existsr4   __path__appendru   r	   r}   r   rc   r~   rJ   )r5   r$   r   r   r   r   test_nonexistentPathEntry  s   "z%PluginTests.test_nonexistentPathEntryc              	   C  s   t |  }| |  |  |dj}| jj	| zt
tt| j}| t|d W | jj| dS | jj| w )z
        Test that getCache skips over any entries in a plugin package's
        C{__path__} which refer to children of paths which are not directories.
        test_packager   N)r
   r)   r   r   touchr,   r$   r4   r   r   ru   r	   r}   r   rc   r~   rJ   )r5   r$   r,   r   r   r   r   test_nonDirectoryChildEntry"  s   "z'PluginTests.test_nonDirectoryChildEntryc                 C  s  t | j | jd}ttd| jd t	  t
| jjd t
|jd | t
j| jjd | t
j|jd g }t|j | t|j t | j}| d| | | j| d|jtjf }|D ]}t|}|d	usvJ ||v r} d	S qj| d
|f  d	S )z
        The C{dropin.cache} file may not be writable: the cache should still be
        attainable, but an error should be logged to show that the cache
        couldn't be updated.
        rQ   r   r   i@     i  r   3Unable to write to plugin cache %s: error number %dN;Did not observe unwriteable cache warning in log events: %r)r	   rb   r4   r-   r,   r
   r/   r0   r1   invalidateImportCachesrI   chmodr$   
addCleanupr   r   r   rd   r2   errnoEPERMr   fail)r5   	cachepatheventsrn   expectedevent	maybeTextr   r   r   test_deployedMode3  s>   

zPluginTests.test_deployedModeNr   r   )F)r4   r   r?   r@   r   r   )rT   rU   r   rV   )r   r   r   r   r6   r=   rP   rR   r[   rr   ry   r   r   r   r   r   r   r   r   r   r   r   r   ,   s0    

	


$ r   sj   
from twisted.plugin import pluginPackagePaths
__path__.extend(pluginPackagePaths(__name__))
__all__ = []
ri   strr   bytesc                 C  s   d | dS )Nzfrom zope.interface import provider
from twisted.plugin import IPlugin
from twisted.test.test_plugin import ITestPlugin

@provider(IPlugin, ITestPlugin)
class {}:
    pass
ascii)formatencoders   r   r   r   pluginFileContentsm  s   r   	entrypathFilePath[str]pluginContentrealr@   pluginModulec                 C  sl   |    | d}|   |r|dd |d}|   |r*|dt ||d | |S )z'
    Create a plugindummy package.
    plugindummyr    r!   rf   .py)r+   r,   r.   pluginInitFile)r   r   r   r   pkgplugsr   r   r   _createPluginDummy}  s   

r   c                   @  s   e Zd ZU ded< dS )_HasBoolLegacyKeyr@   legacyN)r   r   r   __annotations__r   r   r   r   r     s   
 r   c                   @  st   e Zd ZdZdddZdddZddd	ZdddZdddZdddZ	dddZ
dddZdddZdddZdS )DeveloperSetupTestsz
    These tests verify things about the plugin system without actually
    interacting with the deployed 'twisted.plugins' package, instead creating a
    temporary package.
    r   r   c                 C  s>  t jdd | _t j | _t|  | _| j	  | j
d| _| j
d| _| j
d| _t| jtddd| _t| jtddd| _t| jtd	d
d| _t jdd | j| jfD  |   | j
d
d| _| j
d| _t }t| j
dj|d fd  t| jj|d fd  |   |   dS )a7  
        Create a complex environment with multiple entries on sys.path, akin to
        a developer's environment who has a development (trunk) checkout of
        Twisted, a system installed version of Twisted (for their operating
        system's tools) and a project which provides Twisted plugins.
        Nsystem_pathdevelopment_pathapplication_pathsystemTplugindummy_builtindevappFplugindummy_appc                 S     g | ]}|j qS r   r$   r^   xr   r   r   r`         z-DeveloperSetupTests.setUp.<locals>.<listcomp>r   rf   rQ   zplugindummy_builtin.pyi  rz   i  )r#   r$   	savedPathr&   r'   r(   r
   r)   fakeRootr+   r,   
systemPathdevPathappPathr   r   systemPackage
devPackage
appPackageextendgetAllPluginssysplugsyscachetimerI   utime
lockSystemresetEnvironment)r5   nowr   r   r   r6     s2   
 zDeveloperSetupTests.setUpc                 C  $   t | jjd t | jjd dS )zW
        Lock the system directories, as if they were unwritable by this user.
        im  NrI   r   r   r$   r   r<   r   r   r   r        zDeveloperSetupTests.lockSystemc                 C  r   )zW
        Unlock the system directories, as if they were writable by this user.
        i  Nr   r<   r   r   r   unlockSystem  r   z DeveloperSetupTests.unlockSystem	list[str]c                 C  s(   ddl }ttt|j}dd |D S )zl
        Get all the plugins loadable from our dummy package, and return their
        short names.
        r   Nc                 S  r   r   r   )r^   plugr   r   r   r`     r   z5DeveloperSetupTests.getAllPlugins.<locals>.<listcomp>)plugindummy.pluginsru   r	   r}   r   rf   )r5   r   r   r   r   r   r     s   z!DeveloperSetupTests.getAllPluginsc                 C  s.   |    tjdd | j| j| jfD  dS )zc
        Change the environment to what it should be just as the test is
        starting.
        c                 S  r   r   r   r   r   r   r   r`     r   z8DeveloperSetupTests.resetEnvironment.<locals>.<listcomp>N)unsetEnvironmentr#   r$   r   r   r   r   r<   r   r   r   r     s   &z$DeveloperSetupTests.resetEnvironmentc                 C  s2   t   tj  tj| j | jtjdd< dS )zh
        Change the Python environment back to what it was before the test was
        started.
        N)r   r#   r&   r:   r;   r(   r   r$   r<   r   r   r   r     s   
z$DeveloperSetupTests.unsetEnvironmentc                 C  s   |    |   dS )z
        Reset the Python environment to what it was before this test ran, and
        restore permissions on files which were marked read-only so that the
        directory may be cleanly cleaned up.
        N)r   r   r<   r   r   r   r=     s   zDeveloperSetupTests.tearDownc                 C  s2   t dD ]}|  }|  | |ddg qdS )a  
        Plugins added in the development path should be loadable, even when
        the (now non-importable) system path contains its own idea of the
        list of plugins for a package.  Inversely, plugins added in the
        system path should not be available.
        r   r   r   N)ranger   sortrc   )r5   r   r   r   r   r   "test_developmentPluginAvailability  s
   	z6DeveloperSetupTests.test_developmentPluginAvailabilityc                 C  s   | j d}|td t d }t|j||f |d}t	dd}t
j| j jfddi| t|j||f |  |   | d|   | d	|   |   |td	 | d|   | d	|   d
S )z
        Verify that if a stale .pyc file on the PYTHONPATH is replaced by a
        fresh .py file, the plugins in the new .py are picked up rather than
        the stale .pyc, even if the .pyc is still around.
        zstale.pyonei  z	stale.pycT)r   quietr   twoN)r   r,   r.   r   r   rI   r   r$   r0   r   
compileallcompile_dirrJ   r   rd   r   r   )r5   mypathr   pycextrar   r   r   test_freshPyReplacesStalePyc  s    

z0DeveloperSetupTests.test_freshPyReplacesStalePycc                 C  s   |    | jdtd |   tj| j	j g }t
|j | t|j | d|   d| jjtjf }|D ]}t|}|dusHJ ||v rO dS q<| d|f  dS )aF  
        Verify that a failure to write the dropin.cache file on a read-only
        path will not affect the list of plugins returned.

        Note: this test should pass on both Linux and Windows, but may not
        provide useful coverage on Windows due to the different meaning of
        "read-only directory".
        znewstuff.pyr   r   Nr   )r   r   r,   r.   r   r   r#   r$   rJ   r   r   r   r   r   rd   r   r   r   r   r   r   )r5   r   r   r   r   r   r   r   test_newPluginsOnReadOnlyPath,  s.   	
z1DeveloperSetupTests.test_newPluginsOnReadOnlyPathNr   )r   r   )r   r   r   r   r6   r   r   r   r   r   r=   r   r   r   r   r   r   r   r     s    

*







 r   c                   @  sB   e Zd ZdZdddZdddZdddZdddZdddZdS )AdjacentPackageTestsz
    Tests for the behavior of the plugin system when there are multiple
    installed copies of the package containing the plugins being loaded.
    r   r   c                 C  s    t jdd | _t j | _dS )zS
        Save the elements of C{sys.path} and the items of C{sys.modules}.
        N)r#   r$   r%   r&   r'   r(   r<   r   r   r   r6   [  s   zAdjacentPackageTests.setUpc                 C  r7   r8   r9   r<   r   r   r   r=   b  r>   zAdjacentPackageTests.tearDownr*   r   ri   r   
pluginNamec                 C  sn   | |}| d}|  | dd | d}|  | dt | |d }|t| |S )a`  
        Create a directory containing a Python package named I{dummy} with a
        I{plugins} subpackage.

        @type root: L{FilePath}
        @param root: The directory in which to create the hierarchy.

        @type name: C{str}
        @param name: The name of the directory to create which will contain
            the package.

        @type pluginName: C{str}
        @param pluginName: The name of a module to create in the
            I{dummy.plugins} package.

        @rtype: L{FilePath}
        @return: The directory which was created to contain the I{dummy}
            package.
        dummyr    r!   rf   r   )r,   makedirsr.   r   r   )r5   r*   ri   r   	directoryr-   rf   r   r   r   r   createDummyPackagej  s   


z'AdjacentPackageTests.createDummyPackagec                 C  s   t |  }|  | |dd}| |dd}tj|j tj|j ddl}tt	
t|j}| dgdd |D  dS )z
        Only plugins from the first package in sys.path should be returned by
        getPlugins in the case where there are two Python packages by the same
        name installed, each with a plugin module by a single name.
        first
somepluginsecondr   Nc                 S  r   r   r   r]   r   r   r   r`     r   zWAdjacentPackageTests.test_hiddenPackageSamePluginModuleNameObscured.<locals>.<listcomp>r
   r)   r   r   r#   r$   r   dummy.pluginsru   r	   r}   r   rf   rc   r5   r*   firstDirectorysecondDirectoryr   rf   r   r   r   .test_hiddenPackageSamePluginModuleNameObscured     zCAdjacentPackageTests.test_hiddenPackageSamePluginModuleNameObscuredc                 C  s   t |  }|  | |dd}| |dd}tj|j tj|j ddl}tt	
t|j}| dgdd |D  dS )	z
        Plugins from the first package in sys.path should be returned by
        getPlugins in the case where there are two Python packages by the same
        name installed, each with a plugin module by a different name.
        r   
thispluginr   
thatpluginr   Nc                 S  r   r   r   r]   r   r   r   r`     r   z\AdjacentPackageTests.test_hiddenPackageDifferentPluginModuleNameObscured.<locals>.<listcomp>r   r   r   r   r   3test_hiddenPackageDifferentPluginModuleNameObscured  r  zHAdjacentPackageTests.test_hiddenPackageDifferentPluginModuleNameObscuredNr   )r*   r   ri   r   r   r   r   r   )	r   r   r   r   r6   r=   r   r  r  r   r   r   r   r   U  s    



!r   c                   @  s8   e Zd ZdZdddZdddZddd	Zdd
dZdS )PackagePathTestszg
    Tests for L{plugin.pluginPackagePaths} which constructs search paths for
    plugin packages.
    r   r   c                 C  s   t jdd | _dS )z3
        Save the elements of C{sys.path}.
        N)r#   r$   r%   r<   r   r   r   r6     rS   zPackagePathTests.setUpc                 C  s   | j tjdd< dS )z<
        Restore C{sys.path} to its original value.
        N)r%   r#   r$   r<   r   r   r   r=     rS   zPackagePathTests.tearDownc                 C  sT   t d}t d}|j|jgt_| td|ddj|ddjg dS )z
        L{plugin.pluginPackagePaths} should return a list containing each
        directory in C{sys.path} with a suffix based on the supplied package
        name.
        foobardummy.pluginsr   rf   N)r
   r$   r#   rc   r	   pluginPackagePathsr,   )r5   r  r  r   r   r   test_pluginDirectories  s   z'PackagePathTests.test_pluginDirectoriesc                 C  s   t |  }|ddd}|  |dd |dj|djgt_| t	d|dddjg dS )	a  
        L{plugin.pluginPackagePaths} should exclude directories which are
        Python packages.  The only allowed plugin package (the only one
        associated with a I{dummy} package which Python will allow to be
        imported) will already be known to the caller of
        L{plugin.pluginPackagePaths} and will most commonly already be in
        the C{__path__} they are about to mutate.
        r  r   rf   r    r!   r  r	  N)
r
   r)   r,   r   r.   r$   r#   rc   r	   r
  )r5   r*   r  r   r   r   test_pluginPackagesExcluded  s   	z,PackagePathTests.test_pluginPackagesExcludedNr   )r   r   r   r   r6   r=   r  r  r   r   r   r   r    s    


r  )ri   r   r   r   )
r   r   r   r   r   r@   r   r   r   r   )+r   
__future__r   r   r   rY   rI   r#   r   	importlibr   r   typesr   typingr   r   r   zope.interfacer   twistedr	   twisted.python.filepathr
   twisted.python.logr   r   r   r   twisted.trialr   r   r   r   TestCaser   r   r   r   r   r   r   r  r   r   r   r   <module>   s<     <

 B_