Skip to content

Commit f40f0d2

Browse files
Ensure unicity when creating instances of Autogroup (#3650)
The default label of an `Autogroup` instance was based on the current date and time, with a precision of seconds. If multiple scripts attempted to create an instance at the same time, a uniqueness error would be thrown by the database. This commit adds the logic to the `get_or_create_group` method to be able to deal with this situtation and iteratively generate unique labels by appending an integer. The CLI parameters of the `verdi run` command were broken and badly tested. These have been altered so as to fix the behavior: * removed the `--group` flag, which was true by default and so served no purpose whatsoever, and replaced it with `--auto-group`. The auto grouping is now disabled by default, but can be enabled by this new flag. * deprecated use of `group-name' in favour of `group-label-prefix` * the flags to include or exclude certain node types have been merged into just `--exclude` and `--include` which are mutually exclusive. By default everything is included and the flags take entry point strings of nodes to narrow the scope. The entry point string can contain SQL wildcards `%` and `_` to match entry points with the `like` operator. The `Autogroup` interface has been adapted to match the new logic of the CLI. Finally, an overzealous `isinstance` check has been removed from the `Node.store` method to check that the `current_autogroup` global, if set, is of type `Autogroup`, which should speed up the storing of nodes.
1 parent 161eeae commit f40f0d2

File tree

24 files changed

+877
-255
lines changed

24 files changed

+877
-255
lines changed

.ci/workchains.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ def a_magic_unicorn_appeared(self, node):
6868
@process_handler(priority=400, exit_codes=ArithmeticAddCalculation.exit_codes.ERROR_NEGATIVE_NUMBER)
6969
def error_negative_sum(self, node):
7070
"""What even is a negative number, how can I have minus three melons?!."""
71-
self.ctx.inputs.x = Int(abs(node.inputs.x.value))
72-
self.ctx.inputs.y = Int(abs(node.inputs.y.value))
71+
self.ctx.inputs.x = Int(abs(node.inputs.x.value)) # pylint: disable=invalid-name
72+
self.ctx.inputs.y = Int(abs(node.inputs.y.value)) # pylint: disable=invalid-name
7373
return ProcessHandlerReport(True)
7474

7575

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
.cache
2121
.pytest_cache
2222
.coverage
23+
coverage.xml
2324

2425
# Files created by RPN tests
2526
.ci/polish/polish_workchains/polish*

.pre-commit-config.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
aiida/common/datastructures.py|
5454
aiida/engine/daemon/execmanager.py|
5555
aiida/engine/processes/calcjobs/tasks.py|
56-
aiida/orm/autogroup.py|
5756
aiida/orm/querybuilder.py|
5857
aiida/orm/nodes/data/array/bands.py|
5958
aiida/orm/nodes/data/array/projection.py|
@@ -66,7 +65,6 @@
6665
aiida/parsers/plugins/arithmetic/add.py|
6766
aiida/parsers/plugins/templatereplacer/doubler.py|
6867
aiida/parsers/plugins/templatereplacer/__init__.py|
69-
aiida/plugins/entry_point.py|
7068
aiida/plugins/entry.py|
7169
aiida/plugins/info.py|
7270
aiida/plugins/registry.py|

aiida/backends/testbase.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ def tearDown(self):
9999

100100
def reset_database(self):
101101
"""Reset the database to the default state deleting any content currently stored"""
102+
from aiida.orm import autogroup
103+
102104
self.clean_db()
105+
if autogroup.CURRENT_AUTOGROUP is not None:
106+
autogroup.CURRENT_AUTOGROUP.clear_group_cache()
103107
self.insert_data()
104108

105109
@classmethod
@@ -109,7 +113,10 @@ def insert_data(cls):
109113
inserts default data into the database (which is for the moment a
110114
default computer).
111115
"""
116+
from aiida.orm import User
117+
112118
cls.create_user()
119+
User.objects.reset()
113120
cls.create_computer()
114121

115122
@classmethod
@@ -180,7 +187,11 @@ def user_email(cls): # pylint: disable=no-self-argument
180187
def tearDownClass(cls, *args, **kwargs): # pylint: disable=arguments-differ
181188
# Double check for double security to avoid to run the tearDown
182189
# if this is not a test profile
190+
from aiida.orm import autogroup
191+
183192
check_if_tests_can_run()
193+
if autogroup.CURRENT_AUTOGROUP is not None:
194+
autogroup.CURRENT_AUTOGROUP.clear_group_cache()
184195
cls.clean_db()
185196
cls.clean_repository()
186197
cls.__backend_instance.tearDownClass_method(*args, **kwargs)

aiida/cmdline/commands/cmd_plugin.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from aiida.cmdline.commands.cmd_verdi import verdi
1515
from aiida.cmdline.utils import decorators, echo
16-
from aiida.plugins.entry_point import entry_point_group_to_module_path_map
16+
from aiida.plugins.entry_point import ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP
1717

1818

1919
@verdi.group('plugin')
@@ -22,7 +22,7 @@ def verdi_plugin():
2222

2323

2424
@verdi_plugin.command('list')
25-
@click.argument('entry_point_group', type=click.Choice(entry_point_group_to_module_path_map.keys()), required=False)
25+
@click.argument('entry_point_group', type=click.Choice(ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP.keys()), required=False)
2626
@click.argument('entry_point', type=click.STRING, required=False)
2727
@decorators.with_dbenv()
2828
def plugin_list(entry_point_group, entry_point):
@@ -34,7 +34,7 @@ def plugin_list(entry_point_group, entry_point):
3434

3535
if entry_point_group is None:
3636
echo.echo_info('Available entry point groups:')
37-
for group in sorted(entry_point_group_to_module_path_map.keys()):
37+
for group in sorted(ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP.keys()):
3838
echo.echo('* {}'.format(group))
3939

4040
echo.echo('')

aiida/cmdline/commands/cmd_run.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@
1010
"""`verdi run` command."""
1111
import contextlib
1212
import os
13+
import functools
1314
import sys
15+
import warnings
1416

1517
import click
1618

1719
from aiida.cmdline.commands.cmd_verdi import verdi
1820
from aiida.cmdline.params.options.multivalue import MultipleValueOption
1921
from aiida.cmdline.utils import decorators, echo
22+
from aiida.common.warnings import AiidaDeprecationWarning
2023

2124

2225
@contextlib.contextmanager
@@ -37,31 +40,56 @@ def update_environment(argv):
3740
sys.path = _path
3841

3942

43+
def validate_entrypoint_string(ctx, param, value): # pylint: disable=unused-argument,invalid-name
44+
"""Validate that `value` is a valid entrypoint string."""
45+
from aiida.orm import autogroup
46+
47+
try:
48+
autogroup.Autogroup.validate(value)
49+
except Exception as exc:
50+
raise click.BadParameter(str(exc) + ' ({})'.format(value))
51+
52+
return value
53+
54+
4055
@verdi.command('run', context_settings=dict(ignore_unknown_options=True,))
4156
@click.argument('scriptname', type=click.STRING)
4257
@click.argument('varargs', nargs=-1, type=click.UNPROCESSED)
43-
@click.option('-g', '--group', is_flag=True, default=True, show_default=True, help='Enables the autogrouping')
44-
@click.option('-n', '--group-name', type=click.STRING, required=False, help='Specify the name of the auto group')
45-
@click.option('-e', '--exclude', cls=MultipleValueOption, default=[], help='Exclude these classes from auto grouping')
58+
@click.option('--auto-group', is_flag=True, help='Enables the autogrouping')
59+
@click.option(
60+
'-l',
61+
'--auto-group-label-prefix',
62+
type=click.STRING,
63+
required=False,
64+
help='Specify the prefix of the label of the auto group (numbers might be automatically '
65+
'appended to generate unique names per run).'
66+
)
4667
@click.option(
47-
'-i', '--include', cls=MultipleValueOption, default=['all'], help='Include these classes from auto grouping'
68+
'-n',
69+
'--group-name',
70+
type=click.STRING,
71+
required=False,
72+
help='Specify the name of the auto group [DEPRECATED, USE --auto-group-label-prefix instead]. '
73+
'This also enables auto-grouping.'
4874
)
4975
@click.option(
50-
'-E',
51-
'--excludesubclasses',
76+
'-e',
77+
'--exclude',
5278
cls=MultipleValueOption,
53-
default=[],
54-
help='Exclude these classes and their sub classes from auto grouping'
79+
default=None,
80+
help='Exclude these classes from auto grouping (use full entrypoint strings).',
81+
callback=functools.partial(validate_entrypoint_string)
5582
)
5683
@click.option(
57-
'-I',
58-
'--includesubclasses',
84+
'-i',
85+
'--include',
5986
cls=MultipleValueOption,
60-
default=[],
61-
help='Include these classes and their sub classes from auto grouping'
87+
default=None,
88+
help='Include these classes from auto grouping (use full entrypoint strings or "all").',
89+
callback=validate_entrypoint_string
6290
)
6391
@decorators.with_dbenv()
64-
def run(scriptname, varargs, group, group_name, exclude, excludesubclasses, include, includesubclasses):
92+
def run(scriptname, varargs, auto_group, auto_group_label_prefix, group_name, exclude, include):
6593
# pylint: disable=too-many-arguments,exec-used
6694
"""Execute scripts with preloaded AiiDA environment."""
6795
from aiida.cmdline.utils.shell import DEFAULT_MODULES_LIST
@@ -80,22 +108,27 @@ def run(scriptname, varargs, group, group_name, exclude, excludesubclasses, incl
80108
for app_mod, model_name, alias in DEFAULT_MODULES_LIST:
81109
globals_dict['{}'.format(alias)] = getattr(__import__(app_mod, {}, {}, model_name), model_name)
82110

83-
if group:
84-
automatic_group_name = group_name
85-
if automatic_group_name is None:
86-
from aiida.common import timezone
87-
88-
automatic_group_name = 'Verdi autogroup on ' + timezone.now().strftime('%Y-%m-%d %H:%M:%S')
111+
if group_name:
112+
warnings.warn('--group-name is deprecated, use `--auto-group-label-prefix` instead', AiidaDeprecationWarning) # pylint: disable=no-member
113+
if auto_group_label_prefix:
114+
raise click.BadParameter(
115+
'You cannot specify both --group-name and --auto-group-label-prefix; '
116+
'use --auto-group-label-prefix only'
117+
)
118+
auto_group_label_prefix = group_name
119+
# To have the old behavior, with auto-group enabled.
120+
auto_group = True
89121

122+
if auto_group:
90123
aiida_verdilib_autogroup = autogroup.Autogroup()
124+
# Set the ``group_label_prefix`` if defined, otherwise a default prefix will be used
125+
if auto_group_label_prefix is not None:
126+
aiida_verdilib_autogroup.set_group_label_prefix(auto_group_label_prefix)
91127
aiida_verdilib_autogroup.set_exclude(exclude)
92128
aiida_verdilib_autogroup.set_include(include)
93-
aiida_verdilib_autogroup.set_exclude_with_subclasses(excludesubclasses)
94-
aiida_verdilib_autogroup.set_include_with_subclasses(includesubclasses)
95-
aiida_verdilib_autogroup.set_group_name(automatic_group_name)
96129

97130
# Note: this is also set in the exec environment! This is the intended behavior
98-
autogroup.current_autogroup = aiida_verdilib_autogroup
131+
autogroup.CURRENT_AUTOGROUP = aiida_verdilib_autogroup
99132

100133
# Initialize the variable here, otherwise we get UnboundLocalError in the finally clause if it fails to open
101134
handle = None

aiida/engine/processes/calcjobs/calcjob.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def validate_calc_job(inputs, ctx):
6464
)
6565

6666

67-
def validate_parser(parser_name, ctx):
67+
def validate_parser(parser_name, ctx): # pylint: disable=unused-argument
6868
"""Validate the parser.
6969
7070
:raises InputValidationError: if the parser name does not correspond to a loadable `Parser` class.
@@ -78,7 +78,7 @@ def validate_parser(parser_name, ctx):
7878
raise exceptions.InputValidationError('invalid parser specified: {}'.format(exception))
7979

8080

81-
def validate_resources(resources, ctx):
81+
def validate_resources(resources, ctx): # pylint: disable=unused-argument
8282
"""Validate the resources.
8383
8484
:raises InputValidationError: if `num_machines` is not specified or is not an integer.

aiida/manage/caching.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from aiida.common import exceptions
2323
from aiida.common.lang import type_check
2424

25-
from aiida.plugins.entry_point import ENTRY_POINT_STRING_SEPARATOR, entry_point_group_to_module_path_map
25+
from aiida.plugins.entry_point import ENTRY_POINT_STRING_SEPARATOR, ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP
2626

2727
__all__ = ('get_use_cache', 'enable_caching', 'disable_caching')
2828

@@ -248,7 +248,7 @@ def _validate_identifier_pattern(*, identifier):
248248
249249
1. <group_name><ENTRY_POINT_STRING_SEPARATOR><tail>
250250
251-
where `group_name` is one of the keys in `entry_point_group_to_module_path_map`
251+
where `group_name` is one of the keys in `ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP`
252252
and `tail` can be anything _except_ `ENTRY_POINT_STRING_SEPARATOR`.
253253
254254
2. a fully qualified Python name
@@ -276,7 +276,7 @@ def _validate_identifier_pattern(*, identifier):
276276
group_pattern, _ = identifier.split(ENTRY_POINT_STRING_SEPARATOR)
277277
if not any(
278278
_match_wildcard(string=group_name, pattern=group_pattern)
279-
for group_name in entry_point_group_to_module_path_map
279+
for group_name in ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP
280280
):
281281
raise ValueError(
282282
common_error_msg + "Group name pattern '{}' does not match any of the AiiDA entry point group names.".
@@ -290,7 +290,7 @@ def _validate_identifier_pattern(*, identifier):
290290
# aiida.* or aiida.calculations*
291291
if '*' in identifier:
292292
group_part, _ = identifier.split('*', 1)
293-
if any(group_name.startswith(group_part) for group_name in entry_point_group_to_module_path_map):
293+
if any(group_name.startswith(group_part) for group_name in ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP):
294294
return
295295
# Finally, check if it could be a fully qualified Python name
296296
for identifier_part in identifier.split('.'):

0 commit comments

Comments
 (0)