3292: register plugins, load on need, not on start of GRAMPS - GEPS 014
svn: r13400
This commit is contained in:
@@ -22,11 +22,27 @@ The "plug" package for handling plugins in Gramps.
|
||||
"""
|
||||
|
||||
from _plugin import Plugin
|
||||
from _pluginreg import (PluginData, PluginRegister, REPORT, TOOL,
|
||||
CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
|
||||
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ,
|
||||
TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL,
|
||||
TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON,
|
||||
CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE,
|
||||
CATEGORY_QR_PLACE, CATEGORY_QR_REPOSITORY, CATEGORY_QR_NOTE,
|
||||
CATEGORY_QR_DATE )
|
||||
from _manager import PluginManager
|
||||
from _import import ImportPlugin
|
||||
from _export import ExportPlugin
|
||||
from _docgenplugin import DocGenPlugin
|
||||
from utils import *
|
||||
|
||||
__all__ = [ "docbackend", "docgen", "menu", Plugin, PluginManager,
|
||||
ImportPlugin, ExportPlugin, DocGenPlugin ]
|
||||
__all__ = [ "docbackend", "docgen", "menu", Plugin, PluginData,
|
||||
PluginRegister, PluginManager,
|
||||
ImportPlugin, ExportPlugin, DocGenPlugin,
|
||||
REPORT, TOOL, CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
|
||||
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ,
|
||||
TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL,
|
||||
TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON,
|
||||
CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE,
|
||||
CATEGORY_QR_PLACE, CATEGORY_QR_REPOSITORY, CATEGORY_QR_NOTE,
|
||||
CATEGORY_QR_DATE]
|
||||
|
@@ -46,6 +46,7 @@ from gettext import gettext as _
|
||||
#-------------------------------------------------------------------------
|
||||
import gen.utils
|
||||
import Relationship
|
||||
from gen.plug import PluginRegister
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -65,15 +66,6 @@ class PluginManager(gen.utils.Callback):
|
||||
|
||||
__signals__ = { 'plugins-reloaded' : None }
|
||||
|
||||
# Modes for generating reports
|
||||
REPORT_MODE_GUI = 1 # Standalone report using GUI
|
||||
REPORT_MODE_BKI = 2 # Book Item interface using GUI
|
||||
REPORT_MODE_CLI = 4 # Command line interface (CLI)
|
||||
|
||||
# Modes for running tools
|
||||
TOOL_MODE_GUI = 1 # Standard tool using GUI
|
||||
TOOL_MODE_CLI = 2 # Command line interface (CLI)
|
||||
|
||||
def get_instance():
|
||||
""" Use this function to get the instance of the PluginManager """
|
||||
if PluginManager.__instance is None:
|
||||
@@ -89,72 +81,75 @@ class PluginManager(gen.utils.Callback):
|
||||
"Use the get_instance() method")
|
||||
|
||||
gen.utils.Callback.__init__(self)
|
||||
|
||||
self.__report_list = []
|
||||
self.__quick_report_list = []
|
||||
self.__tool_list = []
|
||||
|
||||
self.__import_plugins = []
|
||||
self.__export_plugins = []
|
||||
self.__docgen_plugins = []
|
||||
self.__general_plugins = []
|
||||
self.__mapservice_list = []
|
||||
|
||||
self.__attempt_list = []
|
||||
self.__loaddir_list = []
|
||||
self.__failmsg_list = []
|
||||
self.__bkitems_list = []
|
||||
self.__cl_list = []
|
||||
self.__cli_tool_list = []
|
||||
self.__external_opt_dict = {}
|
||||
self.__success_list = []
|
||||
self.__relcalc_class = Relationship.RelationshipCalculator
|
||||
|
||||
self.__mod2text = {}
|
||||
|
||||
def load_plugins(self, direct):
|
||||
"""
|
||||
Searches the specified directory, and attempts to load any python
|
||||
modules that it finds, adding name to the attempt_lists list. If the
|
||||
module successfully loads, it is added to the success_list list.
|
||||
Each plugin is responsible for registering itself in the correct
|
||||
manner. No attempt is done in this routine to register the tasks.
|
||||
Returns True on error.
|
||||
self.__pgr = PluginRegister.get_instance()
|
||||
self.__registereddir_set = set()
|
||||
self.__loaded_plugins = {}
|
||||
|
||||
def reg_plugins(self, direct):
|
||||
"""
|
||||
Searches the specified directory, and registers python plugin that
|
||||
are being defined in gpr.py files.
|
||||
|
||||
If a relationship calculator for env var LANG is present, it is
|
||||
immediately loaded so it is available for all.
|
||||
"""
|
||||
# if the directory does not exist, do nothing
|
||||
if not os.path.isdir(direct):
|
||||
return False # return value is True for error
|
||||
|
||||
pymod = re.compile(r"^(.*)\.py$")
|
||||
|
||||
# loop through each file in the directory, looking for files that
|
||||
# have a .py extention, and attempt to load the file. If it succeeds,
|
||||
# add it to the success_list list. If it fails, add it to the _failure
|
||||
# list
|
||||
|
||||
for (dirpath, dirnames, filenames) in os.walk(direct):
|
||||
# add the directory to the python search path
|
||||
sys.path.append(dirpath)
|
||||
|
||||
for (dirpath, dirnames, filenames) in os.walk(direct):
|
||||
# if the path has not already been loaded, save it in the
|
||||
# loaddir_list list for use on reloading.
|
||||
if dirpath not in self.__loaddir_list:
|
||||
self.__loaddir_list.append(dirpath)
|
||||
|
||||
for filename in filenames:
|
||||
name = os.path.split(filename)
|
||||
match = pymod.match(name[1])
|
||||
if not match:
|
||||
continue
|
||||
self.__attempt_list.append(filename)
|
||||
plugin = match.groups()[0]
|
||||
try:
|
||||
_module = __import__(plugin)
|
||||
self.__success_list.append((filename, _module))
|
||||
except:
|
||||
self.__failmsg_list.append((filename, sys.exc_info()))
|
||||
|
||||
return len(self.__failmsg_list) != 0 # return True if there are errors
|
||||
# registereddir_list list for use on reloading.
|
||||
self.__registereddir_set.add(dirpath)
|
||||
self.__pgr.scan_dir(dirpath)
|
||||
|
||||
# set correct relationship calculator based on LANG
|
||||
for plugin in self.__pgr.relcalc_plugins():
|
||||
if os.environ["LANG"] in plugin.lang_list:
|
||||
#the loaded module is put in variable mod
|
||||
mod = self.load_plugin(plugin)
|
||||
if mod:
|
||||
self.__relcalc_class = eval('mod.' +
|
||||
plugin.relcalcclass)
|
||||
break
|
||||
# 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
|
||||
|
||||
def reload_plugins(self):
|
||||
""" Reload previously loaded plugins """
|
||||
@@ -199,26 +194,7 @@ class PluginManager(gen.utils.Callback):
|
||||
self.__success_list.append((filename, _module))
|
||||
except:
|
||||
self.__failmsg_list.append((filename, sys.exc_info()))
|
||||
|
||||
# attempt to load any new files found
|
||||
for directory in self.__loaddir_list:
|
||||
for filename in os.listdir(directory):
|
||||
name = os.path.split(filename)
|
||||
match = pymod.match(name[1])
|
||||
if not match:
|
||||
continue
|
||||
if filename in self.__attempt_list:
|
||||
continue
|
||||
self.__attempt_list.append(filename)
|
||||
plugin = match.groups()[0]
|
||||
try:
|
||||
_module = __import__(plugin)
|
||||
if _module not in [plugin[1]
|
||||
for plugin in self.__success_list]:
|
||||
self.__success_list.append((filename, _module))
|
||||
except:
|
||||
self.__failmsg_list.append((filename, sys.exc_info()))
|
||||
|
||||
|
||||
self.emit('plugins-reloaded')
|
||||
|
||||
def get_fail_list(self):
|
||||
@@ -228,34 +204,35 @@ class PluginManager(gen.utils.Callback):
|
||||
def get_success_list(self):
|
||||
""" Return the list of succeeded plugins. """
|
||||
return self.__success_list
|
||||
|
||||
def get_report_list(self):
|
||||
""" Return the list of report plugins. """
|
||||
return self.__report_list
|
||||
|
||||
def get_tool_list(self):
|
||||
""" Return the list of tool plugins. """
|
||||
return self.__tool_list
|
||||
|
||||
def get_quick_report_list(self):
|
||||
""" Return the list of quick report plugins. """
|
||||
return self.__quick_report_list
|
||||
|
||||
def get_mapservice_list(self):
|
||||
""" Return the list of map services"""
|
||||
return self.__mapservice_list
|
||||
|
||||
def get_book_item_list(self):
|
||||
""" Return the list of book plugins. """
|
||||
return self.__bkitems_list
|
||||
def get_reg_reports(self, gui=True):
|
||||
""" Return list of registered reports
|
||||
:Param gui: bool indicating if GUI reports or CLI reports must be
|
||||
returned
|
||||
"""
|
||||
return self.__pgr.report_plugins(gui)
|
||||
|
||||
def get_cl_list(self):
|
||||
""" Return the list of command line report plugins. """
|
||||
return self.__cl_list
|
||||
def get_reg_tools(self, gui=True):
|
||||
""" Return list of registered tools
|
||||
:Param gui: bool indicating if GUI reports or CLI reports must be
|
||||
returned
|
||||
"""
|
||||
return self.__pgr.tool_plugins(gui)
|
||||
|
||||
def get_cl_tool_list(self):
|
||||
""" Return the list of command line tool plugins. """
|
||||
return self.__cli_tool_list
|
||||
def get_reg_quick_reports(self):
|
||||
""" Return list of registered quick reports
|
||||
"""
|
||||
return self.__pgr.quickreport_plugins()
|
||||
|
||||
def get_reg_mapservices(self):
|
||||
""" Return list of registered mapservices
|
||||
"""
|
||||
return self.__pgr.mapservice_plugins()
|
||||
|
||||
def get_reg_bookitems(self):
|
||||
""" Return list of reports registered as bookitem
|
||||
"""
|
||||
return self.__pgr.bookitem_plugins()
|
||||
|
||||
def get_external_opt_dict(self):
|
||||
""" Return the dictionary of external options. """
|
||||
@@ -265,29 +242,26 @@ class PluginManager(gen.utils.Callback):
|
||||
""" Given a module name, return the module description. """
|
||||
return self.__mod2text.get(module, '')
|
||||
|
||||
def register_plugin(self, plugin):
|
||||
"""
|
||||
@param plugin: The plugin to be registered.
|
||||
@type plugin: gen.plug.Plugin
|
||||
@return: nothing
|
||||
"""
|
||||
if isinstance(plugin, gen.plug.ImportPlugin):
|
||||
self.__import_plugins.append(plugin)
|
||||
elif isinstance(plugin, gen.plug.ExportPlugin):
|
||||
self.__export_plugins.append(plugin)
|
||||
elif isinstance(plugin, gen.plug.DocGenPlugin):
|
||||
self.__docgen_plugins.append(plugin)
|
||||
elif isinstance(plugin, gen.plug.Plugin):
|
||||
self.__general_plugins.append(plugin)
|
||||
|
||||
self.__mod2text[plugin.get_module_name()] = plugin.get_description()
|
||||
|
||||
def get_import_plugins(self):
|
||||
"""
|
||||
Get the list of import plugins.
|
||||
|
||||
@return: [gen.plug.ImportPlugin] (a list of ImportPlugin instances)
|
||||
"""
|
||||
## 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
|
||||
imps = self.__pgr.import_plugins()
|
||||
for pdata in imps:
|
||||
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)
|
||||
|
||||
return self.__import_plugins
|
||||
|
||||
def get_export_plugins(self):
|
||||
@@ -296,6 +270,22 @@ class PluginManager(gen.utils.Callback):
|
||||
|
||||
@return: [gen.plug.ExportPlugin] (a list of ExportPlugin instances)
|
||||
"""
|
||||
## 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
|
||||
exps = self.__pgr.export_plugins()
|
||||
for pdata in exps:
|
||||
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)
|
||||
|
||||
return self.__export_plugins
|
||||
|
||||
def get_docgen_plugins(self):
|
||||
@@ -304,211 +294,25 @@ class PluginManager(gen.utils.Callback):
|
||||
|
||||
@return: [gen.plug.DocGenPlugin] (a list of DocGenPlugin instances)
|
||||
"""
|
||||
## 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
|
||||
dgdps = self.__pgr.docgen_plugins()
|
||||
for pdata in dgdps:
|
||||
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)
|
||||
|
||||
return self.__docgen_plugins
|
||||
|
||||
def register_tool(self, name, category, tool_class, options_class,
|
||||
modes, translated_name, status=_("Unknown"),
|
||||
description=_UNAVAILABLE, author_name=_("Unknown"),
|
||||
author_email=_("Unknown"), unsupported=False,
|
||||
require_active=True ):
|
||||
"""
|
||||
Register a tool with the plugin system.
|
||||
|
||||
This function should be used to register tool in GUI and/or
|
||||
command-line mode.
|
||||
"""
|
||||
(junk, gui_task) = divmod(modes, 2**PluginManager.TOOL_MODE_GUI)
|
||||
if gui_task:
|
||||
self.__register_gui_tool(tool_class, options_class, translated_name,
|
||||
name, category, description,
|
||||
status, author_name, author_email, unsupported,
|
||||
require_active)
|
||||
|
||||
(junk, cli_task) = divmod(modes-gui_task,
|
||||
2**PluginManager.TOOL_MODE_CLI)
|
||||
if cli_task:
|
||||
self.__register_cli_tool(name, category, tool_class, options_class,
|
||||
translated_name, unsupported)
|
||||
|
||||
def __register_gui_tool(self, tool_class, options_class, translated_name,
|
||||
name, category, description=_UNAVAILABLE,
|
||||
status=_("Unknown"), author_name=_("Unknown"),
|
||||
author_email=_("Unknown"), unsupported=False,
|
||||
require_active=True):
|
||||
"""
|
||||
Register a GUI tool.
|
||||
"""
|
||||
del_index = -1
|
||||
for i in range(0, len(self.__tool_list)):
|
||||
val = self.__tool_list[i]
|
||||
if val[4] == name:
|
||||
del_index = i
|
||||
if del_index != -1:
|
||||
del self.__tool_list[del_index]
|
||||
self.__mod2text[tool_class.__module__] = description
|
||||
self.__tool_list.append( (tool_class, options_class, translated_name,
|
||||
category, name, description, status,
|
||||
author_name, author_email, unsupported,
|
||||
require_active) )
|
||||
|
||||
def __register_cli_tool(self, name, category, tool_class, options_class,
|
||||
translated_name, unsupported=False):
|
||||
"""
|
||||
Register a CLI tool.
|
||||
"""
|
||||
del_index = -1
|
||||
for i in range(0, len(self.__cli_tool_list)):
|
||||
val = self.__cli_tool_list[i]
|
||||
if val[0] == name:
|
||||
del_index = i
|
||||
if del_index != -1:
|
||||
del self.__cli_tool_list[del_index]
|
||||
self.__cli_tool_list.append( (name, category, tool_class, options_class,
|
||||
translated_name, unsupported, None) )
|
||||
|
||||
def register_report(self, name, category, report_class, options_class,
|
||||
modes, translated_name, status=_("Unknown"),
|
||||
description=_UNAVAILABLE, author_name=_("Unknown"),
|
||||
author_email=_("Unknown"), unsupported=False,
|
||||
require_active=True):
|
||||
"""
|
||||
Registers report for all possible flavors.
|
||||
|
||||
This function should be used to register report as a stand-alone,
|
||||
book item, or command-line flavor in any combination of those.
|
||||
The low-level functions (starting with '_') should not be used
|
||||
on their own. Instead, this function will call them as needed.
|
||||
"""
|
||||
(junk, standalone_task) = divmod(modes,
|
||||
2**PluginManager.REPORT_MODE_GUI)
|
||||
if standalone_task:
|
||||
self.__register_standalone(report_class, options_class,
|
||||
translated_name, name, category,
|
||||
description, status, author_name,
|
||||
author_email, unsupported,
|
||||
require_active)
|
||||
|
||||
(junk, book_item_task) = divmod(modes-standalone_task,
|
||||
2**PluginManager.REPORT_MODE_BKI)
|
||||
if book_item_task:
|
||||
book_item_category = category
|
||||
self.__register_book_item(translated_name, book_item_category,
|
||||
report_class, options_class, name,
|
||||
unsupported, require_active)
|
||||
|
||||
(junk, command_line_task) = divmod(modes-standalone_task-book_item_task,
|
||||
2**PluginManager.REPORT_MODE_CLI)
|
||||
if command_line_task:
|
||||
self.__register_cl_report(name, category, report_class,
|
||||
options_class, translated_name,
|
||||
unsupported, require_active)
|
||||
|
||||
def __register_standalone(self, report_class, options_class,
|
||||
translated_name, name, category,
|
||||
description=_UNAVAILABLE, status=_("Unknown"),
|
||||
author_name=_("Unknown"),
|
||||
author_email=_("Unknown"), unsupported=False,
|
||||
require_active=True):
|
||||
"""
|
||||
Register a report with the plugin system.
|
||||
"""
|
||||
del_index = -1
|
||||
for i in range(0, len(self.__report_list)):
|
||||
val = self.__report_list[i]
|
||||
if val[4] == name:
|
||||
del_index = i
|
||||
if del_index != -1:
|
||||
del self.__report_list[del_index]
|
||||
|
||||
self.__report_list.append( (report_class, options_class,
|
||||
translated_name, category, name,
|
||||
description, status, author_name,
|
||||
author_email, unsupported, require_active) )
|
||||
self.__mod2text[report_class.__module__] = description
|
||||
|
||||
def __register_book_item(self, translated_name, category, report_class,
|
||||
option_class, name, unsupported, require_active):
|
||||
"""
|
||||
Register a book item.
|
||||
"""
|
||||
del_index = -1
|
||||
for i in range(0, len(self.__bkitems_list)):
|
||||
val = self.__bkitems_list[i]
|
||||
if val[4] == name:
|
||||
del_index = i
|
||||
if del_index != -1:
|
||||
del self.__bkitems_list[del_index]
|
||||
|
||||
self.__bkitems_list.append( (translated_name, category, report_class,
|
||||
option_class, name, unsupported,
|
||||
require_active) )
|
||||
|
||||
def __register_cl_report(self, name, category, report_class, options_class,
|
||||
translated_name, unsupported, require_active):
|
||||
"""
|
||||
Register a command line report.
|
||||
"""
|
||||
del_index = -1
|
||||
for i in range(0, len(self.__cl_list)):
|
||||
val = self.__cl_list[i]
|
||||
if val[0] == name:
|
||||
del_index = i
|
||||
if del_index != -1:
|
||||
del self.__cl_list[del_index]
|
||||
self.__cl_list.append( (name, category, report_class, options_class,
|
||||
translated_name, unsupported, require_active) )
|
||||
|
||||
def register_quick_report(self, name, category, run_func, translated_name,
|
||||
status=_("Unknown"), description=_UNAVAILABLE,
|
||||
author_name=_("Unknown"),
|
||||
author_email=_("Unknown"), unsupported=False ):
|
||||
"""
|
||||
Registers quick report for all possible objects.
|
||||
|
||||
This function should be used to register a quick report
|
||||
so it appears in the quick report context menu of the object it is
|
||||
attached to.
|
||||
The low-level functions (starting with '_') should not be used
|
||||
on their own. Instead, this function will call them as needed.
|
||||
"""
|
||||
del_index = -1
|
||||
for i in range(0, len(self.__quick_report_list)):
|
||||
val = self.__quick_report_list[i]
|
||||
if val[3] == name:
|
||||
del_index = i
|
||||
if del_index != -1:
|
||||
del self.__quick_report_list[del_index]
|
||||
|
||||
self.__quick_report_list.append( (run_func, translated_name,
|
||||
category, name, description, status,
|
||||
author_name, author_email, unsupported))
|
||||
|
||||
self.__mod2text[run_func.__module__] = description
|
||||
|
||||
def register_mapservice(self, name, mapservice, translated_name,
|
||||
status=_("Unknown"), tooltip=_UNAVAILABLE,
|
||||
author_name=_("Unknown"),
|
||||
author_email=_("Unknown"), unsupported=False ):
|
||||
"""
|
||||
Register map services for the place view.
|
||||
A map service is a MapService class. The class can be called with a
|
||||
list of (place handle, description) values, and manipulate this data
|
||||
to show on a map.
|
||||
"""
|
||||
del_index = -1
|
||||
for i in range(0, len(self.__mapservice_list)):
|
||||
val = self.__mapservice_list[i]
|
||||
if val[2] == name:
|
||||
del_index = i
|
||||
if del_index != -1:
|
||||
del self.__mapservice_list[del_index]
|
||||
|
||||
self.__mapservice_list.append( (mapservice, translated_name,
|
||||
name, tooltip, status,
|
||||
author_name, author_email, unsupported))
|
||||
|
||||
self.__mod2text[mapservice.__module__] = tooltip
|
||||
|
||||
def register_option(self, option, guioption):
|
||||
"""
|
||||
Register an external option.
|
||||
@@ -532,38 +336,13 @@ class PluginManager(gen.utils.Callback):
|
||||
os.path.splitext(os.path.basename(filename))[0]
|
||||
for filename, junk in self.__failmsg_list
|
||||
]
|
||||
|
||||
self.__general_plugins[:] = [ item for item in self.__export_plugins
|
||||
if item.get_module_name() not in self.__general_plugins ][:]
|
||||
|
||||
self.__export_plugins[:] = [ item for item in self.__export_plugins
|
||||
if item.get_module_name() not in failed_module_names ][:]
|
||||
self.__import_plugins[:] = [ item for item in self.__import_plugins
|
||||
if item.get_module_name() not in failed_module_names ][:]
|
||||
self.__docgen_plugins[:] = [ item for item in self.__docgen_plugins
|
||||
if item.get_module_name() not in failed_module_names ][:]
|
||||
self.__tool_list[:] = [ item for item in self.__tool_list
|
||||
if item[0].__module__ not in failed_module_names ][:]
|
||||
self.__cli_tool_list[:] = [ item for item in self.__cli_tool_list
|
||||
if item[2].__module__ not in failed_module_names ][:]
|
||||
self.__report_list[:] = [ item for item in self.__report_list
|
||||
if item[0].__module__ not in failed_module_names ][:]
|
||||
self.__quick_report_list[:] = \
|
||||
[ item for item in self.__quick_report_list
|
||||
if item[0].__module__ not in failed_module_names ][:]
|
||||
self.__bkitems_list[:] = [ item for item in self.__bkitems_list
|
||||
if item[2].__module__ not in failed_module_names ][:]
|
||||
self.__cl_list[:] = [ item for item in self.__cl_list
|
||||
if item[2].__module__ not in failed_module_names ][:]
|
||||
|
||||
def register_relcalc(self, relclass, languages):
|
||||
"""
|
||||
Register a relationship calculator.
|
||||
"""
|
||||
try:
|
||||
if os.environ["LANG"] in languages:
|
||||
self.__relcalc_class = relclass
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_relationship_calculator(self):
|
||||
"""
|
||||
|
@@ -2,6 +2,7 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
# Copyright (C) 2009 Benny Malengier
|
||||
#
|
||||
# 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
|
||||
@@ -21,8 +22,8 @@
|
||||
|
||||
"""
|
||||
This module provides the base class for plugins.
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
class Plugin(object):
|
||||
"""
|
||||
This class serves as a base class for all plugins that can be registered
|
||||
|
913
src/gen/plug/_pluginreg.py
Normal file
913
src/gen/plug/_pluginreg.py
Normal file
@@ -0,0 +1,913 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Benny Malengier
|
||||
#
|
||||
# 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: _plugin.py 12559 2009-05-21 17:19:50Z gbritton $
|
||||
|
||||
"""
|
||||
This module provides the base class for plugin registration.
|
||||
It provides an object containing data about the plugin (version, filename, ...)
|
||||
and a register for the data of all plugins .
|
||||
"""
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Standard Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import traceback
|
||||
from gettext import gettext as _
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from const import VERSION as GRAMPSVERSION
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# PluginData
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#a plugin is stable or unstable
|
||||
STABLE = 0
|
||||
UNSTABLE = 1
|
||||
STATUS = [STABLE, UNSTABLE]
|
||||
STATUSTEXT = {STABLE: _('Stable'), UNSTABLE: _('Unstable')}
|
||||
#possible plugin types
|
||||
REPORT = 0
|
||||
QUICKREPORT = 1
|
||||
TOOL = 2
|
||||
IMPORT = 3
|
||||
EXPORT = 4
|
||||
DOCGEN = 5
|
||||
GENERAL = 6
|
||||
MAPSERVICE = 7
|
||||
VIEW = 8
|
||||
RELCALC = 9
|
||||
GRAMPLET = 10
|
||||
PTYPE = [ REPORT , QUICKREPORT, TOOL, IMPORT,
|
||||
EXPORT, DOCGEN, GENERAL, MAPSERVICE, VIEW, RELCALC, GRAMPLET]
|
||||
|
||||
#possible report categories
|
||||
CATEGORY_TEXT = 0
|
||||
CATEGORY_DRAW = 1
|
||||
CATEGORY_CODE = 2
|
||||
CATEGORY_WEB = 3
|
||||
CATEGORY_BOOK = 4
|
||||
CATEGORY_GRAPHVIZ = 5
|
||||
REPORT_CAT = [ CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
|
||||
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ]
|
||||
#possible tool categories
|
||||
TOOL_DEBUG = -1
|
||||
TOOL_ANAL = 0
|
||||
TOOL_DBPROC = 1
|
||||
TOOL_DBFIX = 2
|
||||
TOOL_REVCTL = 3
|
||||
TOOL_UTILS = 4
|
||||
TOOL_CAT = [ TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL,
|
||||
TOOL_UTILS]
|
||||
|
||||
#possible quickreport categories
|
||||
CATEGORY_QR_MISC = -1
|
||||
CATEGORY_QR_PERSON = 0
|
||||
CATEGORY_QR_FAMILY = 1
|
||||
CATEGORY_QR_EVENT = 2
|
||||
CATEGORY_QR_SOURCE = 3
|
||||
CATEGORY_QR_PLACE = 4
|
||||
CATEGORY_QR_REPOSITORY = 5
|
||||
CATEGORY_QR_NOTE = 6
|
||||
CATEGORY_QR_DATE = 7
|
||||
|
||||
# Modes for generating reports
|
||||
REPORT_MODE_GUI = 1 # Standalone report using GUI
|
||||
REPORT_MODE_BKI = 2 # Book Item interface using GUI
|
||||
REPORT_MODE_CLI = 4 # Command line interface (CLI)
|
||||
REPORT_MODES = [REPORT_MODE_GUI, REPORT_MODE_BKI, REPORT_MODE_CLI]
|
||||
|
||||
# Modes for running tools
|
||||
TOOL_MODE_GUI = 1 # Standard tool using GUI
|
||||
TOOL_MODE_CLI = 2 # Command line interface (CLI)
|
||||
TOOL_MODES = [TOOL_MODE_GUI, TOOL_MODE_CLI]
|
||||
|
||||
class PluginData(object):
|
||||
"""
|
||||
This is the base class for all plugin data objects.
|
||||
The workflow is:
|
||||
1. plugin manager reads all register files, and stores plugin data
|
||||
objects in a plugin register
|
||||
2. when plugin is needed, the plugin register creates the plugin, and
|
||||
the manager stores this, after which it can be executed.
|
||||
|
||||
Attributes present for all plugins
|
||||
.. attribute:: id
|
||||
A unique identifier for the plugin. This is eg used to store the plugin
|
||||
settings.
|
||||
.. attribute:: name
|
||||
A friendly name to call this plugin (normally translated)
|
||||
.. attribute:: description
|
||||
A friendly description of what the plugin does
|
||||
.. attribute:: version
|
||||
The version of the plugin
|
||||
.. attribute:: status
|
||||
The status of the plugin, STABLE or UNSTABLE
|
||||
UNSTABLE is only visible in development code, not in release
|
||||
.. attribute:: fname
|
||||
The python file where the plugin implementation can be found
|
||||
.. attribute:: ptype
|
||||
The plugin type. One of REPORT , QUICKREPORT, TOOL, IMPORT,
|
||||
EXPORT, DOCGEN, GENERAL, MAPSERVICE, VIEW, GRAMPLET
|
||||
.. attribute:: authors
|
||||
List of authors of the plugin, default=[]
|
||||
.. attribute:: authors_email
|
||||
List of emails of the authors of the plugin, default=[]
|
||||
.. attribute:: supported
|
||||
Bool value indicating if the plugin is still supported, default=True
|
||||
.. attribute:: load_on_reg
|
||||
bool value, if True, the plugin is loaded on GRAMPS startup. Some
|
||||
plugins. Only set this value if for testing you want the plugin to be
|
||||
loaded immediately on startup. default=False
|
||||
|
||||
Attributes for RELCALC plugins:
|
||||
.. attribute:: relcalcclass
|
||||
The class in the module that is the relationcalc class
|
||||
.. attribute:: lang_list
|
||||
List of languages this plugin handles
|
||||
|
||||
Attributes for REPORT plugins:
|
||||
.. attribute:: require_active
|
||||
Bool, If the reports requries an active person to be set or not
|
||||
.. attribute:: reportclass
|
||||
The class in the module that is the report class
|
||||
.. attribute:: report_modes
|
||||
The report modes: list of REPORT_MODE_GUI ,REPORT_MODE_BKI,REPORT_MODE_CLI
|
||||
|
||||
Attributes for REPORT and TOOL and QUICKREPORT plugins
|
||||
.. attribute:: category
|
||||
Or the report category the plugin belongs to, default=CATEGORY_TEXT
|
||||
or the tool category a plugin belongs to, default=TOOL_UTILS
|
||||
or the quickreport category a plugin belongs to, default=CATEGORY_QR_PERSON
|
||||
|
||||
Attributes for REPORT and TOOL plugins
|
||||
.. attribute:: optionclass
|
||||
The class in the module that is the option class
|
||||
|
||||
Attributes for TOOL plugins
|
||||
.. attribute:: toolclass
|
||||
The class in the module that is the tool class
|
||||
.. attribute:: tool_modes
|
||||
The tool modes: list of TOOL_MODE_GUI, TOOL_MODE_CLI
|
||||
|
||||
Attributes for DOCGEN plugins
|
||||
.. attribute :: basedocclass
|
||||
The class in the module that is the BaseDoc defined
|
||||
.. attribute :: paper
|
||||
bool, Indicates whether the plugin uses paper or not, default=True
|
||||
.. attribute :: style
|
||||
bool, Indicates whether the plugin uses styles or not, default=True
|
||||
|
||||
Attribute for DOCGEN, EXPORT plugins
|
||||
.. attribute :: extension
|
||||
str, The file extension to use for output produced by the docgen/export,
|
||||
default=''
|
||||
|
||||
Attributes for QUICKREPORT plugins
|
||||
.. attribute:: runfunc
|
||||
The function that executes the quick report
|
||||
|
||||
Attributes for MAPSERVICE plugins
|
||||
.. attribute:: mapservice
|
||||
The class in the module that is a mapservice
|
||||
|
||||
Attributes for EXPORT plugins
|
||||
.. attribute:: export_function
|
||||
Function that produces the export
|
||||
.. attribute:: export_options
|
||||
Class to set options
|
||||
.. attribute:: export_options_title
|
||||
Title for the option page
|
||||
|
||||
Attributes for IMPORT plugins
|
||||
.. attribute:: import_function
|
||||
Function that starts an import
|
||||
|
||||
Attributes for GRAMPLET plugins
|
||||
.. attribute:: gramplet
|
||||
The Gramplet that is defined
|
||||
.. attribute:: height
|
||||
The height the gramplet should have in a column on GrampletView,
|
||||
default = 200
|
||||
.. attribute:: detached_height
|
||||
The height the gramplet should have detached, default 300
|
||||
.. attribute:: detached_width
|
||||
The width the gramplet should have detached, default 400
|
||||
.. attribute:: expand
|
||||
If the attributed should be expanded on start, default False
|
||||
.. attribute:: gramplet_title
|
||||
Title to use for the gramplet, default = 'Gramplet'
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._id = None
|
||||
self._name = None
|
||||
self._version = None
|
||||
self._description = None
|
||||
self._status = UNSTABLE
|
||||
self._fname = None
|
||||
self._ptype = None
|
||||
self._authors = []
|
||||
self._authors_email = []
|
||||
self._supported = True
|
||||
self._load_on_reg = False
|
||||
#derived var
|
||||
self.mod_name = None
|
||||
#RELCALC attr
|
||||
self._relcalcclass = None
|
||||
self._lang_list = None
|
||||
#REPORT attr
|
||||
self._reportclass = None
|
||||
self._require_active = True
|
||||
self._report_modes = [REPORT_MODE_GUI]
|
||||
#REPORT and TOOL attr
|
||||
self._category = None
|
||||
self._optionclass = None
|
||||
#TOOL attr
|
||||
self._toolclass = None
|
||||
self._tool_modes = [TOOL_MODE_GUI]
|
||||
#DOCGEN attr
|
||||
self._basedocclass = None
|
||||
self._paper = True
|
||||
self._style = True
|
||||
self._extension = ''
|
||||
#QUICKREPORT attr
|
||||
self._runfunc = None
|
||||
#MAPSERVICE attr
|
||||
self._mapservice = None
|
||||
#EXPORT attr
|
||||
self._export_function = None
|
||||
self._export_options = None
|
||||
self._export_options_title = ''
|
||||
#IMPORT attr
|
||||
self._import_function = None
|
||||
#GRAMPLET attr
|
||||
self._gramplet = None
|
||||
self._height = 200
|
||||
self._detached_height = 300
|
||||
self._detached_width = 400
|
||||
self._expand = False
|
||||
self._gramplet_title = _('Gramplet')
|
||||
|
||||
def _set_id(self, id):
|
||||
self._id = id
|
||||
|
||||
def _get_id(self):
|
||||
return self._id
|
||||
|
||||
def _set_name(self, name):
|
||||
self._name = name
|
||||
|
||||
def _get_name(self):
|
||||
return self._name
|
||||
|
||||
def _set_description(self, description):
|
||||
self._description = description
|
||||
|
||||
def _get_description(self):
|
||||
return self._description
|
||||
|
||||
def _set_version(self, version):
|
||||
self._version = version
|
||||
|
||||
def _get_version(self):
|
||||
return self._version
|
||||
|
||||
def _set_status(self, status):
|
||||
if status not in STATUS:
|
||||
raise ValueError, 'plugin status cannot be %s' % str(status)
|
||||
self._status = status
|
||||
|
||||
def _get_status(self):
|
||||
return self._status
|
||||
|
||||
def _set_fname(self, fname):
|
||||
self._fname = fname
|
||||
|
||||
def _get_fname(self):
|
||||
return self._fname
|
||||
|
||||
def _set_ptype(self, ptype):
|
||||
if ptype not in PTYPE:
|
||||
raise ValueError, 'Plugin type cannot be %s' % str(ptype)
|
||||
elif self._ptype is not None:
|
||||
raise ValueError, 'Plugin type may not be changed'
|
||||
self._ptype = ptype
|
||||
if self._ptype == REPORT:
|
||||
self._category = CATEGORY_TEXT
|
||||
elif self._ptype == TOOL:
|
||||
self._category = TOOL_UTILS
|
||||
elif self._ptype == QUICKREPORT:
|
||||
self._category = CATEGORY_QR_PERSON
|
||||
#if self._ptype == DOCGEN:
|
||||
# self._load_on_reg = True
|
||||
|
||||
def _get_ptype(self):
|
||||
return self._ptype
|
||||
|
||||
def _set_authors(self, authors):
|
||||
if not authors or not isinstance(authors, list):
|
||||
return
|
||||
self._authors = authors
|
||||
|
||||
def _get_authors(self):
|
||||
return self._authors
|
||||
|
||||
def _set_authors_email(self, authors_email):
|
||||
if not authors_email or not isinstance(authors_email, list):
|
||||
return
|
||||
self._authors_email = authors_email
|
||||
|
||||
def _get_authors_email(self):
|
||||
return self._authors_email
|
||||
|
||||
def _set_supported(self, supported):
|
||||
if not isinstance(supported, bool):
|
||||
raise ValueError, 'Plugin must have supported=True or False'
|
||||
self._supported = supported
|
||||
|
||||
def _get_supported(self):
|
||||
return self._supported
|
||||
|
||||
def _get_load_on_reg(self):
|
||||
return self._load_on_reg
|
||||
|
||||
def _set_load_on_reg(self, load_on_reg):
|
||||
if not isinstance(load_on_reg, bool):
|
||||
raise ValueError, 'Plugin must have load_on_reg=True or False'
|
||||
self._load_on_reg = load_on_reg
|
||||
|
||||
id = property(_get_id, _set_id)
|
||||
name = property(_get_name, _set_name)
|
||||
description = property(_get_description, _set_description)
|
||||
version = property(_get_version, _set_version)
|
||||
status = property(_get_status, _set_status)
|
||||
fname = property(_get_fname, _set_fname)
|
||||
ptype = property(_get_ptype, _set_ptype)
|
||||
authors = property(_get_authors, _set_authors)
|
||||
authors_email = property(_get_authors_email, _set_authors_email)
|
||||
supported = property(_get_supported, _set_supported)
|
||||
load_on_reg = property(_get_load_on_reg, _set_load_on_reg)
|
||||
|
||||
def statustext(self):
|
||||
return STATUSTEXT[self.status]
|
||||
|
||||
#type specific plugin attributes
|
||||
|
||||
#RELCALC attributes
|
||||
def _set_relcalcclass(self, relcalcclass):
|
||||
if not self._ptype == RELCALC:
|
||||
raise ValueError, 'relcalcclass may only be set for RELCALC plugins'
|
||||
self._relcalcclass = relcalcclass
|
||||
|
||||
def _get_relcalcclass(self):
|
||||
return self._relcalcclass
|
||||
|
||||
def _set_lang_list(self, lang_list):
|
||||
if not self._ptype == RELCALC:
|
||||
raise ValueError, 'relcalcclass may only be set for RELCALC plugins'
|
||||
self._lang_list = lang_list
|
||||
|
||||
def _get_lang_list(self):
|
||||
return self._lang_list
|
||||
|
||||
relcalcclass = property(_get_relcalcclass, _set_relcalcclass)
|
||||
lang_list = property(_get_lang_list, _set_lang_list)
|
||||
|
||||
#REPORT attributes
|
||||
def _set_require_active(self, require_active):
|
||||
if not self._ptype == REPORT:
|
||||
raise ValueError, 'require_active may only be set for REPORT plugins'
|
||||
if not isinstance(require_active, bool):
|
||||
raise ValueError, 'Report must have require_active=True or False'
|
||||
self._require_active = require_active
|
||||
|
||||
def _get_require_active(self):
|
||||
return self._require_active
|
||||
|
||||
def _set_reportclass(self, reportclass):
|
||||
if not self._ptype == REPORT:
|
||||
raise ValueError, 'reportclass may only be set for REPORT plugins'
|
||||
self._reportclass = reportclass
|
||||
|
||||
def _get_reportclass(self):
|
||||
return self._reportclass
|
||||
|
||||
def _set_report_modes(self, report_modes):
|
||||
if not self._ptype == REPORT:
|
||||
raise ValueError, 'report_modes may only be set for REPORT plugins'
|
||||
if not isinstance(report_modes, list):
|
||||
raise ValueError, 'report_modes must be a list'
|
||||
self._report_modes = [x for x in report_modes if x in REPORT_MODES]
|
||||
if not self._report_modes:
|
||||
raise ValueError, 'report_modes not a valid list of modes'
|
||||
|
||||
def _get_report_modes(self):
|
||||
return self._report_modes
|
||||
|
||||
#REPORT OR TOOL OR QUICKREPORT attributes
|
||||
def _set_category(self, category):
|
||||
if not (self._ptype == REPORT or self._ptype == TOOL or
|
||||
self._ptype == QUICKREPORT):
|
||||
raise ValueError, 'category may only be set for REPORT/TOOL plugins'
|
||||
self._category = category
|
||||
|
||||
def _get_category(self):
|
||||
return self._category
|
||||
|
||||
#REPORT OR TOOL attributes
|
||||
def _set_optionclass(self, optionclass):
|
||||
if not (self._ptype == REPORT or self.ptype == TOOL):
|
||||
raise ValueError, 'optionclass may only be set for REPORT/TOOL plugins'
|
||||
self._optionclass = optionclass
|
||||
|
||||
def _get_optionclass(self):
|
||||
return self._optionclass
|
||||
|
||||
#TOOL attributes
|
||||
def _set_toolclass(self, toolclass):
|
||||
if not self._ptype == TOOL:
|
||||
raise ValueError, 'toolclass may only be set for TOOL plugins'
|
||||
self._toolclass = toolclass
|
||||
|
||||
def _get_toolclass(self):
|
||||
return self._toolclass
|
||||
|
||||
def _set_tool_modes(self, tool_modes):
|
||||
if not self._ptype == TOOL:
|
||||
raise ValueError, 'tool_modes may only be set for TOOL plugins'
|
||||
if not isinstance(tool_modes, list):
|
||||
raise ValueError, 'tool_modes must be a list'
|
||||
self._tool_modes = [x for x in tool_modes if x in TOOL_MODES]
|
||||
if not self._tool_modes:
|
||||
raise ValueError, 'tool_modes not a valid list of modes'
|
||||
|
||||
def _get_tool_modes(self):
|
||||
return self._tool_modes
|
||||
|
||||
require_active = property(_get_require_active, _set_require_active)
|
||||
reportclass = property(_get_reportclass, _set_reportclass)
|
||||
report_modes = property(_get_report_modes, _set_report_modes)
|
||||
category = property(_get_category, _set_category)
|
||||
optionclass = property(_get_optionclass, _set_optionclass)
|
||||
toolclass = property(_get_toolclass, _set_toolclass)
|
||||
tool_modes = property(_get_tool_modes, _set_tool_modes)
|
||||
|
||||
#DOCGEN attributes
|
||||
def _set_basedocclass(self, basedocclass):
|
||||
if not self._ptype == DOCGEN:
|
||||
raise ValueError, 'basedocclass may only be set for DOCGEN plugins'
|
||||
self._basedocclass = basedocclass
|
||||
|
||||
def _get_basedocclass(self):
|
||||
return self._basedocclass
|
||||
|
||||
def _set_paper(self, paper):
|
||||
if not self._ptype == DOCGEN:
|
||||
raise ValueError, 'paper may only be set for DOCGEN plugins'
|
||||
if not isinstance(paper, bool):
|
||||
raise ValueError, 'Plugin must have paper=True or False'
|
||||
self._paper = paper
|
||||
|
||||
def _get_paper(self):
|
||||
return self._paper
|
||||
|
||||
def _set_style(self, style):
|
||||
if not self._ptype == DOCGEN:
|
||||
raise ValueError, 'style may only be set for DOCGEN plugins'
|
||||
if not isinstance(style, bool):
|
||||
raise ValueError, 'Plugin must have style=True or False'
|
||||
self._style = style
|
||||
|
||||
def _get_style(self):
|
||||
return self._style
|
||||
|
||||
def _set_extension(self, extension):
|
||||
if not (self._ptype == DOCGEN or self._ptype == EXPORT
|
||||
or self._ptype == IMPORT):
|
||||
raise ValueError, 'extension may only be set for DOCGEN/EXPORT/'\
|
||||
'IMPORT plugins'
|
||||
self._extension = extension
|
||||
|
||||
def _get_extension(self):
|
||||
return self._extension
|
||||
|
||||
basedocclass = property(_get_basedocclass, _set_basedocclass)
|
||||
paper = property(_get_paper, _set_paper)
|
||||
style = property(_get_style, _set_style)
|
||||
extension = property(_get_extension, _set_extension)
|
||||
|
||||
#QUICKREPORT attributes
|
||||
def _set_runfunc(self, runfunc):
|
||||
if not self._ptype == QUICKREPORT:
|
||||
raise ValueError, 'runfunc may only be set for QUICKREPORT plugins'
|
||||
self._runfunc = runfunc
|
||||
|
||||
def _get_runfunc(self):
|
||||
return self._runfunc
|
||||
|
||||
runfunc = property(_get_runfunc, _set_runfunc)
|
||||
|
||||
#MAPSERVICE attributes
|
||||
def _set_mapservice(self, mapservice):
|
||||
if not self._ptype == MAPSERVICE:
|
||||
raise ValueError, 'mapservice may only be set for MAPSERVICE plugins'
|
||||
self._mapservice = mapservice
|
||||
|
||||
def _get_mapservice(self):
|
||||
return self._mapservice
|
||||
|
||||
mapservice = property(_get_mapservice, _set_mapservice)
|
||||
|
||||
#EXPORT attributes
|
||||
def _set_export_function(self, export_function):
|
||||
if not self._ptype == EXPORT:
|
||||
raise ValueError, 'export_function may only be set for EXPORT plugins'
|
||||
self._export_function = export_function
|
||||
|
||||
def _get_export_function(self):
|
||||
return self._export_function
|
||||
|
||||
def _set_export_options(self, export_options):
|
||||
if not self._ptype == EXPORT:
|
||||
raise ValueError, 'export_options may only be set for EXPORT plugins'
|
||||
self._export_options = export_options
|
||||
|
||||
def _get_export_options(self):
|
||||
return self._export_options
|
||||
|
||||
def _set_export_options_title(self, export_options_title):
|
||||
if not self._ptype == EXPORT:
|
||||
raise ValueError, 'export_options_title may only be set for EXPORT plugins'
|
||||
self._export_options_title = export_options_title
|
||||
|
||||
def _get_export_options_title(self):
|
||||
return self._export_options_title
|
||||
|
||||
export_function = property(_get_export_function, _set_export_function)
|
||||
export_options = property(_get_export_options, _set_export_options)
|
||||
export_options_title = property(_get_export_options_title,
|
||||
_set_export_options_title)
|
||||
|
||||
#IMPORT attributes
|
||||
def _set_import_function(self, import_function):
|
||||
if not self._ptype == IMPORT:
|
||||
raise ValueError, 'import_function may only be set for IMPORT plugins'
|
||||
self._import_function = import_function
|
||||
|
||||
def _get_import_function(self):
|
||||
return self._import_function
|
||||
|
||||
import_function = property(_get_import_function, _set_import_function)
|
||||
|
||||
#GRAMPLET attributes
|
||||
def _set_gramplet(self, gramplet):
|
||||
if not self._ptype == GRAMPLET:
|
||||
raise ValueError, 'gramplet may only be set for GRAMPLET plugins'
|
||||
self._gramplet = gramplet
|
||||
|
||||
def _get_gramplet(self):
|
||||
return self._gramplet
|
||||
|
||||
def _set_height(self, height):
|
||||
if not self._ptype == GRAMPLET:
|
||||
raise ValueError, 'height may only be set for GRAMPLET plugins'
|
||||
if not isinstance(height, int):
|
||||
raise ValueError, 'Plugin must have height an integer'
|
||||
self._height = height
|
||||
|
||||
def _get_height(self):
|
||||
return self._height
|
||||
|
||||
def _set_detached_height(self, detached_height):
|
||||
if not self._ptype == GRAMPLET:
|
||||
raise ValueError, 'detached_height may only be set for GRAMPLET plugins'
|
||||
if not isinstance(detached_height, int):
|
||||
raise ValueError, 'Plugin must have detached_height an integer'
|
||||
self._detached_height = detached_height
|
||||
|
||||
def _get_detached_height(self):
|
||||
return self._detached_height
|
||||
|
||||
def _set_detached_width(self, detached_width):
|
||||
if not self._ptype == GRAMPLET:
|
||||
raise ValueError, 'detached_width may only be set for GRAMPLET plugins'
|
||||
if not isinstance(detached_width, int):
|
||||
raise ValueError, 'Plugin must have detached_width an integer'
|
||||
self._detached_width = detached_width
|
||||
|
||||
def _get_detached_width(self):
|
||||
return self._detached_width
|
||||
|
||||
def _set_expand(self, expand):
|
||||
if not self._ptype == GRAMPLET:
|
||||
raise ValueError, 'expand may only be set for GRAMPLET plugins'
|
||||
if not isinstance(expand, bool):
|
||||
raise ValueError, 'Plugin must have expand as a bool'
|
||||
self._expand = expand
|
||||
|
||||
def _get_expand(self):
|
||||
return self._expand
|
||||
|
||||
def _set_gramplet_title(self, gramplet_title):
|
||||
if not self._ptype == GRAMPLET:
|
||||
raise ValueError, 'gramplet_title may only be set for GRAMPLET plugins'
|
||||
if not isinstance(gramplet_title, str):
|
||||
raise ValueError, 'Plugin must have a string as gramplet_title'
|
||||
self._gramplet_title = gramplet_title
|
||||
|
||||
def _get_gramplet_title(self):
|
||||
return self._gramplet_title
|
||||
|
||||
gramplet = property(_get_gramplet, _set_gramplet)
|
||||
height = property(_get_height, _set_height)
|
||||
detached_height = property(_get_detached_height, _set_detached_height)
|
||||
detached_width = property(_get_detached_width, _set_detached_width)
|
||||
expand = property(_get_expand, _set_expand)
|
||||
gramplet_title = property(_get_gramplet_title, _set_gramplet_title)
|
||||
|
||||
def newplugin():
|
||||
"""
|
||||
Function to create a new plugindata object, add it to list of
|
||||
registered plugins
|
||||
:Returns: a newly created PluginData which is already part of the register
|
||||
"""
|
||||
gpr = PluginRegister.get_instance()
|
||||
pgd = PluginData()
|
||||
gpr.add_plugindata(pgd)
|
||||
return pgd
|
||||
|
||||
def register(ptype, **kwargs):
|
||||
"""
|
||||
Convenience function to register a new plugin using a dictionary as input.
|
||||
The register functions will call newplugin() function, and use the
|
||||
dictionary kwargs to assign data to the PluginData newplugin() created,
|
||||
as in: plugindata.key = data
|
||||
:param ptype: the plugin type, one of REPORT, TOOL, ...
|
||||
:param kwargs: dictionary with keys attributes of the plugin, and data
|
||||
the value
|
||||
|
||||
:Returns: a newly created PluginData which is already part of the register
|
||||
and which has kwargs assigned as attributes
|
||||
"""
|
||||
plg = newplugin()
|
||||
plg.ptype = ptype
|
||||
for prop in kwargs:
|
||||
#check it is a valid attribute with getattr
|
||||
getattr(plg, prop)
|
||||
#set the value
|
||||
setattr(plg, prop, kwargs[prop])
|
||||
return plg
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# PluginRegister
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class PluginRegister(object):
|
||||
""" PluginRegister is a Singleton which holds plugin data
|
||||
.. attribute : stable_only
|
||||
Bool, include stable plugins only or not. Default True
|
||||
"""
|
||||
__instance = None
|
||||
|
||||
def get_instance():
|
||||
""" Use this function to get the instance of the PluginRegister """
|
||||
if PluginRegister.__instance is None:
|
||||
PluginRegister.__instance = 1 # Set to 1 for __init__()
|
||||
PluginRegister.__instance = PluginRegister()
|
||||
return PluginRegister.__instance
|
||||
get_instance = staticmethod(get_instance)
|
||||
|
||||
def __init__(self):
|
||||
""" This function should only be run once by get_instance() """
|
||||
if PluginRegister.__instance is not 1:
|
||||
raise Exception("This class is a singleton. "
|
||||
"Use the get_instance() method")
|
||||
self.stable_only = True
|
||||
if __debug__:
|
||||
self.stable_only = False
|
||||
self.__plugindata = []
|
||||
|
||||
def add_plugindata(self, plugindata):
|
||||
self.__plugindata.append(plugindata)
|
||||
|
||||
def scan_dir(self, dir):
|
||||
"""
|
||||
The dir name will be scanned for plugin registration code, which will
|
||||
be loaded in PluginData objects if they satisfy some checks.
|
||||
|
||||
:Returns: A list with PluginData objects
|
||||
"""
|
||||
# if the directory does not exist, do nothing
|
||||
if not os.path.isdir(dir):
|
||||
return []
|
||||
|
||||
ext = r".gpr.py"
|
||||
extlen = -len(ext)
|
||||
pymod = re.compile(r"^(.*)\.py$")
|
||||
|
||||
for filename in os.listdir(dir):
|
||||
name = os.path.split(filename)[1]
|
||||
if not name[extlen:] == ext:
|
||||
continue
|
||||
lenpd = len(self.__plugindata)
|
||||
try:
|
||||
execfile(os.path.join(dir, filename),
|
||||
{'_': _,
|
||||
'newplugin': newplugin,
|
||||
'register': register,
|
||||
'STABLE': STABLE,
|
||||
'UNSTABLE': UNSTABLE,
|
||||
'REPORT': REPORT,
|
||||
'QUICKREPORT': QUICKREPORT,
|
||||
'TOOL': TOOL,
|
||||
'IMPORT': IMPORT,
|
||||
'EXPORT': EXPORT,
|
||||
'DOCGEN': DOCGEN,
|
||||
'GENERAL': GENERAL,
|
||||
'MAPSERVICE': MAPSERVICE,
|
||||
'VIEW': VIEW,
|
||||
'RELCALC': RELCALC,
|
||||
'GRAMPLET': GRAMPLET,
|
||||
'CATEGORY_TEXT': CATEGORY_TEXT,
|
||||
'CATEGORY_DRAW': CATEGORY_DRAW,
|
||||
'CATEGORY_CODE': CATEGORY_CODE,
|
||||
'CATEGORY_WEB': CATEGORY_WEB,
|
||||
'CATEGORY_BOOK': CATEGORY_BOOK,
|
||||
'CATEGORY_GRAPHVIZ': CATEGORY_GRAPHVIZ,
|
||||
'TOOL_DEBUG': TOOL_DEBUG,
|
||||
'TOOL_ANAL': TOOL_ANAL,
|
||||
'TOOL_DBPROC': TOOL_DBPROC,
|
||||
'TOOL_DBFIX': TOOL_DBFIX,
|
||||
'TOOL_REVCTL': TOOL_REVCTL,
|
||||
'TOOL_UTILS': TOOL_UTILS,
|
||||
'CATEGORY_QR_MISC': CATEGORY_QR_MISC,
|
||||
'CATEGORY_QR_PERSON': CATEGORY_QR_PERSON,
|
||||
'CATEGORY_QR_FAMILY': CATEGORY_QR_FAMILY,
|
||||
'CATEGORY_QR_EVENT': CATEGORY_QR_EVENT,
|
||||
'CATEGORY_QR_SOURCE': CATEGORY_QR_SOURCE,
|
||||
'CATEGORY_QR_PLACE': CATEGORY_QR_PLACE,
|
||||
'CATEGORY_QR_REPOSITORY': CATEGORY_QR_REPOSITORY,
|
||||
'CATEGORY_QR_NOTE': CATEGORY_QR_NOTE,
|
||||
'CATEGORY_QR_DATE': CATEGORY_QR_DATE,
|
||||
'REPORT_MODE_GUI': REPORT_MODE_GUI,
|
||||
'REPORT_MODE_BKI': REPORT_MODE_BKI,
|
||||
'REPORT_MODE_CLI': REPORT_MODE_CLI,
|
||||
'TOOL_MODE_GUI': TOOL_MODE_GUI,
|
||||
'TOOL_MODE_CLI': TOOL_MODE_CLI,
|
||||
'GRAMPSVERSION': GRAMPSVERSION,
|
||||
},
|
||||
{})
|
||||
except ValueError, msg:
|
||||
print _('Failed reading plugin registration %(filename)s') % \
|
||||
{'filename' : filename}
|
||||
print msg
|
||||
self.__plugindata = self.__plugindata[:lenpd]
|
||||
except:
|
||||
print _('Failed reading plugin registration %(filename)s') % \
|
||||
{'filename' : filename}
|
||||
print "".join(traceback.format_exception(*sys.exc_info()))
|
||||
self.__plugindata = self.__plugindata[:lenpd]
|
||||
#check if:
|
||||
# 1. plugin exists, if not remove, otherwise set module name
|
||||
# 2. plugin not stable, if stable_only=True, remove
|
||||
# 3. TOOL_DEBUG only if __debug__ True
|
||||
rmlist = []
|
||||
ind = lenpd-1
|
||||
for plugin in self.__plugindata[lenpd:]:
|
||||
ind += 1
|
||||
if not plugin.status == STABLE and self.stable_only:
|
||||
rmlist.append(ind)
|
||||
continue
|
||||
if plugin.ptype == TOOL and plugin.category == TOOL_DEBUG \
|
||||
and not __debug__:
|
||||
rmlist.append(ind)
|
||||
continue
|
||||
match = pymod.match(plugin.fname)
|
||||
if not match:
|
||||
rmlist.append(ind)
|
||||
print _('Wrong python file %(filename)s in register file '
|
||||
'%(regfile)s') % {
|
||||
'filename': os.path.join(dir, plugin.fname),
|
||||
'regfile': os.path.join(dir, filename)
|
||||
}
|
||||
continue
|
||||
if not os.path.isfile(os.path.join(dir, plugin.fname)):
|
||||
rmlist.append(ind)
|
||||
print _('Python file %(filename)s in register file '
|
||||
'%(regfile)s does not exist') % {
|
||||
'filename': os.path.join(dir, plugin.fname),
|
||||
'regfile': os.path.join(dir, filename)
|
||||
}
|
||||
continue
|
||||
module = match.groups()[0]
|
||||
plugin.mod_name = module
|
||||
rmlist.reverse()
|
||||
for ind in rmlist:
|
||||
del self.__plugindata[ind]
|
||||
|
||||
def __type_plugins(self, ptype):
|
||||
"""Return a list of PluginData that are of type ptype
|
||||
"""
|
||||
return [x for x in self.__plugindata if x.ptype == ptype]
|
||||
|
||||
def report_plugins(self, gui=True):
|
||||
"""Return a list of gui or cli PluginData that are of type REPORT
|
||||
:param gui: bool, if True then gui plugin, otherwise cli plugin
|
||||
"""
|
||||
if gui:
|
||||
return [x for x in self.__type_plugins(REPORT) if REPORT_MODE_GUI
|
||||
in x.report_modes]
|
||||
else:
|
||||
return [x for x in self.__type_plugins(REPORT) if REPORT_MODE_CLI
|
||||
in x.report_modes]
|
||||
|
||||
def tool_plugins(self, gui=True):
|
||||
"""Return a list of PluginData that are of type TOOL
|
||||
"""
|
||||
if gui:
|
||||
return [x for x in self.__type_plugins(TOOL) if TOOL_MODE_GUI
|
||||
in x.tool_modes]
|
||||
else:
|
||||
return [x for x in self.__type_plugins(TOOL) if TOOL_MODE_CLI
|
||||
in x.tool_modes]
|
||||
|
||||
|
||||
def bookitem_plugins(self):
|
||||
"""Return a list of REPORT PluginData that are can be used as bookitem
|
||||
"""
|
||||
return [x for x in self.__type_plugins(REPORT) if REPORT_MODE_BKI
|
||||
in x.report_modes]
|
||||
|
||||
def quickreport_plugins(self):
|
||||
"""Return a list of PluginData that are of type QUICKREPORT
|
||||
"""
|
||||
return self.__type_plugins(QUICKREPORT)
|
||||
|
||||
def import_plugins(self):
|
||||
"""Return a list of PluginData that are of type IMPORT
|
||||
"""
|
||||
return self.__type_plugins(IMPORT)
|
||||
|
||||
def export_plugins(self):
|
||||
"""Return a list of PluginData that are of type EXPORT
|
||||
"""
|
||||
return self.__type_plugins(EXPORT)
|
||||
|
||||
def docgen_plugins(self):
|
||||
"""Return a list of PluginData that are of type DOCGEN
|
||||
"""
|
||||
return self.__type_plugins(DOCGEN)
|
||||
|
||||
def general_plugins(self):
|
||||
"""Return a list of PluginData that are of type GENERAL
|
||||
"""
|
||||
return self.__type_plugins(GENERAL)
|
||||
|
||||
def mapservice_plugins(self):
|
||||
"""Return a list of PluginData that are of type MAPSERVICE
|
||||
"""
|
||||
return self.__type_plugins(MAPSERVICE)
|
||||
|
||||
def view_plugins(self):
|
||||
"""Return a list of PluginData that are of type VIEW
|
||||
"""
|
||||
return self.__type_plugins(RELCALC)
|
||||
|
||||
def relcalc_plugins(self):
|
||||
"""Return a list of PluginData that are of type RELCALC
|
||||
"""
|
||||
return self.__type_plugins(RELCALC)
|
||||
|
||||
def filter_load_on_reg(self):
|
||||
"""Return a list of PluginData that have load_on_reg == True
|
||||
"""
|
||||
return [x for x in self.__plugindata if x.load_on_reg == True]
|
Reference in New Issue
Block a user