diff options
author | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:16:14 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:43:30 +0300 |
commit | b8cf9e88f4c5c64d9406af533d8948deb050d695 (patch) | |
tree | 218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py2/twisted/plugin.py | |
parent | 523f645a83a0ec97a0332dbc3863bb354c92a328 (diff) | |
download | ydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz |
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py2/twisted/plugin.py')
-rw-r--r-- | contrib/python/Twisted/py2/twisted/plugin.py | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py2/twisted/plugin.py b/contrib/python/Twisted/py2/twisted/plugin.py new file mode 100644 index 0000000000..82522ee2fe --- /dev/null +++ b/contrib/python/Twisted/py2/twisted/plugin.py @@ -0,0 +1,259 @@ +# -*- test-case-name: twisted.test.test_plugin -*- +# Copyright (c) 2005 Divmod, Inc. +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Plugin system for Twisted. + +@author: Jp Calderone +@author: Glyph Lefkowitz +""" + +from __future__ import absolute_import, division + +import os +import sys + +from zope.interface import Interface, providedBy + +def _determinePickleModule(): + """ + Determine which 'pickle' API module to use. + """ + try: + import cPickle + return cPickle + except ImportError: + import pickle + return pickle + +pickle = _determinePickleModule() + +from twisted.python.components import getAdapterFactory +from twisted.python.reflect import namedAny +from twisted.python import log +from twisted.python.modules import getModule +from twisted.python.compat import iteritems + + + +class IPlugin(Interface): + """ + Interface that must be implemented by all plugins. + + Only objects which implement this interface will be considered for return + by C{getPlugins}. To be useful, plugins should also implement some other + application-specific interface. + """ + + + +class CachedPlugin(object): + def __init__(self, dropin, name, description, provided): + self.dropin = dropin + self.name = name + self.description = description + self.provided = provided + self.dropin.plugins.append(self) + + def __repr__(self): + return '<CachedPlugin %r/%r (provides %r)>' % ( + self.name, self.dropin.moduleName, + ', '.join([i.__name__ for i in self.provided])) + + def load(self): + return namedAny(self.dropin.moduleName + '.' + self.name) + + def __conform__(self, interface, registry=None, default=None): + for providedInterface in self.provided: + if providedInterface.isOrExtends(interface): + return self.load() + if getAdapterFactory(providedInterface, interface, None) is not None: + return interface(self.load(), default) + return default + + # backwards compat HOORJ + getComponent = __conform__ + + + +class CachedDropin(object): + """ + A collection of L{CachedPlugin} instances from a particular module in a + plugin package. + + @type moduleName: C{str} + @ivar moduleName: The fully qualified name of the plugin module this + represents. + + @type description: C{str} or L{None} + @ivar description: A brief explanation of this collection of plugins + (probably the plugin module's docstring). + + @type plugins: C{list} + @ivar plugins: The L{CachedPlugin} instances which were loaded from this + dropin. + """ + def __init__(self, moduleName, description): + self.moduleName = moduleName + self.description = description + self.plugins = [] + + + +def _generateCacheEntry(provider): + dropin = CachedDropin(provider.__name__, + provider.__doc__) + for k, v in iteritems(provider.__dict__): + plugin = IPlugin(v, None) + if plugin is not None: + # Instantiated for its side-effects. + CachedPlugin(dropin, k, v.__doc__, list(providedBy(plugin))) + return dropin + +try: + fromkeys = dict.fromkeys +except AttributeError: + def fromkeys(keys, value=None): + d = {} + for k in keys: + d[k] = value + return d + + + +def getCache(module): + """ + Compute all the possible loadable plugins, while loading as few as + possible and hitting the filesystem as little as possible. + + @param module: a Python module object. This represents a package to search + for plugins. + + @return: a dictionary mapping module names to L{CachedDropin} instances. + """ + allCachesCombined = {} + mod = getModule(module.__name__) + # don't want to walk deep, only immediate children. + buckets = {} + # Fill buckets with modules by related entry on the given package's + # __path__. There's an abstraction inversion going on here, because this + # information is already represented internally in twisted.python.modules, + # but it's simple enough that I'm willing to live with it. If anyone else + # wants to fix up this iteration so that it's one path segment at a time, + # be my guest. --glyph + for plugmod in mod.iterModules(): + fpp = plugmod.filePath.parent() + if fpp not in buckets: + buckets[fpp] = [] + bucket = buckets[fpp] + bucket.append(plugmod) + for pseudoPackagePath, bucket in iteritems(buckets): + dropinPath = pseudoPackagePath.child('dropin.cache') + try: + lastCached = dropinPath.getModificationTime() + with dropinPath.open('r') as f: + dropinDotCache = pickle.load(f) + except: + dropinDotCache = {} + lastCached = 0 + + needsWrite = False + existingKeys = {} + for pluginModule in bucket: + pluginKey = pluginModule.name.split('.')[-1] + existingKeys[pluginKey] = True + if ((pluginKey not in dropinDotCache) or + (pluginModule.filePath.getModificationTime() >= lastCached)): + needsWrite = True + try: + provider = pluginModule.load() + except: + # dropinDotCache.pop(pluginKey, None) + log.err() + else: + entry = _generateCacheEntry(provider) + dropinDotCache[pluginKey] = entry + # Make sure that the cache doesn't contain any stale plugins. + for pluginKey in list(dropinDotCache.keys()): + if pluginKey not in existingKeys: + del dropinDotCache[pluginKey] + needsWrite = True + if needsWrite: + try: + dropinPath.setContent(pickle.dumps(dropinDotCache)) + except OSError as e: + log.msg( + format=( + "Unable to write to plugin cache %(path)s: error " + "number %(errno)d"), + path=dropinPath.path, errno=e.errno) + except: + log.err(None, "Unexpected error while writing cache file") + allCachesCombined.update(dropinDotCache) + return allCachesCombined + + + +def getPlugins(interface, package=None): + """ + Retrieve all plugins implementing the given interface beneath the given module. + + @param interface: An interface class. Only plugins which implement this + interface will be returned. + + @param package: A package beneath which plugins are installed. For + most uses, the default value is correct. + + @return: An iterator of plugins. + """ + if package is None: + import twisted.plugins as package + allDropins = getCache(package) + for key, dropin in iteritems(allDropins): + for plugin in dropin.plugins: + try: + adapted = interface(plugin, None) + except: + log.err() + else: + if adapted is not None: + yield adapted + + +# Old, backwards compatible name. Don't use this. +getPlugIns = getPlugins + + +def pluginPackagePaths(name): + """ + Return a list of additional directories which should be searched for + modules to be included as part of the named plugin package. + + @type name: C{str} + @param name: The fully-qualified Python name of a plugin package, eg + C{'twisted.plugins'}. + + @rtype: C{list} of C{str} + @return: The absolute paths to other directories which may contain plugin + modules for the named plugin package. + """ + package = name.split('.') + # Note that this may include directories which do not exist. It may be + # preferable to remove such directories at this point, rather than allow + # them to be searched later on. + # + # Note as well that only '__init__.py' will be considered to make a + # directory a package (and thus exclude it from this list). This means + # that if you create a master plugin package which has some other kind of + # __init__ (eg, __init__.pyc) it will be incorrectly treated as a + # supplementary plugin directory. + return [ + os.path.abspath(os.path.join(x, *package)) + for x + in sys.path + if + not os.path.exists(os.path.join(x, *package + ['__init__.py']))] + +__all__ = ['getPlugins', 'pluginPackagePaths'] |