Source code for aiida.cmdline.baseclass

# -*- coding: utf-8 -*-

__copyright__ = u"Copyright (c), 2015, ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (Theory and Simulation of Materials (THEOS) and National Centre for Computational Design and Discovery of Novel Materials (NCCR MARVEL)), Switzerland and ROBERT BOSCH LLC, USA. All rights reserved."
__license__ = "MIT license, see LICENSE.txt file"
__version__ = "0.4.1"
__contributors__ = "Andrea Cepellotti, Giovanni Pizzi"

[docs]class VerdiCommand(object): """ This command has no documentation yet. """ class __metaclass__(type): """ Some python black magic to set correctly the logger also in subclasses. """ def __new__(cls, name, bases, attrs): newcls = type.__new__(cls, name, bases, attrs) # If the '_abstract' attribute is not explicitly defined in the # given class, set it to False. if '_abstract' not in attrs: newcls._abstract = False return newcls # This is an abstract class _abstract = True # To be defined if you want that the name is not generated by the class # name, but from a given string _custom_command_name = None
[docs] def get_full_command_name(self, with_exec_name=True): """ Return the current command name. Also tries to get the subcommand name. :param with_exec_name: if True, return the full string, including the executable name ('verdi'). If False, omit it. """ from aiida.cmdline import execname subcommand_str = "" if with_exec_name: exec_name_part = "{} ".format(execname) else: exec_name_part = "" return "{}{}".format(exec_name_part, self.get_command_name())
@classmethod
[docs] def get_command_name(cls): """ Return the name of the verdi command associated to this class. By default, the lower-case version of the class name. """ if cls._custom_command_name is None: return cls.__name__.lower() else: return cls._custom_command_name
[docs] def run(self,*args): """ Method executed when the command is called from the command line. """ import sys print >> sys.stderr, "This command has not been implemented yet"
[docs] def complete(self, subargs_idx, subargs): """ Method called when the user asks for the bash completion. Print a list of valid keywords. Returning without printing will use standard bash completion. :param subargs_idx: the index of the subargs where the TAB key was pressed\ (0 is the first element of subargs) :param subargs: a list of subarguments to this command """ return
class VerdiCommandRouter(VerdiCommand): _abstract = True # Empty valid subcommands to start with; # These should be a dictionary with 'key' the name to type on the # command line, and value a VerdiCommand class to call when that subcommand # is invoked. routed_subcommands = {} def no_subcommand(self,*args): import sys if self.routed_subcommands: print >> sys.stderr, ("You have to pass a valid subcommand to " "{}.\nValid subcommands are:".format( self.get_full_command_name())) print >> sys.stderr, "\n".join(" {}".format(sc) for sc in self.routed_subcommands) else: print >> sys.stderr, ("There are no valid subcommand to " "{}.".format(self.get_full_command_name())) sys.exit(1) def invalid_subcommand(self,*args): import sys if self.routed_subcommands: print >> sys.stderr, ("You passed an invalid subcommand to '{}'.\n" "Valid subcommands are:".format( self.get_full_command_name())) print >> sys.stderr, "\n".join(" {}".format(sc) for sc in self.routed_subcommands) else: print >> sys.stderr, ("There are no valid subcommand to " "{}.".format(self.get_full_command_name())) sys.exit(1) def run(self,*args): try: the_class = self.routed_subcommands[args[0]] the_class._custom_command_name = "{} {}".format( self.get_full_command_name(with_exec_name=False), args[0]) function_to_call = the_class().run except IndexError: function_to_call = self.no_subcommand except KeyError: function_to_call = self.invalid_subcommand function_to_call(*args[1:]) def complete(self,subargs_idx, subargs): if subargs_idx == 0: print "\n".join(self.routed_subcommands.keys()) elif subargs_idx >= 1: try: first_subarg = subargs[0] except IndexError: first_subarg = '' try: complete_function = self.routed_subcommands[first_subarg]().complete except KeyError: print "" return complete_function(subargs_idx - 1, subargs[1:])
[docs]class VerdiCommandWithSubcommands(VerdiCommand): """ Used for commands with subcommands. Just define, in the __init__, the self.valid_subcommands dictionary, in the format:: self.valid_subcommands = { 'uploadfamily': (self.uploadfamily, self.complete_auto), 'listfamilies': (self.listfamilies, self.complete_none), } where the key is the subcommand name to give on the command line, and the value is a tuple of length 2, the first is the function to call on execution, the second is the function to call on complete. This class already defined the complete_auto and complete_none commands, that respectively call the default bash completion for filenames/folders, or do not give any completion suggestion. Other functions can of course be defined. .. todo:: Improve the docstrings for commands with subcommands. """ _abstract = True valid_subcommands = {} def run(self,*args): try: function_to_call = self.valid_subcommands[args[0]][0] except IndexError: function_to_call = self.no_subcommand except KeyError: function_to_call = self.invalid_subcommand function_to_call(*args[1:]) def complete(self,subargs_idx, subargs): if subargs_idx == 0: print "\n".join(self.valid_subcommands.keys()) elif subargs_idx >= 1: try: first_subarg = subargs[0] except IndexError: first_subarg = '' try: complete_function = self.valid_subcommands[first_subarg][1] except KeyError: print "" return complete_data = complete_function(subargs_idx - 1, subargs[1:]) if complete_data is not None: print complete_data def complete_none(self, subargs_idx, subargs): return "" def complete_auto(self, subargs_idx, subargs): return None def no_subcommand(self,*args): import sys if self.valid_subcommands: print >> sys.stderr, ("You have to pass a valid subcommand to " "'{}'.\nValid subcommands are:".format( self.get_full_command_name())) print >> sys.stderr, "\n".join(" {}".format(sc) for sc in self.valid_subcommands) else: print >> sys.stderr, ("There are no valid subcommands to " "'{}'.".format(self.get_full_command_name())) sys.exit(1) def invalid_subcommand(self,*args): import sys if self.valid_subcommands: print >> sys.stderr, ("You passed an invalid subcommand to '{}'.\n" "Valid subcommands are:".format( self.get_full_command_name())) print >> sys.stderr, "\n".join(" {}".format(sc) for sc in self.valid_subcommands) else: print >> sys.stderr, ("There are no valid subcommands to " "'{}'.".format(self.get_full_command_name())) sys.exit(1)
[docs] def get_full_command_name(self, *args, **kwargs): """ Return the current command name. Also tries to get the subcommand name. Also tries to see if the caller function was one specific submethod. :param with_exec_name: if True, return the full string, including the executable name ('verdi'). If False, omit it. """ import inspect from aiida.cmdline import execname subcommand_str = "" try: # [0]: this function; # [1]: function that directly called this function # So I go in order from the function that called to the above # function, etc. until I find it, if I can found = False for caller_function in inspect.stack()[1:]: if found == True: break for k, v in self.valid_subcommands.iteritems(): if v[0].__name__ == caller_function[3]: subcommand_str = " {}".format(k) found = True break except (KeyError, AttributeError, IndexError): # Some of this info could not be retrived, do not set # the subcommand name pass return "{}{}".format( super(VerdiCommandWithSubcommands, self).get_full_command_name( *args, **kwargs), subcommand_str)