Skip to content

Commit

Permalink
Renaming and reorganizing some verdi commands (#2204)
Browse files Browse the repository at this point in the history
* Move functionality from `verdi calculation` to `verdi process` and `verdi calcjob`

The functionality that was in `verdi calculation` mostly applied only to calculation
jobs, and not to any other calculations as generated for example with the calcfunction
decorator. Other sub commands were generic enough to be put in `verdi process`. Here
we move this common functionality such as the commands `show` and `logshow` to the
`verdi process` command, renaming `logshow` to `report`.

The remaining commands that apply to job calculations `inputls`, `inputcat`, `outputls`,
`outputcat`, `gotocomputer` and `cleanworkdir` are moved to `verdi calcjob`. The old
commands in `verdi calculation` are all deprecated and automatically forwarded to the
new commands.

* Move functionality from `verdi work` to `verdi process`

The majority of functionality in `verdi work` that was not already deprecated
and moved to `verdi process`, such as `status` and `report` are generally
applicable to all process types. Therefore it makes sense to move everything
there and deprecate the `verdi work` command.

* Add the `verdi plugin` command

This should serve as the central command to list registered plugins
for the various entry point groups, instead of each verdi command having
its own dedicated sub command. The existing sub commands for `verdi data`
`verdi calculation` and `verdi work` have been deprecated and piped through
to the new `verdi plugin` command.
  • Loading branch information
sphuber authored and giovannipizzi committed Nov 16, 2018
1 parent 05113f8 commit 9787be8
Show file tree
Hide file tree
Showing 19 changed files with 1,085 additions and 598 deletions.
1 change: 1 addition & 0 deletions aiida/backends/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
'backup_setup_script': ['aiida.backends.tests.backup_setup_script'],
'restapi': ['aiida.backends.tests.restapi'],
'examplehelpers': ['aiida.backends.tests.example_helpers'],
'cmdline.commands.calcjob': ['aiida.backends.tests.cmdline.commands.test_calcjob'],
'cmdline.commands.calculation': ['aiida.backends.tests.cmdline.commands.test_calculation'],
'cmdline.commands.code': ['aiida.backends.tests.cmdline.commands.test_code'],
'cmdline.commands.comment': ['aiida.backends.tests.cmdline.commands.test_comment'],
Expand Down
236 changes: 236 additions & 0 deletions aiida/backends/tests/cmdline/commands/test_calcjob.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# -*- 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 #
###########################################################################
# pylint: disable=protected-access,too-many-locals,invalid-name,too-many-public-methods
"""Tests for `verdi calcjob`."""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
from click.testing import CliRunner

from aiida.backends.testbase import AiidaTestCase
from aiida.cmdline.commands import cmd_calcjob as command
from aiida.common.datastructures import calc_states
from aiida.orm.node.process.calculation.calcjob import CalcJobExitStatus


def get_result_lines(result):
return [e for e in result.output.split('\n') if e]


class TestVerdiCalculation(AiidaTestCase):
"""Tests for `verdi calcjob`."""

@classmethod
def setUpClass(cls, *args, **kwargs):
super(TestVerdiCalculation, cls).setUpClass(*args, **kwargs)
from aiida.backends.tests.utils.fixtures import import_archive_fixture
from aiida.common.exceptions import ModificationNotAllowed
from aiida.common.links import LinkType
from aiida.orm import Node, CalculationFactory
from aiida.orm.node.process import CalcJobNode
from aiida.orm.data.parameter import ParameterData
from aiida.work.processes import ProcessState
from aiida import orm

cls.computer = orm.Computer(
name='comp',
hostname='localhost',
transport_type='local',
scheduler_type='direct',
workdir='/tmp/aiida',
backend=cls.backend).store()

cls.code = orm.Code(remote_computer_exec=(cls.computer, '/bin/true')).store()
cls.group = orm.Group(name='test_group').store()
cls.node = Node().store()
cls.calcs = []

user = orm.User.objects(cls.backend).get_default()
authinfo = orm.AuthInfo(computer=cls.computer, user=user, backend=cls.backend)
authinfo.store()

# Create 13 CalcJobNodes (one for each CalculationState)
for calcjob_state in calc_states:

calc = CalcJobNode(
computer=cls.computer, resources={
'num_machines': 1,
'num_mpiprocs_per_machine': 1
}).store()

# Trying to set NEW will raise, but in this case we don't need to change the state
try:
calc._set_state(calcjob_state)
except ModificationNotAllowed:
pass

try:
exit_status = CalcJobExitStatus[calcjob_state]
except KeyError:
if calcjob_state == 'IMPORTED':
calc._set_process_state(ProcessState.FINISHED)
else:
calc._set_process_state(ProcessState.RUNNING)
else:
calc._set_exit_status(exit_status)
calc._set_process_state(ProcessState.FINISHED)

cls.calcs.append(calc)

if calcjob_state == 'PARSING':
cls.KEY_ONE = 'key_one'
cls.KEY_TWO = 'key_two'
cls.VAL_ONE = 'val_one'
cls.VAL_TWO = 'val_two'

output_parameters = ParameterData(dict={
cls.KEY_ONE: cls.VAL_ONE,
cls.KEY_TWO: cls.VAL_TWO,
}).store()

output_parameters.add_link_from(calc, 'output_parameters', link_type=LinkType.RETURN)

# Create shortcut for easy dereferencing
cls.result_job = calc

# Add a single calc to a group
cls.group.add_nodes([calc])

# Load the fixture containing a single ArithmeticAddCalculation node
import_archive_fixture('calcjob/arithmetic.add.aiida')

# Get the imported ArithmeticAddCalculation node
ArithmeticAddCalculation = CalculationFactory('arithmetic.add')
calcjobs = orm.QueryBuilder(backend=cls.backend).append(ArithmeticAddCalculation).all()[0]
cls.arithmetic_job = calcjobs[0]

def setUp(self):
self.cli_runner = CliRunner()

def test_calcjob_res(self):
"""Test verdi calcjob res"""
options = [str(self.result_job.uuid)]
result = self.cli_runner.invoke(command.calcjob_res, options)
self.assertIsNone(result.exception, result.output)
self.assertIn(self.KEY_ONE, result.output)
self.assertIn(self.VAL_ONE, result.output)
self.assertIn(self.KEY_TWO, result.output)
self.assertIn(self.VAL_TWO, result.output)

for flag in ['-k', '--keys']:
options = [flag, self.KEY_ONE, '--', str(self.result_job.uuid)]
result = self.cli_runner.invoke(command.calcjob_res, options)
self.assertIsNone(result.exception, result.output)
self.assertIn(self.KEY_ONE, result.output)
self.assertIn(self.VAL_ONE, result.output)
self.assertNotIn(self.KEY_TWO, result.output)
self.assertNotIn(self.VAL_TWO, result.output)

def test_calcjob_inputls(self):
"""Test verdi calcjob inputls"""
options = []
result = self.cli_runner.invoke(command.calcjob_inputls, options)
self.assertIsNotNone(result.exception)

options = [self.arithmetic_job.uuid]
result = self.cli_runner.invoke(command.calcjob_inputls, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 3)
self.assertIn('.aiida', get_result_lines(result))
self.assertIn('aiida.in', get_result_lines(result))
self.assertIn('_aiidasubmit.sh', get_result_lines(result))

options = [self.arithmetic_job.uuid, '.aiida']
result = self.cli_runner.invoke(command.calcjob_inputls, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 2)
self.assertIn('calcinfo.json', get_result_lines(result))
self.assertIn('job_tmpl.json', get_result_lines(result))

def test_calcjob_outputls(self):
"""Test verdi calcjob outputls"""
options = []
result = self.cli_runner.invoke(command.calcjob_outputls, options)
self.assertIsNotNone(result.exception)

options = [self.arithmetic_job.uuid]
result = self.cli_runner.invoke(command.calcjob_outputls, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 3)
self.assertIn('_scheduler-stderr.txt', get_result_lines(result))
self.assertIn('_scheduler-stdout.txt', get_result_lines(result))
self.assertIn('aiida.out', get_result_lines(result))

options = [self.arithmetic_job.uuid, 'aiida.out']
result = self.cli_runner.invoke(command.calcjob_outputls, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 1)
self.assertIn('aiida.out', get_result_lines(result))

def test_calcjob_inputcat(self):
"""Test verdi calcjob inputcat"""
options = []
result = self.cli_runner.invoke(command.calcjob_inputcat, options)
self.assertIsNotNone(result.exception)

options = [self.arithmetic_job.uuid]
result = self.cli_runner.invoke(command.calcjob_inputcat, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 1)
self.assertEqual(get_result_lines(result)[0], '2 3')

options = [self.arithmetic_job.uuid, 'aiida.in']
result = self.cli_runner.invoke(command.calcjob_inputcat, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 1)
self.assertEqual(get_result_lines(result)[0], '2 3')

def test_calcjob_outputcat(self):
"""Test verdi calcjob outputcat"""
options = []
result = self.cli_runner.invoke(command.calcjob_outputcat, options)
self.assertIsNotNone(result.exception)

options = [self.arithmetic_job.uuid]
result = self.cli_runner.invoke(command.calcjob_outputcat, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 1)
self.assertEqual(get_result_lines(result)[0], '5')

options = [self.arithmetic_job.uuid, 'aiida.out']
result = self.cli_runner.invoke(command.calcjob_outputcat, options)
self.assertIsNone(result.exception, result.output)
self.assertEqual(len(get_result_lines(result)), 1)
self.assertEqual(get_result_lines(result)[0], '5')

def test_calcjob_cleanworkdir(self):
"""Test verdi calcjob cleanworkdir"""

# Specifying no filtering options and no explicit calcjobs should exit with non-zero status
options = []
result = self.cli_runner.invoke(command.calcjob_cleanworkdir, options)
self.assertIsNotNone(result.exception)

# Cannot specify both -p and -o options
for flag_p in ['-p', '--past-days']:
for flag_o in ['-o', '--older-than']:
options = [flag_p, '5', flag_o, '1']
result = self.cli_runner.invoke(command.calcjob_cleanworkdir, options)
self.assertIsNotNone(result.exception)

# Without the force flag it should fail
options = [str(self.result_job.uuid)]
result = self.cli_runner.invoke(command.calcjob_cleanworkdir, options)
self.assertIsNotNone(result.exception)

# With force flag we should find one calcjob
options = ['-f', str(self.result_job.uuid)]
result = self.cli_runner.invoke(command.calcjob_cleanworkdir, options)
self.assertIsNone(result.exception, result.output)
24 changes: 3 additions & 21 deletions aiida/backends/tests/cmdline/commands/test_calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def setUpClass(cls, *args, **kwargs):
cls.group.add_nodes([calc])

# Load the fixture containing a single ArithmeticAddCalculation node
import_archive_fixture('calculation/arithmetic.add.aiida')
import_archive_fixture('calcjob/arithmetic.add.aiida')

# Get the imported ArithmeticAddCalculation node
ArithmeticAddCalculation = CalculationFactory('arithmetic.add')
Expand Down Expand Up @@ -165,7 +165,7 @@ def test_calculation_list_all(self):
options = ['-r', flag]
result = self.cli_runner.invoke(command.calculation_list, options)
self.assertIsNone(result.exception, result.output)
self.assertEquals(len(get_result_lines(result)), 13)
self.assertEquals(len(get_result_lines(result)), 14, result.output)

def test_calculation_list_limit(self):
"""Test verdi calculation list with the limit option"""
Expand All @@ -176,14 +176,6 @@ def test_calculation_list_limit(self):
self.assertIsNone(result.exception, result.output)
self.assertEquals(len(get_result_lines(result)), limit)

def test_calculation_list_group(self):
"""Test verdi calculation list with the group option"""
for flag in ['-G', '--groups']:
options = ['-r', '-a', flag, self.group.uuid]
result = self.cli_runner.invoke(command.calculation_list, options)
self.assertIsNone(result.exception, result.output)
self.assertEquals(len(get_result_lines(result)), 1)

def test_calculation_list_project(self):
"""Test verdi calculation list with the project option"""
for flag in ['-P', '--project']:
Expand All @@ -195,16 +187,6 @@ def test_calculation_list_project(self):
for line in get_result_lines(result):
self.assertIn(int(line), valid_pks)

def test_calculation_list_calculation_state(self):
"""Test verdi calculation list with the calculation state filter"""
for flag in ['-s', '--calculation-state']:
for state in calc_states:
# Each valid state should have exactly one entry
options = ['-r', flag, state]
result = self.cli_runner.invoke(command.calculation_list, options)
self.assertIsNone(result.exception, result.output)
self.assertEquals(len(get_result_lines(result)), 1)

def test_calculation_list_process_state(self):
"""Test verdi calculation list with the process state filter"""
for flag in ['-S', '--process-state']:
Expand All @@ -216,7 +198,7 @@ def test_calculation_list_process_state(self):
self.assertIsNone(result.exception, result.output)

if state == 'finished':
self.assertEquals(len(get_result_lines(result)), 6, result.output)
self.assertEquals(len(get_result_lines(result)), 7, result.output)
else:
self.assertEquals(len(get_result_lines(result)), 7, result.output)

Expand Down
2 changes: 1 addition & 1 deletion aiida/backends/tests/cmdline/commands/test_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test_import_archive(self):
replaced with the version of the new format
"""
archives = [
get_archive_file('calculation/arithmetic.add.aiida'),
get_archive_file('calcjob/arithmetic.add.aiida'),
get_archive_file('export/migrate/export_v0.3.aiida')
]

Expand Down
Loading

0 comments on commit 9787be8

Please sign in to comment.