2005-01-05 10:32:19 +05:30
|
|
|
#
|
|
|
|
# Gramps - a GTK+/GNOME based genealogy program
|
|
|
|
#
|
2005-01-09 08:58:28 +05:30
|
|
|
# Copyright (C) 2000-2005 Donald N. Allingham
|
2008-05-19 00:54:28 +05:30
|
|
|
# Copyright (C) 2008 Brian G. Matherly
|
2009-10-27 00:45:58 +05:30
|
|
|
# Copyright (C) 2009 Benny Malengier
|
2005-01-05 10:32:19 +05:30
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
#
|
|
|
|
# $Id$
|
|
|
|
|
|
|
|
"""
|
2008-10-02 09:32:10 +05:30
|
|
|
The core of the GRAMPS plugin system. This module provides capability to load
|
2009-08-09 22:39:32 +05:30
|
|
|
plugins from specified directories and provide information about the loaded
|
2008-10-02 09:32:10 +05:30
|
|
|
plugins.
|
2005-01-05 10:32:19 +05:30
|
|
|
|
2008-10-02 09:32:10 +05:30
|
|
|
Plugins are divided into several categories. These are: reports, tools,
|
|
|
|
importers, exporters, quick reports, and document generators.
|
2005-01-05 10:32:19 +05:30
|
|
|
"""
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# Standard Python modules
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
import os
|
|
|
|
import sys
|
2005-01-09 07:48:49 +05:30
|
|
|
import re
|
2006-04-07 03:32:46 +05:30
|
|
|
from gettext import gettext as _
|
2005-01-05 10:32:19 +05:30
|
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# GRAMPS modules
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
2008-09-27 19:26:17 +05:30
|
|
|
import gen.utils
|
2009-10-24 19:23:20 +05:30
|
|
|
from gen.plug import PluginRegister
|
2005-01-05 10:32:19 +05:30
|
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
2005-12-06 12:08:09 +05:30
|
|
|
# Constants
|
2005-01-05 10:32:19 +05:30
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
2008-10-14 08:04:28 +05:30
|
|
|
_UNAVAILABLE = _("No description was provided")
|
2005-01-05 10:32:19 +05:30
|
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
2009-10-25 19:22:29 +05:30
|
|
|
# BasePluginManager
|
2005-01-05 10:32:19 +05:30
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
2009-10-25 19:22:29 +05:30
|
|
|
class BasePluginManager(object):
|
|
|
|
""" unique singleton storage class for a PluginManager. """
|
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
__instance = None
|
2008-04-01 08:42:08 +05:30
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
def get_instance():
|
|
|
|
""" Use this function to get the instance of the PluginManager """
|
2009-10-25 19:22:29 +05:30
|
|
|
if BasePluginManager.__instance is None:
|
|
|
|
BasePluginManager.__instance = 1 # Set to 1 for __init__()
|
|
|
|
BasePluginManager.__instance = BasePluginManager()
|
|
|
|
return BasePluginManager.__instance
|
2008-05-19 00:54:28 +05:30
|
|
|
get_instance = staticmethod(get_instance)
|
2009-10-25 19:22:29 +05:30
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
def __init__(self):
|
|
|
|
""" This function should only be run once by get_instance() """
|
2009-10-25 19:22:29 +05:30
|
|
|
if BasePluginManager.__instance is not 1:
|
2008-05-19 00:54:28 +05:30
|
|
|
raise Exception("This class is a singleton. "
|
|
|
|
"Use the get_instance() method")
|
2009-10-24 19:23:20 +05:30
|
|
|
|
2008-10-14 08:04:28 +05:30
|
|
|
self.__import_plugins = []
|
2008-11-04 09:42:51 +05:30
|
|
|
self.__export_plugins = []
|
2009-03-19 07:54:29 +05:30
|
|
|
self.__docgen_plugins = []
|
2009-10-24 19:23:20 +05:30
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
self.__attempt_list = []
|
|
|
|
self.__failmsg_list = []
|
2009-02-05 07:53:46 +05:30
|
|
|
self.__external_opt_dict = {}
|
2008-05-19 00:54:28 +05:30
|
|
|
self.__success_list = []
|
|
|
|
|
|
|
|
self.__mod2text = {}
|
2008-04-01 08:42:08 +05:30
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
self.__pgr = PluginRegister.get_instance()
|
|
|
|
self.__registereddir_set = set()
|
|
|
|
self.__loaded_plugins = {}
|
|
|
|
|
|
|
|
def reg_plugins(self, direct):
|
2008-05-19 00:54:28 +05:30
|
|
|
"""
|
2009-10-24 19:23:20 +05:30
|
|
|
Searches the specified directory, and registers python plugin that
|
|
|
|
are being defined in gpr.py files.
|
2008-05-19 00:54:28 +05:30
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
If a relationship calculator for env var LANG is present, it is
|
|
|
|
immediately loaded so it is available for all.
|
|
|
|
"""
|
2008-05-19 00:54:28 +05:30
|
|
|
# if the directory does not exist, do nothing
|
|
|
|
if not os.path.isdir(direct):
|
|
|
|
return False # return value is True for error
|
2009-01-30 07:46:00 +05:30
|
|
|
|
2009-01-16 21:51:54 +05:30
|
|
|
for (dirpath, dirnames, filenames) in os.walk(direct):
|
|
|
|
# add the directory to the python search path
|
|
|
|
sys.path.append(dirpath)
|
|
|
|
# if the path has not already been loaded, save it in the
|
2009-10-24 19:23:20 +05:30
|
|
|
# registereddir_list list for use on reloading.
|
|
|
|
self.__registereddir_set.add(dirpath)
|
|
|
|
self.__pgr.scan_dir(dirpath)
|
2009-10-25 19:22:29 +05:30
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
# load plugins that request to be loaded on startup
|
|
|
|
for plugin in self.__pgr.filter_load_on_reg():
|
|
|
|
mod = self.load_plugin(plugin)
|
|
|
|
|
|
|
|
def load_plugin(self, pdata):
|
|
|
|
"""
|
|
|
|
Load a PluginData object. This means import of the python module.
|
|
|
|
Plugin directories are added to sys path, so files are found
|
|
|
|
"""
|
|
|
|
if pdata.id in self.__loaded_plugins:
|
|
|
|
return self.__loaded_plugins[pdata.id]
|
|
|
|
filename = pdata.fname
|
|
|
|
self.__attempt_list.append(filename)
|
|
|
|
plugin = pdata.mod_name
|
|
|
|
try:
|
|
|
|
_module = __import__(plugin)
|
|
|
|
self.__success_list.append((filename, _module))
|
|
|
|
self.__loaded_plugins[pdata.id] = _module
|
|
|
|
self.__mod2text[_module.__name__] = pdata.description
|
|
|
|
return _module
|
|
|
|
except:
|
|
|
|
self.__failmsg_list.append((filename, sys.exc_info()))
|
|
|
|
return None
|
2008-04-01 08:42:08 +05:30
|
|
|
|
2009-10-25 19:22:29 +05:30
|
|
|
def empty_managed_plugins(self):
|
|
|
|
""" For some plugins, managed Plugin are used. These are only
|
|
|
|
reobtained from the registry if this method is called
|
|
|
|
"""
|
|
|
|
# TODO: do other lists need to be reset here, too?
|
|
|
|
self.__import_plugins = []
|
|
|
|
self.__export_plugins = []
|
|
|
|
self.__docgen_plugins = []
|
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
def reload_plugins(self):
|
|
|
|
""" Reload previously loaded plugins """
|
|
|
|
pymod = re.compile(r"^(.*)\.py$")
|
|
|
|
|
|
|
|
oldfailmsg = self.__failmsg_list[:]
|
|
|
|
self.__failmsg_list = []
|
|
|
|
|
|
|
|
# attempt to reload all plugins that have succeeded in the past
|
2009-10-25 19:22:29 +05:30
|
|
|
self.empty_managed_plugins()
|
2008-11-29 21:57:08 +05:30
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
for plugin in self.__success_list:
|
|
|
|
filename = plugin[0]
|
|
|
|
filename = filename.replace('pyc','py')
|
|
|
|
filename = filename.replace('pyo','py')
|
|
|
|
try:
|
|
|
|
reload(plugin[1])
|
|
|
|
except:
|
|
|
|
self.__failmsg_list.append((filename, sys.exc_info()))
|
|
|
|
|
|
|
|
# Remove previously good plugins that are now bad
|
|
|
|
# from the registered lists
|
|
|
|
self.__purge_failed()
|
|
|
|
|
|
|
|
# attempt to load the plugins that have failed in the past
|
|
|
|
for (filename, message) in oldfailmsg:
|
|
|
|
name = os.path.split(filename)
|
|
|
|
match = pymod.match(name[1])
|
|
|
|
if not match:
|
|
|
|
continue
|
|
|
|
self.__attempt_list.append(filename)
|
|
|
|
plugin = match.groups()[0]
|
|
|
|
try:
|
|
|
|
# For some strange reason second importing of a failed plugin
|
|
|
|
# results in success. Then reload reveals the actual error.
|
|
|
|
# Looks like a bug in Python.
|
|
|
|
_module = __import__(plugin)
|
|
|
|
reload(_module)
|
|
|
|
self.__success_list.append((filename, _module))
|
|
|
|
except:
|
|
|
|
self.__failmsg_list.append((filename, sys.exc_info()))
|
2009-10-24 19:23:20 +05:30
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
def get_fail_list(self):
|
|
|
|
""" Return the list of failed plugins. """
|
|
|
|
return self.__failmsg_list
|
|
|
|
|
|
|
|
def get_success_list(self):
|
|
|
|
""" Return the list of succeeded plugins. """
|
|
|
|
return self.__success_list
|
2009-10-24 19:23:20 +05:30
|
|
|
|
2009-10-25 20:12:47 +05:30
|
|
|
def get_plugin(self, id):
|
|
|
|
"""
|
|
|
|
Returns a plugin object from PluginRegister by id.
|
|
|
|
"""
|
|
|
|
return self.__pgr.get_plugin(id)
|
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
def get_reg_reports(self, gui=True):
|
2009-10-25 19:22:29 +05:30
|
|
|
""" Return list of registered reports
|
2009-10-24 19:23:20 +05:30
|
|
|
:Param gui: bool indicating if GUI reports or CLI reports must be
|
|
|
|
returned
|
|
|
|
"""
|
2009-10-25 19:22:29 +05:30
|
|
|
return self.__pgr.report_plugins(gui)
|
2008-05-19 00:54:28 +05:30
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
def get_reg_tools(self, gui=True):
|
2009-10-25 19:22:29 +05:30
|
|
|
""" Return list of registered tools
|
2009-10-24 19:23:20 +05:30
|
|
|
:Param gui: bool indicating if GUI reports or CLI reports must be
|
|
|
|
returned
|
|
|
|
"""
|
2009-10-25 19:22:29 +05:30
|
|
|
return self.__pgr.tool_plugins(gui)
|
2008-05-19 00:54:28 +05:30
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
def get_reg_quick_reports(self):
|
2009-10-25 19:22:29 +05:30
|
|
|
""" Return list of registered quick reports
|
2009-10-24 19:23:20 +05:30
|
|
|
"""
|
2009-10-25 19:22:29 +05:30
|
|
|
return self.__pgr.quickreport_plugins()
|
2008-05-19 00:54:28 +05:30
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
def get_reg_mapservices(self):
|
2009-10-25 19:22:29 +05:30
|
|
|
""" Return list of registered mapservices
|
2009-10-24 19:23:20 +05:30
|
|
|
"""
|
2009-10-25 19:22:29 +05:30
|
|
|
return self.__pgr.mapservice_plugins()
|
2009-02-03 03:25:22 +05:30
|
|
|
|
2009-10-24 19:23:20 +05:30
|
|
|
def get_reg_bookitems(self):
|
2009-10-25 19:22:29 +05:30
|
|
|
""" Return list of reports registered as bookitem
|
2009-10-24 19:23:20 +05:30
|
|
|
"""
|
2009-10-25 19:22:29 +05:30
|
|
|
return self.__pgr.bookitem_plugins()
|
2008-05-19 00:54:28 +05:30
|
|
|
|
2009-10-25 20:12:47 +05:30
|
|
|
def get_reg_gramplets(self):
|
|
|
|
""" Return list of non hidden gramplets.
|
|
|
|
"""
|
2009-10-25 21:03:50 +05:30
|
|
|
return self.__pgr.gramplet_plugins()
|
2009-10-25 20:12:47 +05:30
|
|
|
|
2009-02-05 07:53:46 +05:30
|
|
|
def get_external_opt_dict(self):
|
|
|
|
""" Return the dictionary of external options. """
|
|
|
|
return self.__external_opt_dict
|
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
def get_module_description(self, module):
|
|
|
|
""" Given a module name, return the module description. """
|
|
|
|
return self.__mod2text.get(module, '')
|
2008-10-14 08:04:28 +05:30
|
|
|
|
2009-10-25 19:22:29 +05:30
|
|
|
def get_reg_importers(self):
|
|
|
|
""" Return list of registered importers
|
|
|
|
"""
|
|
|
|
return self.__pgr.import_plugins()
|
|
|
|
|
|
|
|
def get_reg_exporters(self):
|
|
|
|
""" Return list of registered exporters
|
|
|
|
"""
|
|
|
|
return self.__pgr.export_plugins()
|
|
|
|
|
|
|
|
def get_reg_docgens(self):
|
|
|
|
""" Return list of registered docgen
|
|
|
|
"""
|
|
|
|
return self.__pgr.docgen_plugins()
|
|
|
|
|
2008-10-14 08:04:28 +05:30
|
|
|
def get_import_plugins(self):
|
|
|
|
"""
|
|
|
|
Get the list of import plugins.
|
|
|
|
|
|
|
|
@return: [gen.plug.ImportPlugin] (a list of ImportPlugin instances)
|
|
|
|
"""
|
2009-10-24 19:23:20 +05:30
|
|
|
## TODO: would it not be better to remove ImportPlugin and use
|
|
|
|
## only PluginData, loading from module when importfunction needed?
|
|
|
|
if self.__import_plugins == []:
|
|
|
|
#The module still needs to be imported
|
2009-10-25 19:22:29 +05:30
|
|
|
for pdata in self.get_reg_importers():
|
2009-10-24 19:23:20 +05:30
|
|
|
mod = self.load_plugin(pdata)
|
|
|
|
if mod:
|
|
|
|
imp = gen.plug.ImportPlugin(name=pdata.name,
|
|
|
|
description = pdata.description,
|
|
|
|
import_function = eval('mod.' + pdata.import_function),
|
|
|
|
extension = pdata.extension)
|
|
|
|
self.__import_plugins.append(imp)
|
|
|
|
|
2008-10-14 08:04:28 +05:30
|
|
|
return self.__import_plugins
|
2008-11-04 09:42:51 +05:30
|
|
|
|
|
|
|
def get_export_plugins(self):
|
|
|
|
"""
|
|
|
|
Get the list of export plugins.
|
|
|
|
|
|
|
|
@return: [gen.plug.ExportPlugin] (a list of ExportPlugin instances)
|
|
|
|
"""
|
2009-10-24 19:23:20 +05:30
|
|
|
## TODO: would it not be better to remove ExportPlugin and use
|
|
|
|
## only PluginData, loading from module when export/options needed?
|
|
|
|
if self.__export_plugins == []:
|
|
|
|
#The modules still need to be imported
|
2009-10-25 19:22:29 +05:30
|
|
|
for pdata in self.get_reg_exporters():
|
2009-10-24 19:23:20 +05:30
|
|
|
mod = self.load_plugin(pdata)
|
|
|
|
if mod:
|
|
|
|
exp = gen.plug.ExportPlugin(name=pdata.name,
|
|
|
|
description = pdata.description,
|
|
|
|
export_function = eval('mod.' + pdata.export_function),
|
|
|
|
extension = pdata.extension,
|
|
|
|
config = (pdata.export_options_title,
|
|
|
|
eval('mod.' + pdata.export_options)))
|
|
|
|
self.__export_plugins.append(exp)
|
|
|
|
|
2008-11-04 09:42:51 +05:30
|
|
|
return self.__export_plugins
|
2009-03-19 07:54:29 +05:30
|
|
|
|
|
|
|
def get_docgen_plugins(self):
|
|
|
|
"""
|
|
|
|
Get the list of docgen plugins.
|
|
|
|
|
|
|
|
@return: [gen.plug.DocGenPlugin] (a list of DocGenPlugin instances)
|
|
|
|
"""
|
2009-10-24 19:23:20 +05:30
|
|
|
## TODO: would it not be better to return list of plugindata, and only
|
|
|
|
## import those docgen that will then actuallly be needed?
|
|
|
|
## So, only do import when docgen.get_basedoc() is requested
|
|
|
|
if self.__docgen_plugins == []:
|
|
|
|
#The modules still need to be imported
|
2009-10-25 19:22:29 +05:30
|
|
|
for pdata in self.get_reg_docgens():
|
2009-10-24 19:23:20 +05:30
|
|
|
mod = self.load_plugin(pdata)
|
|
|
|
if mod:
|
|
|
|
dgp = gen.plug.DocGenPlugin(name=pdata.name,
|
|
|
|
description = pdata.description,
|
|
|
|
basedoc = eval('mod.' + pdata.basedocclass),
|
|
|
|
paper = pdata.paper,
|
|
|
|
style = pdata.style,
|
|
|
|
extension = pdata.extension )
|
|
|
|
self.__docgen_plugins.append(dgp)
|
|
|
|
|
2009-03-19 07:54:29 +05:30
|
|
|
return self.__docgen_plugins
|
2008-05-19 00:54:28 +05:30
|
|
|
|
2009-02-05 07:53:46 +05:30
|
|
|
def register_option(self, option, guioption):
|
|
|
|
"""
|
|
|
|
Register an external option.
|
|
|
|
|
|
|
|
Register a mapping from option to guioption for an option
|
|
|
|
that is not native to Gramps but provided by the plugin writer.
|
|
|
|
This should typically be called during initialisation of a
|
|
|
|
ReportOptions class.
|
|
|
|
@param option: the option class
|
|
|
|
@type option: class that inherits from gen.plug.menu.Option
|
|
|
|
@param guioption: the gui-option class
|
|
|
|
@type guioption: class that inherits from gtk.Widget.
|
|
|
|
"""
|
|
|
|
self.__external_opt_dict[option] = guioption;
|
|
|
|
|
2008-05-19 00:54:28 +05:30
|
|
|
def __purge_failed(self):
|
|
|
|
"""
|
|
|
|
Purge the failed plugins from the corresponding lists.
|
|
|
|
"""
|
|
|
|
failed_module_names = [
|
|
|
|
os.path.splitext(os.path.basename(filename))[0]
|
|
|
|
for filename, junk in self.__failmsg_list
|
|
|
|
]
|
2009-10-24 19:23:20 +05:30
|
|
|
|
2008-11-04 09:42:51 +05:30
|
|
|
self.__export_plugins[:] = [ item for item in self.__export_plugins
|
2009-01-30 07:46:00 +05:30
|
|
|
if item.get_module_name() not in failed_module_names ][:]
|
2008-10-14 08:04:28 +05:30
|
|
|
self.__import_plugins[:] = [ item for item in self.__import_plugins
|
2009-01-30 07:46:00 +05:30
|
|
|
if item.get_module_name() not in failed_module_names ][:]
|
2009-03-19 07:54:29 +05:30
|
|
|
self.__docgen_plugins[:] = [ item for item in self.__docgen_plugins
|
|
|
|
if item.get_module_name() not in failed_module_names ][:]
|