Skip to content

Commit f9d3a0e

Browse files
authored
Merge branch 'develop' into bugfix/daemon-pid-recycling
2 parents 057c8a5 + f99f1e8 commit f9d3a0e

File tree

20 files changed

+223
-91
lines changed

20 files changed

+223
-91
lines changed

aiida/backends/djsite/db/migrations/0033_replace_text_field_with_json_field.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from django.db import migrations
1717

1818
from aiida.backends.djsite.db.migrations import upgrade_schema_version
19+
from aiida.common.json import JSONEncoder
1920

2021
REVISION = '1.0.33'
2122
DOWN_REVISION = '1.0.32'
@@ -32,27 +33,27 @@ class Migration(migrations.Migration):
3233
migrations.AlterField(
3334
model_name='dbauthinfo',
3435
name='auth_params',
35-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
36+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, encoder=JSONEncoder),
3637
),
3738
migrations.AlterField(
3839
model_name='dbauthinfo',
3940
name='metadata',
40-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
41+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, encoder=JSONEncoder),
4142
),
4243
migrations.AlterField(
4344
model_name='dbcomputer',
4445
name='metadata',
45-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
46+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, encoder=JSONEncoder),
4647
),
4748
migrations.AlterField(
4849
model_name='dbcomputer',
4950
name='transport_params',
50-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
51+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, encoder=JSONEncoder),
5152
),
5253
migrations.AlterField(
5354
model_name='dblog',
5455
name='metadata',
55-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
56+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, encoder=JSONEncoder),
5657
),
5758
upgrade_schema_version(REVISION, DOWN_REVISION)
5859
]

aiida/backends/djsite/db/migrations/0037_attributes_extras_settings_json.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from aiida.backends.djsite.db.migrations import upgrade_schema_version
2121
from aiida.cmdline.utils import echo
22+
from aiida.common.json import JSONEncoder
2223
from aiida.common.timezone import datetime_to_isoformat
2324

2425
REVISION = '1.0.37'
@@ -202,12 +203,12 @@ class Migration(migrations.Migration):
202203
migrations.AddField(
203204
model_name='dbnode',
204205
name='attributes',
205-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=True),
206+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=True, encoder=JSONEncoder),
206207
),
207208
migrations.AddField(
208209
model_name='dbnode',
209210
name='extras',
210-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=True),
211+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=True, encoder=JSONEncoder),
211212
),
212213
# Migrate the data from the DbAttribute table to the JSONB field
213214
migrations.RunPython(transition_attributes_extras, reverse_code=migrations.RunPython.noop),
@@ -232,7 +233,7 @@ class Migration(migrations.Migration):
232233
migrations.AddField(
233234
model_name='dbsetting',
234235
name='val',
235-
field=django.contrib.postgres.fields.jsonb.JSONField(default=None, null=True),
236+
field=django.contrib.postgres.fields.jsonb.JSONField(default=None, null=True, encoder=JSONEncoder),
236237
),
237238
# Migrate the data from the DbSetting EAV to the JSONB val field
238239
migrations.RunPython(transition_settings, reverse_code=migrations.RunPython.noop),

aiida/backends/djsite/db/migrations/0045_dbgroup_extras.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
# pylint: disable=invalid-name
1212
import django.contrib.postgres.fields.jsonb
1313
from django.db import migrations
14+
1415
from aiida.backends.djsite.db.migrations import upgrade_schema_version
16+
from aiida.common.json import JSONEncoder
1517

1618
REVISION = '1.0.45'
1719
DOWN_REVISION = '1.0.44'
@@ -27,7 +29,7 @@ class Migration(migrations.Migration):
2729
migrations.AddField(
2830
model_name='dbgroup',
2931
name='extras',
30-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=False),
32+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=False, encoder=JSONEncoder),
3133
),
3234
upgrade_schema_version(REVISION, DOWN_REVISION),
3335
]

aiida/backends/djsite/db/migrations/0046_add_node_repository_metadata.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
# pylint: disable=no-name-in-module,import-error
1414
import django.contrib.postgres.fields.jsonb
1515
from django.db import migrations
16+
1617
from aiida.backends.djsite.db.migrations import upgrade_schema_version
18+
from aiida.common.json import JSONEncoder
1719

1820
REVISION = '1.0.46'
1921
DOWN_REVISION = '1.0.45'
@@ -30,7 +32,7 @@ class Migration(migrations.Migration):
3032
migrations.AddField(
3133
model_name='dbnode',
3234
name='repository_metadata',
33-
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=True),
35+
field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, null=True, encoder=JSONEncoder),
3436
),
3537
upgrade_schema_version(REVISION, DOWN_REVISION),
3638
]

aiida/backends/djsite/db/models.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import aiida.backends.djsite.db.migrations as migrations
2020
from aiida.common import timezone
21+
from aiida.common.json import JSONEncoder
2122
from aiida.common.utils import get_new_uuid
2223

2324
# This variable identifies the schema version of this file.
@@ -124,10 +125,10 @@ class DbNode(m.Model):
124125
dbcomputer = m.ForeignKey('DbComputer', null=True, on_delete=m.PROTECT, related_name='dbnodes')
125126

126127
# JSON Attributes
127-
attributes = JSONField(default=dict, null=True)
128+
attributes = JSONField(default=dict, null=True, encoder=JSONEncoder)
128129
# JSON Extras
129-
extras = JSONField(default=dict, null=True)
130-
repository_metadata = JSONField(default=dict, null=True)
130+
extras = JSONField(default=dict, null=True, encoder=JSONEncoder)
131+
repository_metadata = JSONField(default=dict, null=True, encoder=JSONEncoder)
131132

132133
objects = m.Manager()
133134
# Return aiida Node instances or their subclasses instead of DbNode instances
@@ -184,7 +185,7 @@ def __str__(self):
184185
class DbSetting(m.Model):
185186
"""This will store generic settings that should be database-wide."""
186187
key = m.CharField(max_length=1024, db_index=True, blank=False, unique=True)
187-
val = JSONField(default=None, null=True)
188+
val = JSONField(default=None, null=True, encoder=JSONEncoder)
188189
# I also add a description field for the variables
189190
description = m.TextField(blank=True)
190191
# Modification time of this attribute
@@ -256,7 +257,7 @@ class DbGroup(m.Model):
256257
# the groups
257258
user = m.ForeignKey(DbUser, on_delete=m.CASCADE, related_name='dbgroups')
258259
# JSON Extras
259-
extras = JSONField(default=dict, null=False)
260+
extras = JSONField(default=dict, null=False, encoder=JSONEncoder)
260261

261262
class Meta:
262263
unique_together = (('label', 'type_string'),)
@@ -303,7 +304,7 @@ class DbComputer(m.Model):
303304
description = m.TextField(blank=True)
304305
scheduler_type = m.CharField(max_length=255)
305306
transport_type = m.CharField(max_length=255)
306-
metadata = JSONField(default=dict)
307+
metadata = JSONField(default=dict, encoder=JSONEncoder)
307308

308309
def __str__(self):
309310
return f'{self.label} ({self.hostname})'
@@ -317,12 +318,12 @@ class DbAuthInfo(m.Model):
317318
# Delete the DbAuthInfo if either the user or the computer are removed
318319
aiidauser = m.ForeignKey(DbUser, on_delete=m.CASCADE)
319320
dbcomputer = m.ForeignKey(DbComputer, on_delete=m.CASCADE)
320-
auth_params = JSONField(default=dict) # contains mainly the remoteuser and the private_key
321+
auth_params = JSONField(default=dict, encoder=JSONEncoder) # contains mainly the remoteuser and the private_key
321322

322323
# The keys defined in the metadata of the DbAuthInfo will override the
323324
# keys with the same label defined in the DbComputer (using a dict.update()
324325
# call of python).
325-
metadata = JSONField(default=dict)
326+
metadata = JSONField(default=dict, encoder=JSONEncoder)
326327
# Whether this computer is enabled (user-level enabling feature)
327328
enabled = m.BooleanField(default=True)
328329

@@ -361,7 +362,7 @@ class DbLog(m.Model):
361362
levelname = m.CharField(max_length=50, db_index=True)
362363
dbnode = m.ForeignKey(DbNode, related_name='dblogs', on_delete=m.CASCADE)
363364
message = m.TextField(blank=True)
364-
metadata = JSONField(default=dict)
365+
metadata = JSONField(default=dict, encoder=JSONEncoder)
365366

366367
def __str__(self):
367368
return f'DbLog: {self.levelname} for node {self.dbnode.id}: {self.message}'

aiida/cmdline/commands/cmd_group.py

+25-30
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def verdi_group():
3232
def group_add_nodes(group, force, nodes):
3333
"""Add nodes to a group."""
3434
if not force:
35-
click.confirm(f'Do you really want to add {len(nodes)} nodes to Group<{group.label}>?', abort=True)
35+
click.confirm(f'Do you really want to add {len(nodes)} nodes to {group}?', abort=True)
3636

3737
group.add_nodes(nodes)
3838

@@ -47,9 +47,6 @@ def group_remove_nodes(group, nodes, clear, force):
4747
"""Remove nodes from a group."""
4848
from aiida.orm import QueryBuilder, Group, Node
4949

50-
label = group.label
51-
klass = group.__class__.__name__
52-
5350
if nodes and clear:
5451
echo.echo_critical(
5552
'Specify either the `--clear` flag to remove all nodes or the identifiers of the nodes you want to remove.'
@@ -67,18 +64,18 @@ def group_remove_nodes(group, nodes, clear, force):
6764
group_node_pks = query.all(flat=True)
6865

6966
if not group_node_pks:
70-
echo.echo_critical(f'None of the specified nodes are in {klass}<{label}>.')
67+
echo.echo_critical(f'None of the specified nodes are in {group}.')
7168

7269
if len(node_pks) > len(group_node_pks):
7370
node_pks = set(node_pks).difference(set(group_node_pks))
74-
echo.echo_warning(f'{len(node_pks)} nodes with PK {node_pks} are not in {klass}<{label}>.')
71+
echo.echo_warning(f'{len(node_pks)} nodes with PK {node_pks} are not in {group}.')
7572

76-
message = f'Are you sure you want to remove {len(group_node_pks)} nodes from {klass}<{label}>?'
73+
message = f'Are you sure you want to remove {len(group_node_pks)} nodes from {group}?'
7774

7875
elif clear:
79-
message = f'Are you sure you want to remove ALL the nodes from {klass}<{label}>?'
76+
message = f'Are you sure you want to remove ALL the nodes from {group}?'
8077
else:
81-
echo.echo_critical(f'No nodes were provided for removal from {klass}<{label}>.')
78+
echo.echo_critical(f'No nodes were provided for removal from {group}.')
8279

8380
click.confirm(message, abort=True)
8481

@@ -104,24 +101,21 @@ def group_delete(group, delete_nodes, dry_run, force, verbose, **traversal_rules
104101
from aiida.tools import delete_group_nodes, DELETE_LOGGER
105102
from aiida import orm
106103

107-
label = group.label
108-
klass = group.__class__.__name__
109-
110104
verbosity = logging.DEBUG if verbose else logging.INFO
111105
DELETE_LOGGER.setLevel(verbosity)
112106

113107
if not (force or dry_run):
114-
click.confirm(f'Are you sure to delete {klass}<{label}>?', abort=True)
108+
click.confirm(f'Are you sure you want to delete {group}?', abort=True)
115109
elif dry_run:
116-
echo.echo_info(f'Would have deleted {klass}<{label}>.')
110+
echo.echo_info(f'Would have deleted {group}.')
117111

118112
if delete_nodes:
119113

120114
def _dry_run_callback(pks):
121115
if not pks or force:
122116
return False
123117
echo.echo_warning(f'YOU ARE ABOUT TO DELETE {len(pks)} NODES! THIS CANNOT BE UNDONE!')
124-
return not click.confirm('Shall I continue?', abort=True)
118+
return not click.confirm('Do you want to continue?', abort=True)
125119

126120
with override_log_formatter_context('%(message)s'):
127121
_, nodes_deleted = delete_group_nodes([group.pk], dry_run=dry_run or _dry_run_callback, **traversal_rules)
@@ -130,8 +124,9 @@ def _dry_run_callback(pks):
130124
return
131125

132126
if not dry_run:
127+
group_str = str(group)
133128
orm.Group.objects.delete(group.pk)
134-
echo.echo_success(f'{klass}<{label}> deleted.')
129+
echo.echo_success(f'{group_str} deleted.')
135130

136131

137132
@verdi_group.command('relabel')
@@ -143,9 +138,9 @@ def group_relabel(group, label):
143138
try:
144139
group.label = label
145140
except UniquenessError as exception:
146-
echo.echo_critical(f'Error: {exception}.')
141+
echo.echo_critical(str(exception))
147142
else:
148-
echo.echo_success(f'Label changed to {label}')
143+
echo.echo_success(f"Label changed to '{label}'")
149144

150145

151146
@verdi_group.command('description')
@@ -155,11 +150,11 @@ def group_relabel(group, label):
155150
def group_description(group, description):
156151
"""Change the description of a group.
157152
158-
If no DESCRIPTION is defined, the current description will simply be echoed.
153+
If no description is defined, the current description will simply be echoed.
159154
"""
160155
if description:
161156
group.description = description
162-
echo.echo_success(f'Changed the description of Group<{group.label}>')
157+
echo.echo_success(f'Changed the description of {group}.')
163158
else:
164159
echo.echo(group.description)
165160

@@ -172,7 +167,7 @@ def group_description(group, description):
172167
'--uuid',
173168
is_flag=True,
174169
default=False,
175-
help='Show UUIDs together with PKs. Note: if the --raw option is also passed, PKs are not printed, but oly UUIDs.'
170+
help='Show UUIDs together with PKs. Note: if the --raw option is also passed, PKs are not printed, but only UUIDs.'
176171
)
177172
@arguments.GROUP()
178173
@with_dbenv()
@@ -223,7 +218,7 @@ def group_show(group, raw, limit, uuid):
223218

224219
@verdi_group.command('list')
225220
@options.ALL_USERS(help='Show groups for all users, rather than only for the current user.')
226-
@options.USER(help='Add a filter to show only groups belonging to a specific user')
221+
@options.USER(help='Add a filter to show only groups belonging to a specific user.')
227222
@options.ALL(help='Show groups of all types.')
228223
@options.TYPE_STRING()
229224
@click.option(
@@ -292,7 +287,7 @@ def group_list(
292287
if past_days:
293288
filters['time'] = {'>': timezone.now() - datetime.timedelta(days=past_days)}
294289

295-
# Query for specific group names
290+
# Query for specific group labels
296291
filters['or'] = []
297292
if startswith:
298293
filters['or'].append({'label': {'like': f'{escape_for_sql_like(startswith)}%'}})
@@ -346,10 +341,10 @@ def group_list(
346341
table.append([projection_lambdas[field](group[0]) for field in projection_fields])
347342

348343
if not all_entries:
349-
echo.echo_info('to show groups of all types, use the `-a/--all` option.')
344+
echo.echo_info('To show groups of all types, use the `-a/--all` option.')
350345

351346
if not table:
352-
echo.echo_info('no groups found matching the specified criteria.')
347+
echo.echo_info('No groups found matching the specified criteria.')
353348
else:
354349
echo.echo(tabulate(table, headers=projection_header))
355350

@@ -358,15 +353,15 @@ def group_list(
358353
@click.argument('group_label', nargs=1, type=click.STRING)
359354
@with_dbenv()
360355
def group_create(group_label):
361-
"""Create an empty group with a given name."""
356+
"""Create an empty group with a given label."""
362357
from aiida import orm
363358

364359
group, created = orm.Group.objects.get_or_create(label=group_label)
365360

366361
if created:
367-
echo.echo_success(f"Group created with PK = {group.id} and name '{group.label}'")
362+
echo.echo_success(f"Group created with PK = {group.pk} and label '{group.label}'.")
368363
else:
369-
echo.echo_info(f"Group '{group.label}' already exists, PK = {group.id}")
364+
echo.echo_info(f"Group with label '{group.label}' already exists: {group}.")
370365

371366

372367
@verdi_group.command('copy')
@@ -384,12 +379,12 @@ def group_copy(source_group, destination_group):
384379

385380
# Issue warning if destination group is not empty and get user confirmation to continue
386381
if not created and not dest_group.is_empty:
387-
echo.echo_warning(f'Destination group<{dest_group.label}> already exists and is not empty.')
382+
echo.echo_warning(f'Destination {dest_group} already exists and is not empty.')
388383
click.confirm('Do you wish to continue anyway?', abort=True)
389384

390385
# Copy nodes
391386
dest_group.add_nodes(list(source_group.nodes))
392-
echo.echo_success(f'Nodes copied from group<{source_group.label}> to group<{dest_group.label}>')
387+
echo.echo_success(f'Nodes copied from {source_group} to {dest_group}.')
393388

394389

395390
@verdi_group.group('path')

0 commit comments

Comments
 (0)