GEPS 014: Plugin registration and management

From Gramps
Jump to: navigation, search

This GEP is now included in Gramps 3.2.x

This GEP aims to introduce plugin registration and management in GRAMPS.

Present situation

What happens in version 3.1: The pluginmanager runs through the directory INSTALLDIR/plugins, and GRAMPSDIR/plugins, loading all .py files. If these have a plugin register method then the textreport, gramplet, exportmethod, ... becomes available in GRAMPS.

Disadvantages:

  • loading plugins takes up a large part of the startup time of GRAMPS. This is especially annoying for CLI mode
  • all plugins are loaded, so all imports happen, in essence almost the entirity of GRAMPS is imported. When doing a CLI report, this eg means GTK is loaded, ...
  • from a security point of view, just importing everything from a directory is not ideal. However, as the user downloaded a plugin, he will probably run it no matter what.
  • no management possible of what plugins should be loaded and enabled.
  • no way to catch duplicate plugins


Proposal

This GEP proposes to change this to the following setup

  1. every plugin is accompanied by a plugin.gpr file, which is a gramps plugin register file. This contains an xml (?? see below) file with:
    • plugin name (internationalization ???)
    • plugin python file
    • plugin description
    • optional plugin screenshots
    • plugin mode (CLI, GUI, CLI_GUI)
    • plugin author + email
    • plugin version
    • plugin status (alpha, beta, final)
  2. on load of GRAMPS these files are parsed and the pluginmanager so has a list of plugins that are available. The GRAMPS ini or a new ini file lists all plugins that should be enabled by default in GRAMPS. Only those are visible in the plugin menu. A command line option allows to preload some plugins.
  3. some plugins types can be preloaded in the GUI mode, eg export/import ??
  4. when the user selects a plugin, the pluginmanager imports the plugin and returns the specific class
  5. There is a plugin manager interface showing all possible plugins, and an option to enable/disable. Some plugins are ptotected, meaning they cannot be disabled. For debugging, there is a load option importing a selected plugin again. If load fails, the traceback is available here too.
  6. A newly downloaded plugin must be enabled to make it available. In the case of name clash, the INSTALLDIR version takes precedence.

Advantages

  • it is possible to split between CLI and GUI code also in the plugins
  • one can disable plugins one does not want so as to simplify the plugin menu
  • added security (??)
  • duplicates are handled in a known way
  • easier support. The effective determination of the plugin classes will be done in one place, instead of a register method in every plugin.

The gpr xml file ??

A good definition for the xml must be present. Things to answer:

  • can we have gettext extract the name and description from the xml to create internationalization? Or should we have a setup like:
<name>
<default>Descendant Report</default>
<lang value='nl'>Afstammelings rapport</lang
</name>
  • what must be present in the xml file?
  • it would be easier if the gpr file is just an python file. Can this be done safely? Is it possible to require a python file with only a gettext import, and only a definition of a dict with the required defenitions. So something like:
from descreport.gpr.py import PLUGINLIST
where the descreport.gpr.py file is something like:
DESCREPORT = {'name': _('Descendant Report'), ...}
PLUGINLIST = [DESCREPORT]
This would simplify a lot things over an xml file.

Reply of HippySurfer

I think that the plugin description is better done in Python rather than XML.

We could use something like the following to read and load the plugin descriptions: First a class that represents a plugin:

 class PlugIn(object):

   _version = None
   _name = None

   def _set_version(self,version):
       self._version = version

   def _get_version(self):
       return self._version

   def _set_name(self,name):
       self._name = name

   def _get_name(self):
       return self._name

   version = property(_get_version,_set_version)
   name = property(_get_name,_set_name)

Then walk the tree looking for plugin registration files and for each one that we find:

 from gettext import gettext as _

 plug = PlugIn()

 execfile('test.py',{'_':_,
                   'set_version':plug._set_version,
                   'set_name':plug._set_name},
        {})

The plugin registration file can then just be a Python file that has assess to the methods that are exported from the plugin object, e.g.:

test.py:
 set_version (2)
 set_name(_('my name'))

After the execfile you can access the values that have been set:

print plug.version
print plug.name

There is no security here, the plugin registration code can still do what ever it likes but I don't see that as an issue. The plugins will not be run in a sandbox so why worry about their registration code.

Translation is simple because we can export '_'.

The functions that we choose to export could do anything we like, for instance you could export a function that would allow the plugin registration to query which version of gramps is running and register a different class. You could not do that if the registration was XML.

Remark

The reason to drive this GEP now is to enable cleanly plugin views. In this setup, the views of GRAMPS become plugins that can be enabled and disabled. Some views must always be present, so a way to not make plugins disabled must be present. The point is not to load views in the case CLI mode is done.

Views should also accomodate for more than one instance of the view. This must be worked out if this should be part of the pluginmanager or in some other configuration dialog.

Screenshots

Registered_plugins
Loaded plugins
Hidden plugins
Detailed informations
Plugin edition
Registered plugins (localized)