-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refs #4226. Add plugin loader for Python framework.
Adds a generic plugin (module) loader for importing additional python modules at start up
- Loading branch information
1 parent
4e7c47e
commit 1907ead
Showing
22 changed files
with
216 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
Code/Mantid/Framework/PythonInterface/mantid/kernel/plugins.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
""" | ||
Defines functions to dynamically load Python modules. | ||
These modules may define extensions to C++ types, e.g. | ||
algorithms, fit functions etc. | ||
""" | ||
import os as _os | ||
import imp as _imp | ||
from mantid.kernel import Logger | ||
|
||
class PluginLoader(object): | ||
|
||
def __init__(self, filepath): | ||
if not _os.path.isfile(filepath): | ||
raise ValueError("PluginLoader expects a single filename. '%s' does not point to an existing file" % filepath) | ||
if not filepath.endswith('.py'): | ||
raise ValueError("PluginLoader expects a filename ending with .py. '%s' does not have a .py extension" % filepath) | ||
self._filepath = filepath | ||
self._logger = Logger.get("PluginLoader") | ||
|
||
def run(self): | ||
""" | ||
Load the module we are pointing at and return | ||
the module object. | ||
Any ImportErrors raised are not caught and are passed | ||
on to the caller | ||
""" | ||
pathname = self._filepath | ||
name = _os.path.basename(pathname) # Including extension | ||
name = _os.path.splitext(name)[0] | ||
self._logger.debug("Loading python plugin %s" % pathname) | ||
return _imp.load_source(name, pathname) | ||
|
||
def load(path): | ||
""" | ||
High-level function to import the module(s) on the given path. | ||
The module is imported using __import__ so any code not defined | ||
inside an if __name__ == '__main__' block is executed. | ||
@param path :: If the path is a filename load the file; if the | ||
path points to a directory load all files in the directory | ||
recursively; if the path contains a list of directories then | ||
all files in each are loaded in turn | ||
@return A list of the names of the loaded modules. Note this | ||
will not included modules that will have attempted to be | ||
reloaded but had not been changed | ||
""" | ||
loaded = [] | ||
if _os.path.isfile(path) and path.endswith('.py'): # Single file | ||
loader = PluginLoader(path) | ||
module = loader.run() | ||
loaded.append(module.__name__) | ||
elif _os.path.isdir(path): # Directory | ||
loaded.extend(load_from_dir(path)) | ||
else: # a list | ||
if ';' in path: | ||
path = split(';') | ||
if type(path) is list: # Call load again for each one | ||
for p in path: | ||
loaded.extend(load(p)) | ||
|
||
return loaded | ||
|
||
def load_from_dir(directory): | ||
""" | ||
Load all modules in the given directory | ||
@param directory :: A path that must point to a directory | ||
""" | ||
if not _os.path.isdir(directory): | ||
raise RuntimeError("The path given does not point to an existing directory") | ||
loaded = [] | ||
for root, dirs, files in _os.walk(directory): | ||
for f in files: | ||
filename = _os.path.join(root, f) | ||
loaded.extend(load(filename)) | ||
|
||
return loaded | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,3 +84,5 @@ def _clean_up_test_areas(self): | |
except OSError: | ||
pass | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
Code/Mantid/Framework/PythonInterface/test/python/PythonPluginsTest.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import unittest | ||
import os | ||
import shutil | ||
import sys | ||
|
||
import mantid.kernel.plugins as plugins | ||
from mantid import algorithm_factory, algorithm_mgr | ||
|
||
__TESTALG__ = \ | ||
"""from mantid import Algorithm, register_algorithm | ||
class TestPyAlg(Algorithm): | ||
def PyInit(self): | ||
pass | ||
def PyExec(self): | ||
pass | ||
register_algorithm(TestPyAlg) | ||
""" | ||
|
||
class PythonPluginsTest(unittest.TestCase): | ||
|
||
def setUp(self): | ||
# Make a test directory and test plugin | ||
self._testdir = os.path.join(os.getcwd(), 'PythonPluginsTest_TmpDir') | ||
try: | ||
os.mkdir(self._testdir) | ||
except OSError: | ||
pass # Already exists, maybe it was not removed when a test failed? | ||
filename = os.path.join(self._testdir, 'TestPyAlg.py') | ||
if not os.path.exists(filename): | ||
plugin = file(filename, 'w') | ||
plugin.write(__TESTALG__) | ||
plugin.close() | ||
|
||
def tearDown(self): | ||
try: | ||
shutil.rmtree(self._testdir) | ||
except shutil.Error: | ||
pass | ||
|
||
def test_loading_python_algorithm_increases_registered_algs_by_one(self): | ||
loaded = plugins.load(self._testdir) | ||
self.assertTrue(len(loaded) > 0) | ||
expected_name = 'TestPyAlg' | ||
# Has the name appear in the module dictionary | ||
self.assertTrue(expected_name in sys.modules) | ||
# Do we have the registered algorithm | ||
algs = algorithm_factory.get_registered_algorithms(True) | ||
self.assertTrue(expected_name in algs) | ||
# Can it be created? | ||
try: | ||
test_alg = algorithm_mgr.create_unmanaged(expected_name) | ||
self.assertEquals(expected_name, test_alg.name()) | ||
self.assertEquals(1, test_alg.version()) | ||
except RuntimeError, exc: | ||
self.fail("Failed to create plugin algorithm from the manager: '%s' " %s) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters