Command interpreter

The command interpreter is used for program control in stand-alone mode, but generally not when called from / embedded in another package. After the program has been invoked with options/arguments that are parsed, program flow is controlled with a series of user-entered interactive commands.

These run-time commands are interpreted with an extenstion (cmd2nest) of the cmd2 package that adds support for nested sub-commands. The following will summaraize the essentials of program control and note differences from cmd2. The cmd2 documentation provides additional detail.

Syntax:

Commands are entered at the prompt in a unix-shell style:
  • command [option(s)] [positional argument(s)]

  • where options can be provided as -x [value] (x is a single letter), or --option[[=]value] in “two-dash” long form.

  • Various standard short-cuts are pre-defined, and tab completion is available for commands and arguments.

    Error

    The abbreviation given in the help is not always long enough to be unique (a bug inherited from cmd2.

Error

Tab completion fails after exiting a sub-command.

Shell:

The cmd2 shell-like interface is inherited, offering history, command editing and redirects. Redirects should work (<, |, >).

Hierachical structure:

Sub-commands are only available after entering the command. Higher-level commands are generally not available in sub-commands. The exceptions are general utility commands such as shell, shortcuts & set. Help, by default, is specific to the command level. The --descend (-d) documents one sub-command level deeper & --recursive --long (-rl) decends through all levels exhaustively. Note that load (“@”) & related commands and history, do not transcend different command levels.

Just-in-time calculation & pre-requisites:

A number of efficiencies are possible by pre-calculating and repeatedly using objects. Rather than pre-calculating at startup all objects that might be needed, the program attempts to calculate the minimal needed, just-in-time. For the most part, the pre-requisites are figured out and tasks are executed when needed using pre-assigned (or default) parameters. One exception is that any command with a “parameterize” pre-requisite will issue an error message if not already performed (mind-reading is not an option!).

The order that commands are entered is sometimes important, particularly when the embedded python interpreter is invoked with “py” (see below). Given the flexibility of the “py” command, there is no way to figure out the pre-requisites. Users should be especially attentive to AttributeErrors that might indicate an unmet pre-requisite dependence.

Error recovery:

Inherited from cmd2, exceptions are captured at the Command level, printing at least an error message, but without aborting the whole program. On interactive use, this conveniently often offers a second chance. If run as a script, users should search the output for “Error”, lest one has scrolled by. The default is a terse error message, but this can be changed to a full traceback using “set debug True” (still does not abort).

Selected commands - implementation-specific extensions & limitations.

@FILE or run_script FILE

Used to run commands from an external file. The limitation is that commands cannot descend/ascend through nested sub-commands. Thus, for example, commands within parameterize would have to be given separately. The same limitation applies to variants _relative_run_script (@@).

Command-line commands

Tokens following any of the program’s required positional parameters (e.g. INPUT.PDB) will be run as top-level commands. There is no support for transcending sub-commands or for command options:

Example: rsref.py /dev/null help shortcuts exit

Options can be incorporated by using the cmd2 run_script shortcut on the command line (Example1), where cmd.txt has one command per line that can include options and whitespace. Even better, use the --infile option (imported from argparser)

Example1: rsref.py /dev/null @cmd.txt exit
Example2: rsref.py /dev/null --infile=cmd.txt

done, exit and quit

These are near synonyms to mitigate a problem with cmd2’s error-handling in scripted runs with sub-commands. On an exception within a sub-command, the program terminates (just) the sub-command, and continues reading commands that had been intended for the terminated sub-command, but applying them mistakenly to continued exectuation in the higher level from where the sub-command was invoked. Should a quit (or exit), intended for a sub-command, be encountered at top-level, the program can terminate before any results are saved. To avoid this, the base cmd2 commands have been overridden:

  • exit is only available from the top level.

  • done is only available from sub-commands.

  • quit is unsafely available from both.

Thus, if done is used exclusively to finish a sub-command, if it is invoked accidentally at the top level, it will lead to an unrecognized command error, and remaining top-level commands (eg. saving results) will executed before the program is terminated with exit. The unsafe quit can be used interactively and repeatedly to bail out of a failed run if the sub-command level is unclear.

python interpreter

py (without statement) opens a python shell within which multiple statements can be executed, terminating the shell with Cntrl-D, exit() or quit(). These provide powerful ways of customizing the programs and extending functionality beyond the commands that are provided.

In our extension of cmd2, namespace my provides access to objects within the task-space of the program. Thus, for example, atomic B-factors could be printed or manipulated using my.atoms.b, and program options with my.option.resolution (for example).

The python shell is executed in its own namespace, so modules (such as sys or numpy) have to be imported explicitly.

Additional examples are given in sections “Python Interpreter for advanced functionality” in the documentation for specific programs.

Limitations, bugs & work-arounds

The single-line variant, py statement, executing a single python statement, was deprecated in package cmd2 v2.4. There may be legacy scripts that will need updating.

  • Annotations

    py print("\nAnnotation for stdout") was a common use. Consider the alternative: shell echo -e "\nAnnotation for stdout" which will avoid additional output from interpreter start and termination. The shell alternative is only possible if access to python attributes is not required.

  • Redirects (> , < and |) on the py command line

    are captured by the cmd2 parser, not any shell that might redirect io for the python interpreter. This means that shell heredoc file and variables are not supported within py.

  • Support for compound single-line statements (py stmt1; stmt2)

    with a ‘;’ separator disappeared from cmd2 prior to v2.4. A common usage was to import a module, then use a module attribute. Subsequently, code following ‘;’ was ignored silently, affecting some legacy scripts.

All of these issues are by-passed by invoking the full python shell instead of the single-line py command.

Other commands available in all applications

Use application help <command> for further details:

alias

Manage aliases

edit

Run a text editor and optionally open a file with it

exit

Safe program exit from top level, not subcommands.

help

List available commands or help for one or all commands

history

View, run, edit, save, or clear previously entered commands

macro

Manage macros

parrot

Echo commands (or not)

py

Invoke Python shell, ending exit(); single line “py command” no longer supported; see comments above and also shell

quit

Exit this application

run_pyscript

Run a Python script file inside the console

run_script

Run commands in script file that is encoded as either ASCII or UTF-8 text

set

Set a settable parameter or show current settings of parameters

shell

Execute a command as if at the OS prompt

shortcuts

List available shortcuts

test

test [<name>]: run test (developers only)