Source code for finesse.script.shell

"""Kat shell tools."""

import cmd
from collections import ChainMap

from . import parse
from .spec import KatSpec
from ..exceptions import FinesseException
from .. import PROGRAM, __version__, Model


[docs]class KatShell(cmd.Cmd): """Kat shell.""" intro = f"Welcome to the {PROGRAM} {__version__} shell. Type help or ? to list commands.\n" prompt = "(kat) " doc_leader = "For further help on a topic, type 'help <topic>'.\n" doc_header = "Available elements:" misc_header = "Available commands ('!<command>'):" model = None solution = None
[docs] def __init__(self, *args, **kwargs): spec = KatSpec() # Set kat script elements as shell commands. for element, adapter in spec.elements.items(): setattr(self.__class__, f"do_{element}", self._wrap_kat_element(element)) setattr( self.__class__, f"help_{element}", self._wrap_kat_directive_help(adapter), ) # Set kat script command as magic methods. for command, adapter in ChainMap(spec.commands, spec.analyses).items(): setattr( self.__class__, f"_magic_{command}", self._wrap_kat_command(command) ) setattr( self.__class__, f"help_{command}", self._wrap_kat_directive_help(adapter), ) # Set help for magic methods. for attr in dir(self): if attr.startswith("_magic_"): setattr(self.__class__, f"help_{attr[7:]}", self._wrap_magic_help(attr)) super().__init__(*args, **kwargs)
@classmethod def _wrap_kat_element(cls, element): def wrapper(*args): # Get rid of self, and add the element instead. shell = args[0] args = [element] + list(args[1:]) original_line = " ".join(args) try: parse(original_line, model=shell.model) except FinesseException as e: print(e, file=shell.stdout) return wrapper @classmethod def _wrap_kat_command(cls, command): def wrapper(*args): # Get rid of self, and add the command instead. shell = args[0] args = [command] + list(args[1:]) original_line = " ".join(args) try: parse(original_line, model=shell.model) except FinesseException as e: print(e, file=shell.stdout) return wrapper @classmethod def _wrap_kat_directive_help(cls, adapter): def wrapper(*args): shell = args[0] print( adapter.call_signature_type.__doc__, file=shell.stdout, ) return wrapper @classmethod def _wrap_magic_help(cls, method): def wrapper(*args): shell = args[0] print( getattr(cls, method).__doc__, file=shell.stdout, ) return wrapper def _reset(self): self.model = Model()
[docs] def preloop(self): self._reset()
[docs] def close(self): self.model = None self.solution = None
[docs] def do_shell(self, arg): """Handler for commands starting with "!".""" magic_attr = f"_magic_{arg}" if hasattr(self, magic_attr): try: getattr(self, magic_attr)(arg) except FinesseException as e: print(e, file=self.stdout) else: try: parse(arg, model=self.model) except FinesseException as e: print(e, file=self.stdout)
def _magic_model_info(self, arg): """Show information about the current model (if no argument is specified) or a particular model element (if its name is specified as an argument).""" item = self.model.get(arg) if arg else self.model print(f"{item.info()}", file=self.stdout) def _magic_model_get(self, arg): """Get a model element attribute.""" print(self.model.get(arg), file=self.stdout) def _magic_model_set(self, arg): """Set an attribute of the model or a model element.""" self.model.set(*arg.split()) def _magic_model_run(self, arg): """Run the analysis.""" try: self.solution = self.model.run() except FinesseException as e: print(e, file=self.stdout) def _magic_model_plot(self, arg): """Plot the solution.""" self.solution.plot() def _magic_kat_load(self, arg): """Parse the specified kat file into the current model.""" self.model.parse_file(arg) def _magic_kat_save(self, arg): """Save the current model to file.""" self.model.unparse_file(arg) def _magic_model_reset(self, arg): """Reset the model.""" self._reset()