This module provides the appshell.Shell class, which is a simple line-oriented
command interpreter similar to Python's built-in cmd.Cmd class, but providing
ergonomic alternatives that the author prefers.
In particular, the user can abbreviate commands (as long as the abbreviation isn't ambiguous), and the shell supports simple user-created command aliases.
An instance of Shell (or a subclass) is a line-oriented command interpreter.
You add commands for it to recognize with Shell.add_command(), optionally
add the standard command suite (help, quit, and alias), and start it
running. It reads lines (by default using input()), each line
representing one command. The first word on the line is the name of the
command, and the remaining words (if any) are the command's command-specific
arguments. It runs until its input is exhausted or Shell.Quit is
raised (this is what the quit command does).
Lines beginning with the comment character (# by default) are ignored.
Words are separated by ASCII whitespace (spaces and tabs), unless quoted.
Both single-quote ' and double-quote " can be used to quote words with
spaces (or the other kind of quote) in them. Any character, including whitespace
or a quote, can be escaped with a backslash \. The escaping may be enhanced
in the future to enable common string escapes (like \n for newline).
The user can define an alias for a command, including initial arguments. When an alias is given, it is expanded to the original command and initial arguments, with following arguments appended. For example
alias bar foo baz
means that if the user enters bar biff, it should be interpreted as though
foo baz biff was entered.
Instance variables:
Shell.stdin- File object from which commands are read with itsreadline()method; ifNone(the default), lines are read using the builtininput()function.Shell.stdout- File object to which output is written;sys.stdoutby default.Shell.help_width- The width, in characters, for command names and usages in thehelpso that the help summaries will all be aligned. This starts at 8 characters and is extended as commands are added.Shell.alias_width- The width, in characters, for the wordaliasand the alias name, so that expansions will be aligned when listing aliases. This starts at 1 character and is extended as aliases are added.Shell.prompt- The prompt to display before the next command is read, default ">".Shell.prompt2- The prompt to display to continue a line if the previous line ended mid-quote, default ">>".Shell.comment_char- The character or string that, if a line begins with it, the line is ignored, default "#".Shell.help_separator- The string to separate a command name and usage from its summary inhelp, default "-".
Instance methods:
Shell.add_command(*, action, name=None, usage='', summary='', help='')
Add a new command to the be recognized by the shell. Parameters:action- A callable to call to execute the command, which takes one argument: a list of the argument vector for the command, including the command's name as entered.name- The name for the command; if not specified, the name is the action's__name__minus a leadingdo_, if any.usage- An optional short string for the help to indicate options or arguments the command might take.summary- A short summary of the command to display in the help after thehelp_separator; if not specified, it is the summary line from the action's docstring, if any.help- If specified, the "long help" to display if help is requested for this command specifically; if not specified, it is the rest of the action's docstring after the summary, if any.
Shell.add(*, name=None, usage='', summary='', help='')
Convenience decorator to calladd_command()with the decorated function as the action. This function returns a function of one argument (taking the decorated function) that itself returns the decorated function with no additional wrapping, soadd()decorators can be stacked to give alternate names to the same action function, if desired.Shell.add_standard_commands()
Add the suite of standard commands and their alternate names; specificallyalias,help,quit,?(the same ashelp), andx(the same asquit).Shell.run(batch=False)
Run the command interpreter, reading lines withinput()ifShell.stdinisNoneotherwise withShell.stdin.readline()until the end of the input is reached, orShell.Quitis raised. IfbatchisTrue, don't print the prompt before reading each command.Shell.readrc(filename)
Attempt to read commands from the file namedfilenameby opening it and temporarily settingShell.stdinto the file and executingShell.run(batch=True).Shell.do_quit(argv)
RaiseShell.Quitto quit the application.Shell.do_help(argv)
- With no arguments, prints the summary help for all commands.
- With exactly one argument, prints the summary and long help (if any) for that command.
- With more than one argument, prints the summary help for the indicated commands.
Shell.do_alias(argv)
- With no arguments, show all aliases.
- With one argument, show the expansion for just that alias.
- With more than one argument, define an alias named by the first argument that expands to the remaining arguments.
Shell.before_prompt(argv)
Called just before printing the prompt;argvis the argument vector from the previous command. The default implementation does nothing.Shell.after_command(argv)
Called after invoking the action for a command;argvis the argument vector from the command just invoked. The default implementation does nothing.Shell.empty_command(argv)
If not inbatchmode, called if the user enters a blank line. The default implementation does nothing.Shell.write(b)
Convenience method writesbtoShell.stdout.Shell.writef(b)
Convenience method writesbtoShell.stdoutthen callsShell.flush().Shell.flush()
Convenience method callsShell.stdout.flush().
Exceptions:
Shell.Quit
Raise this in an action to terminateShell.run().Shell.ImproperUsage
Convenience: raise this in an action to print the help message for the invoked command.
from appshell.appshell import Shell
shell = Shell()
@shell.add(name="alt", usage="[args...]")
@shell.add(usage="[args...]")
def do_foo(argv):
"""
Print my argument vector
Long help for this command.
"""
print(argv)
shell.add_standard_commands()
if __name__ == "__main__":
shell.run()
The above example adds two commands for the same action function: foo and
alt, with help usage strings of "[args...]", help summaries of
"Print my argument vector", and long help. It then adds the standard command
suite and then runs the command interpreter. A sample run might look like:
$ python3 example.py
> h
foo [args...] - Print my argument vector
alt [args...] - Print my argument vector
alias [name [command...]] - make <name> do <command>, or show aliases
help [command...] - help on all or specific commands
quit - exit the application
? [command...] - help on all or specific commands
x - exit the application
> help f
foo [args...] - Print my argument vector
===
Long help for this command.
> f one two "three four"
['f', 'one', 'two', 'three four']
> alias bar foo bar
> bar baz
['foo', 'bar', 'baz']
> q
$