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

Deprecate methods that refer to a computer's label as name #4309

Merged
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
2 changes: 1 addition & 1 deletion aiida/cmdline/commands/cmd_calcjob.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,4 @@ def calcjob_cleanworkdir(calcjobs, past_days, older_than, computers, force):
clean_remote(transport, path)
counter += 1

echo.echo_success('{} remote folders cleaned on {}'.format(counter, computer.name))
echo.echo_success('{} remote folders cleaned on {}'.format(counter, computer.label))
37 changes: 33 additions & 4 deletions aiida/cmdline/commands/cmd_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def get_default(key, ctx):


def get_computer_name(ctx):
return getattr(ctx.code_builder, 'computer').name
return getattr(ctx.code_builder, 'computer').label


def get_on_computer(ctx):
Expand Down Expand Up @@ -168,7 +168,36 @@ def code_duplicate(ctx, code, non_interactive, **kwargs):
@with_dbenv()
def show(code, verbose):
"""Display detailed information for a code."""
click.echo(tabulate.tabulate(code.get_full_text_info(verbose)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, can I ask what is the intended purpose of the commands show and computer_show modified in this PR? Because I'm not sure I understand why you are removing the general get_full_text_info method to implement two relatively similar versions directly into each of those commands.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that one is verdi code show and the other verdi computer show. I removed the methods from the classes because they don't really belong there. Especially the Computer one was bad since it was baking in the formatting. It was returning a string fully formatted. This is really inflexible as the caller cannot do anything to modify it. The Code one is already slightly better since it simply returned a list of tuples. Still I think deciding what information should be displayed is still very situation dependent and so there is no need to have a dedicated method for this. It was no wonder that the methods were also just used in one place, namely the show CLI commands. Might as well put that logic there so it has all the freedom it needs to choose what and how to display the information

Copy link
Member

@ramirezfranciscof ramirezfranciscof Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see, I didn't notice these were methods of different classes. Thanks!

from aiida.orm.utils.repository import FileType

table = []
table.append(['PK', code.pk])
table.append(['UUID', code.uuid])
table.append(['Label', code.label])
table.append(['Description', code.description])
table.append(['Default plugin', code.get_input_plugin_name()])

if code.is_local():
table.append(['Type', 'local'])
table.append(['Exec name', code.get_execname()])
table.append(['List of files/folders:', ''])
for obj in code.list_objects():
if obj.type == FileType.DIRECTORY:
table.append(['directory', obj.name])
else:
table.append(['file', obj.name])
else:
table.append(['Type', 'remote'])
table.append(['Remote machine', code.get_remote_computer().label])
table.append(['Remote absolute path', code.get_remote_exec_path()])

table.append(['Prepend text', code.get_prepend_text()])
table.append(['Append text', code.get_append_text()])

if verbose:
table.append(['Calculations', len(code.get_outgoing().all())])

click.echo(tabulate.tabulate(table))


@verdi_code.command()
Expand Down Expand Up @@ -225,7 +254,7 @@ def relabel(code, label):
try:
code.relabel(label)
except InputValidationError as exception:
echo.echo_critical('invalid code name: {}'.format(exception))
echo.echo_critical('invalid code label: {}'.format(exception))
else:
echo.echo_success('Code<{}> relabeled from {} to {}'.format(code.pk, old_label, code.full_label))

Expand All @@ -249,7 +278,7 @@ def code_list(computer, input_plugin, all_entries, all_users, show_owner):

qb_computer_filters = dict()
if computer is not None:
qb_computer_filters['name'] = computer.name
qb_computer_filters['name'] = computer.label

qb_code_filters = dict()
if input_plugin is not None:
Expand Down
86 changes: 54 additions & 32 deletions aiida/cmdline/commands/cmd_computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@
###########################################################################
# pylint: disable=invalid-name,too-many-statements,too-many-branches
"""`verdi computer` command."""

from functools import partial

import click
import tabulate

from aiida.cmdline.commands.cmd_verdi import verdi
from aiida.cmdline.params import options, arguments
from aiida.cmdline.params.options.commands import computer as options_computer
from aiida.cmdline.utils import echo
from aiida.cmdline.utils.decorators import with_dbenv
from aiida.cmdline.utils.decorators import with_dbenv, deprecated_command
from aiida.cmdline.utils.multi_line_input import ensure_scripts
from aiida.common.exceptions import ValidationError, InputValidationError
from aiida.plugins.entry_point import get_entry_points
Expand Down Expand Up @@ -260,10 +260,10 @@ def computer_setup(ctx, non_interactive, **kwargs):
except ValidationError as err:
echo.echo_critical('unable to store the computer: {}. Exiting...'.format(err))
else:
echo.echo_success('Computer<{}> {} created'.format(computer.pk, computer.name))
echo.echo_success('Computer<{}> {} created'.format(computer.pk, computer.label))

echo.echo_info('Note: before the computer can be used, it has to be configured with the command:')
echo.echo_info(' verdi computer configure {} {}'.format(computer.get_transport_type(), computer.name))
echo.echo_info(' verdi computer configure {} {}'.format(computer.transport_type, computer.label))


@verdi_computer.command('duplicate')
Expand Down Expand Up @@ -316,20 +316,20 @@ def computer_duplicate(ctx, computer, non_interactive, **kwargs):
except (ComputerBuilder.ComputerValidationError, ValidationError) as e:
echo.echo_critical('{}: {}'.format(type(e).__name__, e))
else:
echo.echo_success('stored computer {}<{}>'.format(computer.name, computer.pk))
echo.echo_success('stored computer {}<{}>'.format(computer.label, computer.pk))

try:
computer.store()
except ValidationError as err:
echo.echo_critical('unable to store the computer: {}. Exiting...'.format(err))
else:
echo.echo_success('Computer<{}> {} created'.format(computer.pk, computer.name))
echo.echo_success('Computer<{}> {} created'.format(computer.pk, computer.label))

is_configured = computer.is_user_configured(orm.User.objects.get_default())

if not is_configured:
echo.echo_info('Note: before the computer can be used, it has to be configured with the command:')
echo.echo_info(' verdi computer configure {} {}'.format(computer.get_transport_type(), computer.name))
echo.echo_info(' verdi computer configure {} {}'.format(computer.transport_type, computer.label))


@verdi_computer.command('enable')
Expand All @@ -344,15 +344,15 @@ def computer_enable(computer, user):
authinfo = computer.get_authinfo(user)
except NotExistent:
echo.echo_critical(
"User with email '{}' is not configured for computer '{}' yet.".format(user.email, computer.name)
"User with email '{}' is not configured for computer '{}' yet.".format(user.email, computer.label)
)

if not authinfo.enabled:
authinfo.enabled = True
echo.echo_info("Computer '{}' enabled for user {}.".format(computer.name, user.get_full_name()))
echo.echo_info("Computer '{}' enabled for user {}.".format(computer.label, user.get_full_name()))
else:
echo.echo_info(
"Computer '{}' was already enabled for user {} {}.".format(computer.name, user.first_name, user.last_name)
"Computer '{}' was already enabled for user {} {}.".format(computer.label, user.first_name, user.last_name)
)


Expand All @@ -370,15 +370,17 @@ def computer_disable(computer, user):
authinfo = computer.get_authinfo(user)
except NotExistent:
echo.echo_critical(
"User with email '{}' is not configured for computer '{}' yet.".format(user.email, computer.name)
"User with email '{}' is not configured for computer '{}' yet.".format(user.email, computer.label)
)

if authinfo.enabled:
authinfo.enabled = False
echo.echo_info("Computer '{}' disabled for user {}.".format(computer.name, user.get_full_name()))
echo.echo_info("Computer '{}' disabled for user {}.".format(computer.label, user.get_full_name()))
else:
echo.echo_info(
"Computer '{}' was already disabled for user {} {}.".format(computer.name, user.first_name, user.last_name)
"Computer '{}' was already disabled for user {} {}.".format(
computer.label, user.first_name, user.last_name
)
)


Expand All @@ -400,7 +402,7 @@ def computer_list(all_entries, raw):
if not computers:
echo.echo_info("No computers configured yet. Use 'verdi computer setup'")

sort = lambda computer: computer.name
sort = lambda computer: computer.label
highlight = lambda comp: comp.is_user_configured(user) and comp.is_user_enabled(user)
hide = lambda comp: not (comp.is_user_configured(user) and comp.is_user_enabled(user)) and not all_entries
echo.echo_formatted_list(computers, ['name'], sort=sort, highlight=highlight, hide=hide)
Expand All @@ -411,36 +413,57 @@ def computer_list(all_entries, raw):
@with_dbenv()
def computer_show(computer):
"""Show detailed information for a computer."""
echo.echo(computer.full_text_info)
table = []
table.append(['Label', computer.label])
table.append(['PK', computer.pk])
table.append(['UUID', computer.uuid])
table.append(['Description', computer.description])
table.append(['Hostname', computer.hostname])
table.append(['Transport type', computer.transport_type])
table.append(['Scheduler type', computer.scheduler_type])
table.append(['Work directory', computer.get_workdir()])
table.append(['Shebang', computer.get_shebang()])
table.append(['Mpirun command', ' '.join(computer.get_mpirun_command())])
table.append(['Prepend text', computer.get_prepend_text()])
table.append(['Append text', computer.get_append_text()])
echo.echo(tabulate.tabulate(table))


@verdi_computer.command('rename')
@arguments.COMPUTER()
@arguments.LABEL('NEW_NAME')
@deprecated_command("This command has been deprecated. Please use 'verdi computer relabel' instead.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely unrelated, but should we maybe have @deprecated_command automatically append the "This command has been deprecated" text to the string passed through, so it is not necessary to include that part each time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would certainly be an option, although low priority I would say. Usually you copy this line from some other place anyway so it is already there.

@click.pass_context
@with_dbenv()
def computer_rename(computer, new_name):
def computer_rename(ctx, computer, new_name):
"""Rename a computer."""
ctx.invoke(computer_relabel, computer=computer, label=new_name)


@verdi_computer.command('relabel')
@arguments.COMPUTER()
@arguments.LABEL('LABEL')
@with_dbenv()
def computer_relabel(computer, label):
"""Relabel a computer."""
from aiida.common.exceptions import UniquenessError

old_name = computer.get_name()
old_label = computer.label

if old_name == new_name:
echo.echo_critical('The old and new names are the same.')
if old_label == label:
echo.echo_critical('The old and new labels are the same.')

try:
computer.set_name(new_name)
computer.label = label
computer.store()
except ValidationError as error:
echo.echo_critical('Invalid input! {}'.format(error))
except UniquenessError as error:
echo.echo_critical(
'Uniqueness error encountered! Probably a '
"computer with name '{}' already exists"
''.format(new_name)
"Uniqueness error encountered! Probably a computer with label '{}' already exists: {}".format(label, error)
)
echo.echo_critical('(Message was: {})'.format(error))

echo.echo_success("Computer '{}' renamed to '{}'".format(old_name, new_name))
echo.echo_success("Computer '{}' relabeled to '{}'".format(old_label, label))


@verdi_computer.command('test')
Expand Down Expand Up @@ -472,15 +495,15 @@ def computer_test(user, print_traceback, computer):
if user is None:
user = orm.User.objects.get_default()

echo.echo_info('Testing computer<{}> for user<{}>...'.format(computer.name, user.email))
echo.echo_info('Testing computer<{}> for user<{}>...'.format(computer.label, user.email))

try:
authinfo = computer.get_authinfo(user)
except NotExistent:
echo.echo_critical('Computer<{}> is not yet configured for user<{}>'.format(computer.name, user.email))
echo.echo_critical('Computer<{}> is not yet configured for user<{}>'.format(computer.label, user.email))

if not authinfo.enabled:
echo.echo_warning('Computer<{}> is disabled for user<{}>'.format(computer.name, user.email))
echo.echo_warning('Computer<{}> is disabled for user<{}>'.format(computer.label, user.email))
click.confirm('Do you really want to test it?', abort=True)

scheduler = authinfo.computer.get_scheduler()
Expand Down Expand Up @@ -568,14 +591,14 @@ def computer_delete(computer):
from aiida.common.exceptions import InvalidOperation
from aiida import orm

compname = computer.name
label = computer.label

try:
orm.Computer.objects.delete(computer.id)
except InvalidOperation as error:
echo.echo_critical(str(error))

echo.echo_success("Computer '{}' deleted.".format(compname))
echo.echo_success("Computer '{}' deleted.".format(label))


@verdi_computer.group('configure')
Expand All @@ -594,12 +617,11 @@ def computer_configure():
@arguments.COMPUTER()
def computer_config_show(computer, user, defaults, as_option_string):
"""Show the current configuration for a computer."""
import tabulate
from aiida.common.escaping import escape_for_bash

transport_cls = computer.get_transport_class()
option_list = [
param for param in transport_cli.create_configure_cmd(computer.get_transport_type()).params
param for param in transport_cli.create_configure_cmd(computer.transport_type).params
if isinstance(param, click.core.Option)
]
option_list = [option for option in option_list if option.name in transport_cls.get_valid_auth_params()]
Expand Down
2 changes: 1 addition & 1 deletion aiida/cmdline/commands/cmd_data/cmd_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,6 @@ def remote_cat(datum, path):
def remote_show(datum):
"""Show information for a RemoteData object."""
click.echo('- Remote computer name:')
click.echo(' {}'.format(datum.get_computer_name()))
click.echo(' {}'.format(datum.computer.label))
click.echo('- Remote folder full path:')
click.echo(' {}'.format(datum.get_remote_path()))
2 changes: 1 addition & 1 deletion aiida/cmdline/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def get_node_summary(node):
pass
else:
if computer is not None:
table.append(['computer', '[{}] {}'.format(node.computer.pk, node.computer.name)])
table.append(['computer', '[{}] {}'.format(node.computer.pk, node.computer.label)])

return tabulate(table, headers=table_headers)

Expand Down
12 changes: 6 additions & 6 deletions aiida/engine/daemon/execmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def upload_calculation(node, transport, calc_info, folder, inputs=None, dry_run=
if not remote_working_directory.strip():
raise exceptions.ConfigurationError(
"[submission of calculation {}] No remote_working_directory configured for computer '{}'".format(
node.pk, computer.name
node.pk, computer.label
)
)

Expand All @@ -94,7 +94,7 @@ def upload_calculation(node, transport, calc_info, folder, inputs=None, dry_run=
raise exceptions.ConfigurationError(
'[submission of calculation {}] '
'Unable to create the remote directory {} on '
"computer '{}': {}".format(node.pk, remote_working_directory, computer.name, exc)
"computer '{}': {}".format(node.pk, remote_working_directory, computer.label, exc)
)
# Store remotely with sharding (here is where we choose
# the folder structure of remote jobs; then I store this
Expand Down Expand Up @@ -211,7 +211,7 @@ def find_data_node(inputs, uuid):
for remote_computer_uuid, remote_abs_path, dest_rel_path in remote_copy_list:
handle.write(
'would have copied {} to {} in working directory on remote {}'.format(
remote_abs_path, dest_rel_path, computer.name
remote_abs_path, dest_rel_path, computer.label
)
)

Expand All @@ -220,7 +220,7 @@ def find_data_node(inputs, uuid):
for remote_computer_uuid, remote_abs_path, dest_rel_path in remote_symlink_list:
handle.write(
'would have created symlinks from {} to {} in working directory on remote {}'.format(
remote_abs_path, dest_rel_path, computer.name
remote_abs_path, dest_rel_path, computer.label
)
)

Expand All @@ -230,7 +230,7 @@ def find_data_node(inputs, uuid):
if remote_computer_uuid == computer.uuid:
logger.debug(
'[submission of calculation {}] copying {} remotely, directly on the machine {}'.format(
node.pk, dest_rel_path, computer.name
node.pk, dest_rel_path, computer.label
)
)
try:
Expand All @@ -251,7 +251,7 @@ def find_data_node(inputs, uuid):
if remote_computer_uuid == computer.uuid:
logger.debug(
'[submission of calculation {}] copying {} remotely, directly on the machine {}'.format(
node.pk, dest_rel_path, computer.name
node.pk, dest_rel_path, computer.label
)
)
try:
Expand Down
2 changes: 1 addition & 1 deletion aiida/engine/processes/calcjobs/calcjob.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ def presubmit(self, folder):
for code in codes:
if not code.can_run_on(computer):
raise InputValidationError('The selected code {} for calculation {} cannot run on computer {}'.format(
code.pk, self.node.pk, computer.name))
code.pk, self.node.pk, computer.label))

if code.is_local() and code.get_local_executable() in folder.get_content_list():
raise PluginInternalError('The plugin created a file {} that is also the executable name!'.format(
Expand Down
6 changes: 3 additions & 3 deletions aiida/orm/authinfos.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ def __init__(self, computer, user, backend=None):

def __str__(self):
if self.enabled:
return 'AuthInfo for {} on {}'.format(self.user.email, self.computer.name)
return 'AuthInfo for {} on {}'.format(self.user.email, self.computer.label)

return 'AuthInfo for {} on {} [DISABLED]'.format(self.user.email, self.computer.name)
return 'AuthInfo for {} on {} [DISABLED]'.format(self.user.email, self.computer.label)

@property
def enabled(self):
Expand Down Expand Up @@ -138,7 +138,7 @@ def get_transport(self):
:rtype: :class:`aiida.transports.Transport`
"""
computer = self.computer
transport_type = computer.get_transport_type()
transport_type = computer.transport_type

try:
transport_class = TransportFactory(transport_type)
Expand Down
Loading