Back to index

python-cliapp  1.20120630
plugin.py
Go to the documentation of this file.
00001 # Copyright (C) 2009-2012  Lars Wirzenius
00002 # 
00003 # This program is free software; you can redistribute it and/or modify
00004 # it under the terms of the GNU General Public License as published by
00005 # the Free Software Foundation; either version 2 of the License, or
00006 # (at your option) any later version.
00007 # 
00008 # This program is distributed in the hope that it will be useful,
00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 # GNU General Public License for more details.
00012 # 
00013 # You should have received a copy of the GNU General Public License along
00014 # with this program; if not, write to the Free Software Foundation, Inc.,
00015 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016 
00017 
00018 '''A generic plugin manager.
00019 
00020 The plugin manager finds files with plugins and loads them. It looks
00021 for plugins in a number of locations specified by the caller. To add
00022 a plugin to be loaded, it is enough to put it in one of the locations,
00023 and name it *_plugin.py. (The naming convention is to allow having
00024 other modules as well, such as unit tests, in the same locations.)
00025 
00026 '''
00027 
00028 
00029 import imp
00030 import inspect
00031 import os
00032 
00033 
00034 class Plugin(object):
00035 
00036     '''Base class for plugins.
00037     
00038     A plugin MUST NOT have any side effects when it is instantiated.
00039     This is necessary so that it can be safely loaded by unit tests,
00040     and so that a user interface can allow the user to disable it,
00041     even if it is installed, with no ill effects. Any side effects
00042     that would normally happen should occur in the enable() method,
00043     and be undone by the disable() method. These methods must be
00044     callable any number of times.
00045     
00046     The subclass MAY define the following attributes:
00047     
00048     * name
00049     * description
00050     * version
00051     * required_application_version
00052     
00053     name is the user-visible identifier for the plugin. It defaults
00054     to the plugin's classname.
00055     
00056     description is the user-visible description of the plugin. It may
00057     be arbitrarily long, and can use pango markup language. Defaults
00058     to the empty string.
00059     
00060     version is the plugin version. Defaults to '0.0.0'. It MUST be a
00061     sequence of integers separated by periods. If several plugins with
00062     the same name are found, the newest version is used. Versions are
00063     compared integer by integer, starting with the first one, and a 
00064     missing integer treated as a zero. If two plugins have the same 
00065     version, either might be used.
00066     
00067     required_application_version gives the version of the minimal 
00068     application version the plugin is written for. The first integer
00069     must match exactly: if the application is version 2.3.4, the
00070     plugin's required_application_version must be at least 2 and
00071     at most 2.3.4 to be loaded. Defaults to 0.
00072     
00073     '''
00074     
00075     @property
00076     def name(self):
00077         return self.__class__.__name__
00078         
00079     @property
00080     def description(self):
00081         return ''
00082         
00083     @property
00084     def version(self):
00085         return '0.0.0'
00086         
00087     @property
00088     def required_application_version(self):
00089         return '0.0.0'
00090         
00091     def setup(self):
00092         '''Setup plugin.
00093         
00094         This is called at plugin load time. It should not yet enable the
00095         plugin (the ``enable`` method does that), but it might do things
00096         like add itself into a hook that adds command line arguments
00097         to the application.
00098         
00099         '''
00100         
00101     def enable_wrapper(self):
00102         '''Enable plugin.
00103         
00104         The plugin manager will call this method, which then calls the
00105         enable method. Plugins should implement the enable method.
00106         The wrapper method is there to allow an application to provide
00107         an extended base class that does some application specific
00108         magic when plugins are enabled or disabled.
00109         
00110         '''
00111         
00112         self.enable()
00113 
00114     def disable_wrapper(self):
00115         '''Corresponds to enable_wrapper, but for disabling a plugin.'''
00116         self.disable()
00117     
00118     def enable(self):
00119         '''Enable the plugin.'''
00120         raise NotImplemented()
00121     
00122     def disable(self):
00123         '''Disable the plugin.'''
00124         raise NotImplemented()
00125