forked from aiidateam/aiida-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a
PluginVersionProvider
for processes (aiidateam#3131)
This new utility class is used by the `Runner` class to keep a mapping of certain process classes, either `Process` sub classes or process functions onto a dictionary of "version" information. This dictionary now includes the version of `aiida-core` that is running as well as the version of the top level module of the plugin, if defined. If the latter cannot be determined for whatever reason, only the version of `aiida-core` is returned. This information is then retrieved by the `Process` class during the creation process. It will store this information in the attributes of the process node. Currently, no logic in `aiida-core` will act on this information. Its sole purpose is to give the user slightly more info on with what versions of core and the plugin a certain process node was generated. The attributes can also be used in querying to filter nodes for a sub set generated with a specific version of the plugin. Note that "plugin" here refers to the entire package, e.g the entire `aiida-quantumespresso` plugin. Each plugin can contain multiple entry points for the various entry point categories, that are sometimes individually also referred to as plugins. In the future, the version dictionary returned by the `PluginVersionProvider` may be enriched with a specific `entry_point` version, once that level of version granulariy will become supported. For the time being it is not included.
- Loading branch information
Showing
8 changed files
with
229 additions
and
106 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
Empty file.
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,130 @@ | ||
# -*- coding: utf-8 -*- | ||
########################################################################### | ||
# Copyright (c), The AiiDA team. All rights reserved. # | ||
# This file is part of the AiiDA code. # | ||
# # | ||
# The code is hosted on GitHub at https://github.com/aiidateam/aiida_core # | ||
# For further information on the license, see the LICENSE.txt file # | ||
# For further information please visit http://www.aiida.net # | ||
########################################################################### | ||
"""Tests for utilities dealing with plugins and entry points.""" | ||
from __future__ import division | ||
from __future__ import absolute_import | ||
from __future__ import print_function | ||
|
||
from aiida import __version__ as version_core | ||
from aiida.backends.testbase import AiidaTestCase | ||
from aiida.engine import calcfunction, WorkChain | ||
from aiida.plugins import CalculationFactory | ||
from aiida.plugins.utils import PluginVersionProvider | ||
|
||
|
||
class TestPluginVersionProvider(AiidaTestCase): | ||
"""Tests for the :py:class:`~aiida.plugins.utils.PluginVersionProvider` utility class.""" | ||
|
||
# pylint: disable=no-init,old-style-class,too-few-public-methods,no-member | ||
|
||
def setUp(self): | ||
super(TestPluginVersionProvider, self).setUp() | ||
self.provider = PluginVersionProvider() | ||
|
||
@staticmethod | ||
def create_dynamic_plugin_module(plugin, plugin_version, add_module_to_sys=True, add_version=True): | ||
"""Create a fake dynamic module with a certain `plugin` entity, a class or function and the given version.""" | ||
import sys | ||
import types | ||
import uuid | ||
|
||
# Create a new module with a unique name and add the `plugin` and `plugin_version` as attributes | ||
module_name = 'TestModule{}'.format(str(uuid.uuid4())[:5]) | ||
dynamic_module = types.ModuleType(module_name, 'Dynamically created module for testing purposes') | ||
setattr(plugin, '__module__', dynamic_module.__name__) | ||
setattr(dynamic_module, plugin.__name__, plugin) | ||
|
||
# For tests that need to fail, this flag can be set to `False` | ||
if add_version: | ||
setattr(dynamic_module, '__version__', plugin_version) | ||
|
||
# Get the `DummyClass` plugin from the dynamically created test module | ||
dynamic_plugin = getattr(dynamic_module, plugin.__name__) | ||
|
||
# Make the dynamic module importable unless the test requests not to, to test an unimportable module | ||
if add_module_to_sys: | ||
sys.modules[dynamic_module.__name__] = dynamic_module | ||
|
||
return dynamic_plugin | ||
|
||
def test_external_module_import_fail(self): | ||
"""Test that mapper does not except even if external module cannot be imported.""" | ||
|
||
class DummyCalcJob(): | ||
pass | ||
|
||
version_plugin = '0.1.01' | ||
dynamic_plugin = self.create_dynamic_plugin_module(DummyCalcJob, version_plugin, add_module_to_sys=False) | ||
|
||
expected_version = {'version': {'core': version_core}} | ||
self.assertEqual(self.provider.get_version_info(dynamic_plugin), expected_version) | ||
|
||
def test_external_module_no_version_attribute(self): | ||
"""Test that mapper does not except even if external module does not define `__version__` attribute.""" | ||
|
||
class DummyCalcJob(): | ||
pass | ||
|
||
version_plugin = '0.1.02' | ||
dynamic_plugin = self.create_dynamic_plugin_module(DummyCalcJob, version_plugin, add_version=False) | ||
|
||
expected_version = {'version': {'core': version_core}} | ||
self.assertEqual(self.provider.get_version_info(dynamic_plugin), expected_version) | ||
|
||
def test_external_module_class(self): | ||
"""Test the mapper works for a class from an external module.""" | ||
|
||
class DummyCalcJob(): | ||
pass | ||
|
||
version_plugin = '0.1.17' | ||
dynamic_plugin = self.create_dynamic_plugin_module(DummyCalcJob, version_plugin) | ||
|
||
expected_version = {'version': {'core': version_core, 'plugin': version_plugin}} | ||
self.assertEqual(self.provider.get_version_info(dynamic_plugin), expected_version) | ||
|
||
def test_external_module_function(self): | ||
"""Test the mapper works for a function from an external module.""" | ||
|
||
@calcfunction | ||
def test_calcfunction(): | ||
return | ||
|
||
version_plugin = '0.2.19' | ||
dynamic_plugin = self.create_dynamic_plugin_module(test_calcfunction, version_plugin) | ||
|
||
expected_version = {'version': {'core': version_core, 'plugin': version_plugin}} | ||
self.assertEqual(self.provider.get_version_info(dynamic_plugin), expected_version) | ||
|
||
def test_calcfunction(self): | ||
"""Test the mapper for a `calcfunction`.""" | ||
|
||
@calcfunction | ||
def test_calcfunction(): | ||
return | ||
|
||
expected_version = {'version': {'core': version_core, 'plugin': version_core}} | ||
self.assertEqual(self.provider.get_version_info(test_calcfunction), expected_version) | ||
|
||
def test_calc_job(self): | ||
"""Test the mapper for a `CalcJob`.""" | ||
AddArithmeticCalculation = CalculationFactory('arithmetic.add') # pylint: disable=invalid-name | ||
|
||
expected_version = {'version': {'core': version_core, 'plugin': version_core}} | ||
self.assertEqual(self.provider.get_version_info(AddArithmeticCalculation), expected_version) | ||
|
||
def test_work_chain(self): | ||
"""Test the mapper for a `WorkChain`.""" | ||
|
||
class SomeWorkChain(WorkChain): | ||
"""Need to create a dummy class since there is no built-in work chain with entry point in `aiida-core`.""" | ||
|
||
expected_version = {'version': {'core': version_core, 'plugin': version_core}} | ||
self.assertEqual(self.provider.get_version_info(SomeWorkChain), expected_version) |
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
Oops, something went wrong.