PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/desktop/core/ext-py/Twisted/twisted/python/plugin.py

https://github.com/jcrobak/hue
Python | 332 lines | 237 code | 24 blank | 71 comment | 43 complexity | 4f79045f670ea0bcd6e0503f7da91f15 MD5 | raw file
  1. # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. from __future__ import nested_scopes
  4. # System Imports
  5. import sys
  6. import os
  7. import errno
  8. import types
  9. import warnings
  10. # Twisted imports
  11. from twisted.python import util
  12. # Sibling Imports
  13. from reflect import namedModule
  14. try:
  15. from os.path import realpath as cacheTransform
  16. except ImportError:
  17. from os.path import abspath as cacheTransform
  18. class PlugIn:
  19. """I am a Python module registered in a plugins.tml file.
  20. """
  21. def __init__(self, name, module, **kw):
  22. self.name = name
  23. self.module = module
  24. for key, value in kw.items():
  25. setattr(self, key, value)
  26. def isLoaded(self):
  27. """Check to see if the module for this plugin has been imported yet.
  28. @rtype: C{int}
  29. @return: A true value if the module for this plugin has been loaded,
  30. false otherwise.
  31. """
  32. return sys.modules.has_key(self.module)
  33. def load(self):
  34. """Load the module for this plugin.
  35. @rtype: C{ModuleType}
  36. @return: The module object that is loaded.
  37. """
  38. return namedModule(self.module)
  39. def __repr__(self):
  40. if self.isLoaded():
  41. loaded = ' loaded'
  42. else:
  43. loaded = ''
  44. return "<Plugin %s %s%s>" % (repr(self.name), self.module, loaded)
  45. class DropIn:
  46. """I am a Python package containing plugins.tml.
  47. """
  48. def __init__(self, name):
  49. self.name = name
  50. self.plugins = []
  51. def register(self, name, module, **kw):
  52. """Register a new plug-in.
  53. """
  54. warnings.warn("The twisted.python.plugin system is deprecated. "
  55. "See twisted.plugin for the revised edition.",
  56. DeprecationWarning, 2)
  57. self.plugins.append(PlugIn(name, module, **kw))
  58. def __repr__(self):
  59. return "<Package %s %s>" % (self.name, self.plugins)
  60. def _prepCallbacks(debug, progress):
  61. if debug:
  62. try:
  63. debug('Looking for plugin.tml files')
  64. except:
  65. debug = lambda x: sys.stdout.write(x + '\n')
  66. debug('Looking for plugin.tml files')
  67. else:
  68. debug = lambda x: None
  69. if progress:
  70. try:
  71. progress(0.0)
  72. except:
  73. pb = util.makeStatusBar(76)
  74. progress = lambda x, pb=pb: sys.stdout.write(pb(x) + '\r')
  75. progress(0.0)
  76. else:
  77. progress = lambda x: None
  78. return debug, progress
  79. def getPluginFileList(debugInspection=None, showProgress=None):
  80. """Find plugin.tml files in subdirectories of paths in C{sys.path}
  81. @type debugInspection: C{None} or a callable taking one argument
  82. @param debugInspection: If not None, this is invoked with strings containing
  83. debug information about the loading process. If it is any other true value,
  84. this debug information is written to stdout (This behavior is deprecated).
  85. @type showProgress: C{None} or a callable taking one argument.
  86. @param showProgress: If not None, this is invoked with floating point
  87. values between 0 and 1 describing the progress of the loading process.
  88. If it is any other true value, this progress information is written to
  89. stdout. (This behavior is deprecated).
  90. @rtype: C{list} of C{str}
  91. @return: A list of the plugin.tml files found.
  92. """
  93. if isinstance(debugInspection, types.IntType):
  94. warnings.warn(
  95. "int parameter for debugInspection is deprecated, pass None or "
  96. "a function that takes a single argument instead.",
  97. DeprecationWarning, 2
  98. )
  99. if isinstance(showProgress, types.IntType):
  100. warnings.warn(
  101. "int parameter for showProgress is deprecated, pass None or "
  102. "a function that takes a single argument instead.",
  103. DeprecationWarning, 2
  104. )
  105. debugInspection, showProgress = _prepCallbacks(debugInspection, showProgress)
  106. exists = os.path.exists
  107. join = os.sep.join
  108. result = []
  109. loaded = {}
  110. seenNames = {}
  111. # XXX Some people claim to have found non-strings in sys.path (an empty
  112. # list, in particular). Instead of tracking down the cause for their
  113. # presence, they decided it was better to discard them unconditionally
  114. # without further investigation. At some point, someone should track
  115. # down where non-strings are coming from and do something about them.
  116. paths = [cacheTransform(p) for p in sys.path
  117. if isinstance(p, str) and os.path.isdir(p)]
  118. # special case for commonly used directories we *know* shouldn't be checked
  119. # and really slow down mktap and such-like in real installations
  120. for p in ("/usr/bin", "/usr/local/bin"):
  121. try:
  122. paths.remove(p)
  123. except ValueError:
  124. pass
  125. progress = 0.0
  126. increments = 1.0 / len(paths)
  127. for (index, d) in zip(range(len(paths)), paths):
  128. showProgress(progress)
  129. if loaded.has_key(d):
  130. debugInspection('Already saw ' + d)
  131. continue
  132. else:
  133. debugInspection('Recursing through ' + d)
  134. try:
  135. subDirs = os.listdir(d)
  136. except OSError, (err, s):
  137. # Permission denied, carry on
  138. if err == errno.EACCES:
  139. debugInspection('Permission denied on ' + d)
  140. else:
  141. raise
  142. else:
  143. # filter out files we obviously don't need to check - ones with '.' in them
  144. subDirs = [s for s in subDirs if "." not in s]
  145. if not subDirs:
  146. continue
  147. incr = increments * (1.0 / len(subDirs))
  148. for plugindir in subDirs:
  149. if seenNames.has_key(plugindir):
  150. debugInspection('Seen %s already' % plugindir)
  151. continue
  152. tmlname = join((d, plugindir, "plugins.tml"))
  153. if isAModule(join((d,plugindir))):
  154. seenNames[plugindir] = 1
  155. if exists(tmlname):
  156. result.append(tmlname)
  157. debugInspection('Found ' + tmlname)
  158. else:
  159. debugInspection('Failed ' + tmlname)
  160. else:
  161. debugInspection('Not a module ' + tmlname)
  162. progress = progress + incr
  163. showProgress(progress)
  164. showProgress(1.0)
  165. return result
  166. def loadPlugins(plugInType, fileList, debugInspection=None, showProgress=None):
  167. """Traverse the given list of files and attempt to load plugins from them.
  168. @type plugInType: C{str}
  169. @param plugInType: The type of plugin to search for. This is tested
  170. against the C{type} argument to the C{register} function in the
  171. plugin.tml files.
  172. @type fileList: C{list} of C{str}
  173. @param fileList: A list of the files to attempt to load plugin
  174. information from. One name is put in their scope, the C{register}
  175. function.
  176. @type debugInspection: C{None} or a callable taking one argument
  177. @param debugInspection: If not None, this is invoked with strings containing
  178. debug information about the loading process. If it is any other true value,
  179. this debug information is written to stdout (This behavior is deprecated).
  180. @type showProgress: C{None} or a callable taking one argument.
  181. @param showProgress: If not None, this is invoked with floating point
  182. values between 0 and 1 describing the progress of the loading process.
  183. If it is any other true value, this progress information is written to
  184. stdout. (This behavior is deprecated).
  185. @rtype: C{list}
  186. @return: A list of the C{PlugIn} objects found.
  187. """
  188. if isinstance(debugInspection, types.IntType):
  189. warnings.warn(
  190. "int parameter for debugInspection is deprecated, pass None or "
  191. "a function that takes a single argument instead.",
  192. DeprecationWarning, 4
  193. )
  194. if isinstance(showProgress, types.IntType):
  195. warnings.warn(
  196. "int parameter for showProgress is deprecated, pass None or "
  197. "a function that takes a single argument instead.",
  198. DeprecationWarning, 4
  199. )
  200. result = []
  201. debugInspection, showProgress = _prepCallbacks(debugInspection, showProgress)
  202. if not fileList:
  203. raise ValueError("No plugins passed to loadPlugins")
  204. increments = 1.0 / len(fileList)
  205. progress = 0.0
  206. for (index, tmlFile) in zip(range(len(fileList)), fileList):
  207. showProgress(progress)
  208. debugInspection("Loading from " + tmlFile)
  209. pname = os.path.split(os.path.abspath(tmlFile))[-2]
  210. dropin = DropIn(pname)
  211. ns = {'register': dropin.register, '__file__': tmlFile}
  212. try:
  213. execfile(tmlFile, ns)
  214. except (IOError, OSError), e:
  215. # guess we don't have permissions for that
  216. debugInspection("Error loading: %s" % e)
  217. continue
  218. ldp = len(dropin.plugins) or 1.0
  219. incr = increments * (1.0 / ldp)
  220. for plugin in dropin.plugins:
  221. if plugInType == plugin.type:
  222. result.append(plugin)
  223. debugInspection("Found %r" % (plugin,))
  224. else:
  225. debugInspection("Disqualified %r" % (plugin,))
  226. progress = progress + incr
  227. showProgress(progress)
  228. debugInspection("Finished loading from %s!" % tmlFile)
  229. showProgress(1.0)
  230. debugInspection("Returning %r" % (result,))
  231. return result
  232. def getPlugIns(plugInType, debugInspection=None, showProgress=None):
  233. """Helper function to get all the plugins of a particular type.
  234. @type plugInType: C{str}
  235. @param plugInType: The type of plugin to search for. This is tested
  236. against the C{type} argument to the C{register} function in the
  237. plugin.tml files.
  238. @type debugInspection: C{None} or a callable taking one argument
  239. @param debugInspection: If not None, this is invoked with strings containing
  240. debug information about the loading process. If it is any other true value,
  241. this debug information is written to stdout (This behavior is deprecated).
  242. @type showProgress: C{None} or a callable taking one argument.
  243. @param showProgress: If not None, this is invoked with floating point
  244. values between 0 and 1 describing the progress of the loading process.
  245. If it is any other true value, this progress information is written to
  246. stdout. (This behavior is deprecated).
  247. @rtype: C{list}
  248. @return: A list of C{PlugIn} objects that were found.
  249. """
  250. warnings.warn("The twisted.python.plugin system is deprecated. "
  251. "See twisted.plugin for the revised edition.",
  252. DeprecationWarning, 2)
  253. return _getPlugIns(plugInType, debugInspection, showProgress)
  254. def _getPlugIns(plugInType, debugInspection=None, showProgress=None):
  255. if isinstance(debugInspection, types.IntType):
  256. warnings.warn(
  257. "int parameter for debugInspection is deprecated, pass None or "
  258. "a function that takes a single argument instead.",
  259. DeprecationWarning, 3
  260. )
  261. if isinstance(showProgress, types.IntType):
  262. warnings.warn(
  263. "int parameter for showProgress is deprecated, pass None or "
  264. "a function that takes a single argument instead.",
  265. DeprecationWarning, 3
  266. )
  267. debugInspection, showProgress = _prepCallbacks(debugInspection, showProgress)
  268. firstHalf = secondHalf = lambda x: None
  269. if showProgress:
  270. firstHalf = lambda x: showProgress(x / 2.0)
  271. secondHalf = lambda x: showProgress(x / 2.0 + 0.5)
  272. tmlFiles = getPluginFileList(debugInspection, firstHalf)
  273. if not tmlFiles:
  274. return []
  275. return loadPlugins(plugInType, tmlFiles, debugInspection, secondHalf)
  276. def isAModule(d):
  277. """This function checks the directory for __init__ files.
  278. """
  279. suffixes = ['py', 'pyc', 'pyo', 'so', 'pyd', 'dll']
  280. exists = os.path.exists
  281. join = os.sep.join
  282. for s in suffixes: # bad algorithm, but probably works
  283. if exists(join((d,'__init__.%s' % s))):
  284. return 1
  285. return 0
  286. __all__ = ['PlugIn', 'DropIn', 'getPluginFileList', 'loadPlugins', 'getPlugIns']