Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow empty enabled and disabled keys in caching configuration #3330

Merged
merged 2 commits into from
Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@
aiida/backends/tests/test_nodes.py|
aiida/backends/tests/orm/data/test_remote.py|
aiida/backends/tests/orm/utils/test_loaders.py|
aiida/backends/tests/test_caching_config.py|
aiida/backends/tests/test_plugin_loader.py|
aiida/backends/tests/engine/test_class_loader.py|
aiida/backends/tests/engine/test_daemon.py|
Expand Down
2 changes: 1 addition & 1 deletion aiida/backends/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
'backup_script': ['aiida.backends.tests.test_backup_script'],
'backup_setup_script': ['aiida.backends.tests.test_backup_setup_script'],
'base_dataclasses': ['aiida.backends.tests.test_base_dataclasses'],
'caching_config': ['aiida.backends.tests.test_caching_config'],
'calculation_node': ['aiida.backends.tests.test_calculation_node'],
'cmdline.commands.calcjob': ['aiida.backends.tests.cmdline.commands.test_calcjob'],
'cmdline.commands.code': ['aiida.backends.tests.cmdline.commands.test_code'],
Expand Down Expand Up @@ -108,6 +107,7 @@
'engine.work_chain': ['aiida.backends.tests.engine.test_work_chain'],
'engine.workfunctions': ['aiida.backends.tests.engine.test_workfunctions'],
'generic': ['aiida.backends.tests.test_generic'],
'manage.caching.': ['aiida.backends.tests.manage.test_caching'],
'manage.configuration.config.': ['aiida.backends.tests.manage.configuration.test_config'],
'manage.configuration.migrations.': ['aiida.backends.tests.manage.configuration.migrations.test_migrations'],
'manage.configuration.options.': ['aiida.backends.tests.manage.configuration.test_options'],
Expand Down
123 changes: 123 additions & 0 deletions aiida/backends/tests/manage/test_caching.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# -*- 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 the functionality that reads and modifies the caching configuration file."""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

import tempfile
import unittest
import yaml

from aiida.common import exceptions
from aiida.manage.caching import configure, get_use_cache, enable_caching, disable_caching
from aiida.manage.configuration import get_profile


class CacheConfigTest(unittest.TestCase):
"""Tests the caching configuration."""

def setUp(self):
"""Write a temporary config file, and load the configuration."""
self.config_reference = {
get_profile().name: {
'default': True,
'enabled': ['aiida.calculations:arithmetic.add'],
'disabled': ['aiida.calculations:templatereplacer']
}
}
with tempfile.NamedTemporaryFile() as handle:
yaml.dump(self.config_reference, handle, encoding='utf-8')
configure(config_file=handle.name)

def tearDown(self): # pylint: disable=no-self-use
"""Reset the configuration."""
configure()

def test_empty_enabled_disabled(self): # pylint: disable=no-self-use
"""Test that `aiida.manage.caching.configure` does not except when either `enabled` or `disabled` is `None`.

This will happen when the configuration file specifies either one of the keys but no actual values, e.g.::

profile_name:
default: False
enabled:

In this case, the dictionary parsed by yaml will contain `None` for the `enabled` key.
Now this will be unlikely, but the same holds when all values are commented::

profile_name:
default: False
enabled:
# - aiida.calculations:templatereplacer

which is not unlikely to occurr in the wild.
"""
configuration = {get_profile().name: {'default': True, 'enabled': None, 'disabled': None}}
with tempfile.NamedTemporaryFile() as handle:
yaml.dump(configuration, handle, encoding='utf-8')
configure(config_file=handle.name)

# Check that `get_use_cache` also does not except
get_use_cache(identifier='aiida.calculations:templatereplacer')

def test_invalid_enabled_disabled_directives(self):
"""Test that `configure` raises for invalid enable or disable directives."""

def load_configuration(identifier):
"""Write the caching file for given configuration and load it."""
configuration = {get_profile().name: {'default': True, 'enabled': [identifier]}}
with tempfile.NamedTemporaryFile() as handle:
yaml.dump(configuration, handle, encoding='utf-8')
configure(config_file=handle.name)

with self.assertRaises(exceptions.ConfigurationError):
load_configuration(1) # entry point string needs to be a string

with self.assertRaises(exceptions.ConfigurationError):
load_configuration('templatereplacer') # entry point string needs to be fully qualified

with self.assertRaises(exceptions.ConfigurationError):
load_configuration('calculations:templatereplacer') # entry point string needs to be fully qualified

with self.assertRaises(exceptions.ConfigurationError):
load_configuration('aiida.nonexistent_group:templatereplacer') # invalid entry point group

def test_invalid_config(self):
"""Test `get_use_cache` raises a `TypeError` if identifier is not a valid entry point string."""
with self.assertRaises(TypeError):
get_use_cache(identifier=int)

def test_default(self):
"""Verify that when not specifying any specific identifier, the `default` is used, which is set to `True`."""
self.assertTrue(get_use_cache())

def test_caching_enabled(self):
"""Test `get_use_cache` when specifying identifier."""
self.assertFalse(get_use_cache(identifier='aiida.calculations:templatereplacer'))

def test_contextmanager_enable_explicit(self):
"""Test the `enable_caching` context manager."""
with enable_caching(identifier='aiida.calculations:templatereplacer'):
self.assertTrue(get_use_cache(identifier='aiida.calculations:templatereplacer'))

def test_contextmanager_disable_global(self):
"""Test the `disable_caching` context manager without specific identifier."""
with disable_caching():
self.assertTrue(
get_use_cache(identifier='aiida.calculations:arithmetic.add')
) # explicitly set, hence not overwritten
self.assertFalse(get_use_cache(identifier='aiida.calculations:templatereplacer'))

def test_disable_caching(self):
"""Test the `disable_caching` context manager with specific identifier."""
with disable_caching(identifier='aiida.calculations:arithmetic.add'):
self.assertFalse(get_use_cache(identifier='aiida.calculations:arithmetic.add'))
self.assertTrue(get_use_cache(identifier='aiida.calculations:arithmetic.add'))
63 changes: 0 additions & 63 deletions aiida/backends/tests/test_caching_config.py

This file was deleted.

12 changes: 9 additions & 3 deletions aiida/manage/caching.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,18 @@ def _get_config(config_file):
if key not in DEFAULT_CONFIG:
raise ValueError("Configuration error: Invalid key '{}' in cache_config.yml".format(key))

# Add defaults where config is missing
# Add defaults where key is either completely missing or specifies no values in which case it will be `None`
for key, default_config in DEFAULT_CONFIG.items():
config[key] = config.get(key, default_config)
if key not in config or config[key] is None:
config[key] = default_config

# Validate and load the entry point identifiers
# Validate the entry point identifiers
for key in [ConfigKeys.ENABLED.value, ConfigKeys.DISABLED.value]:

# If the key is defined in the file but contains no values, it will be `None`
if config[key] is None:
continue

for identifier in config[key]:
if not is_valid_entry_point_string(identifier):
raise exceptions.ConfigurationError(
Expand Down
2 changes: 1 addition & 1 deletion aiida/plugins/entry_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def is_valid_entry_point_string(entry_point_string):
"""
try:
group, name = entry_point_string.split(ENTRY_POINT_STRING_SEPARATOR)
except (TypeError, ValueError):
except (AttributeError, ValueError):
# Either `entry_point_string` is not a string or it does not contain the separator
return False

Expand Down