Package doapfiend :: Package plugins
[hide private]
[frames] | no frames]

Source Code for Package doapfiend.plugins

  1   
  2  # pylint: disable-msg=W0142,C0103 
  3   
  4   
  5  """ 
  6  Writing Plugins 
  7  =============== 
  8   
  9  doapfiend supports setuptools_ entry point plugins. 
 10   
 11  There are two basic rules for plugins: 
 12   
 13   - Plugin classes should subclass `doapfiend.plugins.Plugin`_. 
 14   - Plugins may implement any of the methods described in the class 
 15     PluginInterface in doapfiend.plugins.base. Please note that this class is for 
 16     documentary purposes only; plugins may not subclass PluginInterface. 
 17   
 18  Setuptools: http://peak.telecommunity.com/DevCenter/setuptools 
 19  Doapfiend Plugins: http://trac.doapspace.org/doapfiend/wiki/DoapfiendPlugins  
 20   
 21  Registering 
 22  ----------- 
 23   
 24  For doapfiend to find a plugin, it must be part of a package that uses 
 25  setuptools, and the plugin must be included in the entry points defined 
 26  in the setup.py for the package:: 
 27   
 28    setup(name='Some plugin', 
 29          ... 
 30          entry_points = { 
 31              'doapfiend.plugins': [ 
 32                  'someplugin = someplugin:SomePlugin' 
 33                  ] 
 34              }, 
 35          ... 
 36          ) 
 37   
 38  Once the package is installed with install or develop, doapfiend will be able 
 39  to load the plugin. 
 40   
 41  Defining options 
 42  ---------------- 
 43   
 44  All plugins must implement the methods ``add_options(self, parser, env)`` 
 45  and ``configure(self, options, conf)``. Subclasses of doapfiend.plugins.Plugin 
 46  that want the standard options should call the superclass methods. 
 47   
 48  doapfiend uses optparse.OptionParser from the standard library to parse 
 49  arguments. A plugin's ``add_options()`` method receives a parser 
 50  instance. It's good form for a plugin to use that instance only to add 
 51  additional arguments that take only long arguments (--like-this). Most 
 52  of doapfiend's built-in arguments get their default value from an environment 
 53  variable. This is a good practice because it allows options to be 
 54  utilized when run through some other means than the doapfiendtests script. 
 55   
 56  A plugin's ``configure()`` method receives the parsed ``OptionParser`` options  
 57  object, as well as the current config object. Plugins should configure their 
 58  behavior based on the user-selected settings, and may raise exceptions 
 59  if the configured behavior is nonsensical. 
 60   
 61  Logging 
 62  ------- 
 63   
 64  doapfiend uses the logging classes from the standard library. To enable users 
 65  to view debug messages easily, plugins should use ``logging.getLogger()`` to 
 66  acquire a logger in the ``doapfiend.plugins`` namespace. 
 67   
 68  """ 
 69   
 70  import logging 
 71  import pkg_resources 
 72  from warnings import warn 
 73  from inspect import isclass 
 74  from doapfiend.plugins.base import Plugin 
 75   
 76  LOG = logging.getLogger(__name__) 
 77   
 78  # +==== IMPORTANT ====+ 
 79  #If you add any builtin plugins in doapfiend.plugins you must add them  
 80  #to this list for them to be loaded. It's okay to add other Python modules 
 81  #in the doapfiend.plugins namespace, but they won't be recognized as a plugin 
 82  #unless listed here: 
 83   
 84  builtin_plugins = ['url', 'homepage', 'n3', 'xml', 'text', 'sourceforge', 
 85          'pypi', 'freshmeat', 'ohloh'] 
 86   
87 -def call_plugins(plugins, method, *arg, **kw):
88 """Call all method on plugins in list, that define it, with provided 89 arguments. The first response that is not None is returned. 90 """ 91 for plug in plugins: 92 func = getattr(plug, method, None) 93 if func is None: 94 continue 95 LOG.debug("call plugin %s: %s", plug.name, method) 96 result = func(*arg, **kw) 97 if result is not None: 98 return result 99 return None
100
101 -def load_plugins(builtin=True, others=True):
102 """Load plugins, either builtin, others, or both. 103 """ 104 loaded = [] 105 if builtin: 106 for name in builtin_plugins: 107 try: 108 parent = __import__(__name__, globals(), locals(), [name]) 109 #print name 110 pmod = getattr(parent, name) 111 for entry in dir(pmod): 112 obj = getattr(pmod, entry) 113 if (isclass(obj) 114 and issubclass(obj, Plugin) 115 and obj is not Plugin 116 and not obj in loaded): 117 #LOG.debug("load builtin plugin %s (%s)" % (name, obj)) 118 #print "load builtin plugin %s (%s)" % (name, obj) 119 yield obj 120 loaded.append(obj) 121 except KeyboardInterrupt: 122 raise 123 except Exception, e: 124 warn("Unable to load builtin plugin %s: %s" % (name, e), 125 RuntimeWarning) 126 for entry_point in pkg_resources.iter_entry_points('doapfiend.plugins'): 127 LOG.debug("load plugin %s" % entry_point) 128 try: 129 plugin = entry_point.load() 130 except KeyboardInterrupt: 131 raise 132 except Exception, err_msg: 133 # never want a plugin load to exit doapfiend 134 # but we can't log here because the logger is not yet 135 # configured 136 warn("Unable to load plugin %s: %s" % \ 137 (entry_point, err_msg), RuntimeWarning) 138 continue 139 if plugin.__module__.startswith('doapfiend.plugins'): 140 if builtin: 141 yield plugin 142 elif others: 143 yield plugin
144