title: Yapsy: a simple hack to get rid of the plugin info file
body: <p>I'd like to use a plugin system within my code. I've looked around for simple (yet powerful) python modules, and found Yapsy (among some others).</p>
  
  <p>It is quite what I was looking for, but the way Yapsy discover plugins is not very flexible and require a plugin info file to be present. I'd like to get rid of it, without having to fork the code (if I start relying on Yapsy, I want to be sure I'll get all the updates from it without having to refork it each time).</p>
  
  <p>I came out with this quick and dirty solution which is working fine, but do not improve the flexibility of the "discovering" process:</p>
  
  <pre><code>#!/usr/bin/env python
  
  import os
  import logging
  from cStringIO import StringIO
  
  from yapsy.PluginManager import PluginManager
  from yapsy.IPlugin import IPlugin
  from yapsy.PluginInfo import PluginInfo
  
  
  class MyPluginManager(PluginManager):
      """
      My attempt to get rid of the plugin info file...
      """
      def __init__(self, 
                   categories_filter={"Default":IPlugin}, 
                   directories_list=None, 
                   plugin_info_ext="plugin.py"):
          """
          Initialize the mapping of the categories and set the list of
          directories where plugins may be. This can also be set by
          direct call the methods: 
  
          - ``setCategoriesFilter`` for ``categories_filter``
          - ``setPluginPlaces`` for ``directories_list``
          - ``setPluginInfoExtension`` for ``plugin_info_ext``
  
          You may look at these function's documentation for the meaning
          of each corresponding arguments.
          """
          self.setPluginInfoClass(PluginInfo)
          self.setCategoriesFilter(categories_filter)     
          self.setPluginPlaces(directories_list)
          self.setPluginInfoExtension(plugin_info_ext)    
  
      def _gatherCorePluginInfo(self, directory, filename):
          """
          Gather the core information (name, and module to be loaded)
          about a plugin described by it's info file (found at
          'directory/filename').
  
          Return an instance of ``self.plugin_info_cls`` and the
          config_parser used to gather the core data *in a tuple*, if the
          required info could be localised, else return ``(None,None)``.
  
          .. note:: This is supposed to be used internally by subclasses
              and decorators.
  
          """
          # now we can consider the file as a serious candidate
          candidate_infofile = os.path.join(directory,filename)
          print candidate_infofile
  
          # My hack : just create a StringIO file with basic plugin info
          _fname = filename.rstrip(".py")
          _file = StringIO()
          _file.write("""[Core]
  Name = %s
  Module = %s
          """ % (_fname, _fname))
          _file.seek(0)
  
          # parse the information file to get info about the plugin
          name,moduleName,config_parser = self._getPluginNameAndModuleFromStream(_file, candidate_infofile)
          print name, moduleName, config_parser
          if (name,moduleName,config_parser)==(None,None,None):
                          return (None,None)
          # start collecting essential info
          plugin_info = self._plugin_info_cls(name,os.path.join(directory,moduleName))
          return (plugin_info,config_parser)
  </code></pre>
  
  <p>This hack just assumes that the plugin has an extension ".plugin.py" (or ".plugin" for directory, but I did not test it). Then I create a cSringIO file to fool Yapsy and make it think he found a plugin info file. (One can still provide additional informations in the plugin by setting the proper variables: author, description...).</p>
  
  <p>I'm wondering if there is a better way or if people have already done that. This hack is clearly too rough to be really useful, and I'd like to have something more flexible: a plugin may be discovered by its plugin info file (as in the original code) or by a pattern for the plugin name (probably using <code>re</code>, allowing the usage of prefix, suffix...). As far as I see, having these ideas implemented would require a much more complex hack than what I've already done...</p>