From 91a5995a5244dface52ff7fc3d72a9a1cb4de550 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 22 Dec 2017 14:20:55 +0100 Subject: [PATCH 1/4] Add WorkChain as acceptable subclass for workflows plugin loader The WorkflowFactory can be used to load both legacy Workflow classes as well as new style WorkChain workflows. The plugin loader tests were only allowing for legacy Workflow classes to be registered even though the loader works just fine. Therefore we add the WorkChain as an acceptable subclass for classes registered under the aiida.workflows entry point --- aiida/backends/tests/test_plugin_loader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aiida/backends/tests/test_plugin_loader.py b/aiida/backends/tests/test_plugin_loader.py index 5600621ac4..0649525fae 100644 --- a/aiida/backends/tests/test_plugin_loader.py +++ b/aiida/backends/tests/test_plugin_loader.py @@ -15,6 +15,7 @@ from aiida.orm import Workflow from aiida.orm.data import Data from aiida.orm import JobCalculation +from aiida.work import WorkChain from aiida.scheduler import Scheduler from aiida.tools.dbexporters.tcod_plugins import BaseTcodtranslator from aiida.transport import Transport @@ -74,7 +75,7 @@ def test_existing_workflows(self): workflows = all_plugins('workflows') self.assertIsInstance(workflows, list) for i in workflows: - self.assertTrue(issubclass(WorkflowFactory(i), Workflow)) + self.assertTrue(issubclass(WorkflowFactory(i), (Workflow, WorkChain))) def test_existing_tcod_plugins(self): """ From 78bdb867208e82794c539c7b7338f2053c056898 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 22 Dec 2017 14:27:30 +0100 Subject: [PATCH 2/4] Add assertion error messages to the plugin loader tests --- aiida/backends/tests/test_plugin_loader.py | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/aiida/backends/tests/test_plugin_loader.py b/aiida/backends/tests/test_plugin_loader.py index 0649525fae..41d3285d5b 100644 --- a/aiida/backends/tests/test_plugin_loader.py +++ b/aiida/backends/tests/test_plugin_loader.py @@ -36,19 +36,20 @@ def test_existing_calculations(self): calculations = all_plugins('calculations') self.assertIsInstance(calculations, list) for i in calculations: - self.assertTrue( - issubclass(CalculationFactory(i), JobCalculation), - 'Calculation plugin class {} is not subclass of JobCalculation'.format( - CalculationFactory(i))) + cls = CalculationFactory(i) + self.assertTrue(issubclass(cls, JobCalculation), + 'Calculation plugin class {} is not subclass of {}'.format(cls, JobCalculation)) def test_existing_data(self): """ - Test listing all preinstalled data formats + Test listing all preinstalled data classes """ data = all_plugins('data') self.assertIsInstance(data, list) for i in data: - self.assertTrue(issubclass(DataFactory(i), Data)) + cls = DataFactory(i) + self.assertTrue(issubclass(cls, Data), + 'Data plugin class {} is not subclass of {}'.format(cls, Data)) def test_existing_schedulers(self): """ @@ -57,7 +58,9 @@ def test_existing_schedulers(self): schedulers = all_plugins('schedulers') self.assertIsInstance(schedulers, list) for i in schedulers: - self.assertTrue(issubclass(SchedulerFactory(i), Scheduler)) + cls = SchedulerFactory(i) + self.assertTrue(issubclass(cls, Scheduler), + 'Scheduler plugin class {} is not subclass of {}'.format(cls, Scheduler)) def test_existing_transports(self): """ @@ -66,7 +69,9 @@ def test_existing_transports(self): transports = all_plugins('transports') self.assertIsInstance(transports, list) for i in transports: - self.assertTrue(issubclass(TransportFactory(i), Transport)) + cls = TransportFactory(i) + self.assertTrue(issubclass(cls, Transport), + 'Transport plugin class {} is not subclass of {}'.format(cls, Transport)) def test_existing_workflows(self): """ @@ -75,7 +80,9 @@ def test_existing_workflows(self): workflows = all_plugins('workflows') self.assertIsInstance(workflows, list) for i in workflows: - self.assertTrue(issubclass(WorkflowFactory(i), (Workflow, WorkChain))) + cls = WorkflowFactory(i) + self.assertTrue(issubclass(cls, (Workflow, WorkChain)), + 'Workflow plugin class {} is neither a subclass of {} nor {}'.format(cls, Workflow, WorkChain)) def test_existing_tcod_plugins(self): """ From b9b4b310de19ceee374f622bd45da3fa80daf639 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 22 Dec 2017 14:36:40 +0100 Subject: [PATCH 3/4] Implement TcodExporterFactory and update plugin loader tests The plugin loader tests will now try to construct the plugins for the Tcod exporter through the TcodExporterFactory and test whether they are a subclass of the BaseTcodtranslator class --- aiida/backends/tests/test_plugin_loader.py | 14 ++++++++------ aiida/tools/dbexporters/tcod_plugins/__init__.py | 9 +++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/aiida/backends/tests/test_plugin_loader.py b/aiida/backends/tests/test_plugin_loader.py index 41d3285d5b..321cf5914f 100644 --- a/aiida/backends/tests/test_plugin_loader.py +++ b/aiida/backends/tests/test_plugin_loader.py @@ -10,15 +10,13 @@ from aiida.backends.testbase import AiidaTestCase from aiida.common.pluginloader import all_plugins from aiida.orm import CalculationFactory, DataFactory, WorkflowFactory -from aiida.scheduler import SchedulerFactory -from aiida.transport import TransportFactory from aiida.orm import Workflow from aiida.orm.data import Data from aiida.orm import JobCalculation +from aiida.scheduler import Scheduler, SchedulerFactory +from aiida.transport import Transport, TransportFactory +from aiida.tools.dbexporters.tcod_plugins import BaseTcodtranslator, TcodExporterFactory from aiida.work import WorkChain -from aiida.scheduler import Scheduler -from aiida.tools.dbexporters.tcod_plugins import BaseTcodtranslator -from aiida.transport import Transport class TestExistingPlugins(AiidaTestCase): @@ -88,5 +86,9 @@ def test_existing_tcod_plugins(self): """ Test listing all preinstalled tcod exporter plugins """ - tcod_plugins = all_plugins('transports') + tcod_plugins = all_plugins('tools.dbexporters.tcod_plugins') self.assertIsInstance(tcod_plugins, list) + for i in tcod_plugins: + cls = TcodExporterFactory(i) + self.assertTrue(issubclass(cls, BaseTcodtranslator), + 'TcodExporter plugin class {} is not subclass of {}'.format(cls, BaseTcodtranslator)) diff --git a/aiida/tools/dbexporters/tcod_plugins/__init__.py b/aiida/tools/dbexporters/tcod_plugins/__init__.py index 3fd559897a..8cc875fd00 100644 --- a/aiida/tools/dbexporters/tcod_plugins/__init__.py +++ b/aiida/tools/dbexporters/tcod_plugins/__init__.py @@ -9,6 +9,15 @@ ########################################################################### +def TcodExporterFactory(module): + """ + Return a suitable BaseTcodtranslator subclass. + """ + from aiida.common.pluginloader import BaseFactory + + return BaseFactory(module, BaseTcodtranslator, 'aiida.tools.dbexporters.tcod_plugins') + + class BaseTcodtranslator(object): """ Base translator from calculation-specific input and output parameters From fabfc93297e02158f3e3a4bfdb90d32181ea4493 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 22 Dec 2017 15:28:43 +0100 Subject: [PATCH 4/4] Simplify parser entry point mapping and add ParserFactory With the new ParserFactory I have also added a tests to the plugin loader for all registered plugins for the aiida.parsers entry point --- aiida/backends/tests/test_plugin_loader.py | 12 ++++++++++++ aiida/common/pluginloader.py | 2 +- aiida/parsers/__init__.py | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/aiida/backends/tests/test_plugin_loader.py b/aiida/backends/tests/test_plugin_loader.py index 321cf5914f..57e3fa0674 100644 --- a/aiida/backends/tests/test_plugin_loader.py +++ b/aiida/backends/tests/test_plugin_loader.py @@ -11,6 +11,7 @@ from aiida.common.pluginloader import all_plugins from aiida.orm import CalculationFactory, DataFactory, WorkflowFactory from aiida.orm import Workflow +from aiida.parsers import Parser, ParserFactory from aiida.orm.data import Data from aiida.orm import JobCalculation from aiida.scheduler import Scheduler, SchedulerFactory @@ -49,6 +50,17 @@ def test_existing_data(self): self.assertTrue(issubclass(cls, Data), 'Data plugin class {} is not subclass of {}'.format(cls, Data)) + def test_existing_parsers(self): + """ + Test listing all preinstalled parsers + """ + parsers = all_plugins('parsers') + self.assertIsInstance(parsers, list) + for i in parsers: + cls = ParserFactory(i) + self.assertTrue(issubclass(cls, Parser), + 'Parser plugin class {} is not subclass of {}'.format(cls, Parser)) + def test_existing_schedulers(self): """ Test listing all preinstalled schedulers diff --git a/aiida/common/pluginloader.py b/aiida/common/pluginloader.py index ebef3ea543..eeaa0d7fb7 100644 --- a/aiida/common/pluginloader.py +++ b/aiida/common/pluginloader.py @@ -27,7 +27,7 @@ _category_mapping = { 'calculations': 'aiida.orm.calculation.job', 'data': 'aiida.orm.data', - 'parsers': 'aiida.parsers.plugins', + 'parsers': 'aiida.parsers', 'schedulers': 'aiida.scheduler.plugins', 'transports': 'aiida.transport.plugins', 'workflows': 'aiida.workflows', diff --git a/aiida/parsers/__init__.py b/aiida/parsers/__init__.py index 1a8dcdd1ce..04ec80a5f7 100644 --- a/aiida/parsers/__init__.py +++ b/aiida/parsers/__init__.py @@ -18,4 +18,4 @@ def ParserFactory(module): from aiida.common.pluginloader import BaseFactory from aiida.common.exceptions import MissingPluginError - return BaseFactory(module, Parser, 'aiida.parsers.plugins') + return BaseFactory(module, Parser, 'aiida.parsers')