Command-line programs with sub-commands (pwkit.cli.multitool)

pwkit.cli.multitool - Framework for command-line tools with sub-commands

This module provides a framework for quickly creating command-line programs that have multiple independent sub-commands (similar to the way Git’s interface works).

Classes:

Command

A command supported by the tool.

DelegatingCommand

A command that delegates to named sub-commands.

HelpCommand

A command that prints the help for other commands.

Multitool

The tool itself.

UsageError

Raised if illegal command-line arguments are used.

Functions:

invoke_tool

Run as a tool and exit.

Standard usage:

class MyCommand (multitool.Command):
  name = 'info'
  summary = 'Do something useful.'

  def invoke (self, args, **kwargs):
    print ('hello')

class MyTool (multitool.MultiTool):
  cli_name = 'mytool'
  summary = 'Do several useful things.'

HelpCommand = multitool.HelpCommand # optional

def commandline ():
  multitool.invoke_tool (globals ())
class pwkit.cli.multitool.Command[source]

A command in a multifunctional CLI tool.

For historical reasons, this class defaults to a homebrew argument parsing system. Use ArgparsingCommand for a better system based on the argparse module.

Attributes:

argspec

One-line string summarizing the command-line arguments that should be passed to this command.

help_if_no_args

If True, usage help will automatically be displayed if no command-line arguments are given.

more_help

Additional help text to be displayed below the summary (optional).

name

The command’s name, as should be specified at the CLI.

summary

A one-line summary of this command’s functionality.

Functions:

invoke(self, args, **kwargs)

Execute this command.

‘name’ must be set; other attributes are optional, although at least ‘summary’ and ‘argspec’ should be set. ‘invoke()’ must be implemented.

invoke(args, **kwargs)[source]

Invoke this command. ‘args’ is a list of the remaining command-line arguments. ‘kwargs’ contains at least ‘argv0’, which is the equivalent of, well, argv[0] for this command; ‘tool’, the originating Multitool instance; and ‘parent’, the parent DelegatingCommand instance. Other kwargs may be added in an application-specific manner. Basic processing of ‘–help’ will already have been done if invoked through invoke_with_usage().

invoke_with_usage(args, **kwargs)[source]

Invoke the command with standardized usage-help processing. Same calling convention as Command.invoke().

class pwkit.cli.multitool.DelegatingCommand(populate_from_self=True)[source]

A command that delegates to sub-commands.

Attributes:

cmd_desc

The noun used to desribe the sub-commands.

usage_tmpl

A formatting template for long tool usage. The default is almost surely acceptable.

Functions:

register

Register a new sub-command.

populate

Register many sub-commands automatically.

invoke(args, **kwargs)[source]

Invoke this command. ‘args’ is a list of the remaining command-line arguments. ‘kwargs’ contains at least ‘argv0’, which is the equivalent of, well, argv[0] for this command; ‘tool’, the originating Multitool instance; and ‘parent’, the parent DelegatingCommand instance. Other kwargs may be added in an application-specific manner. Basic processing of ‘–help’ will already have been done if invoked through invoke_with_usage().

invoke_command(cmd, args, **kwargs)[source]

This function mainly exists to be overridden by subclasses.

populate(values)[source]

Register multiple new commands by investigating the iterable values. For each item in values, instances of Command are registered, and subclasses of Command are instantiated (with no arguments passed to the constructor) and registered. Other kinds of values are ignored. Returns ‘self’.

register(cmd)[source]

Register a new command with the tool. ‘cmd’ is expected to be an instance of Command, although here only the cmd.name attribute is investigated. Multiple commands with the same name are not allowed to be registered. Returns ‘self’.

class pwkit.cli.multitool.HelpCommand[source]
invoke(args, parent=None, parent_kwargs=None, **kwargs)[source]

Invoke this command. ‘args’ is a list of the remaining command-line arguments. ‘kwargs’ contains at least ‘argv0’, which is the equivalent of, well, argv[0] for this command; ‘tool’, the originating Multitool instance; and ‘parent’, the parent DelegatingCommand instance. Other kwargs may be added in an application-specific manner. Basic processing of ‘–help’ will already have been done if invoked through invoke_with_usage().

class pwkit.cli.multitool.Multitool[source]

A command-line tool with multiple sub-commands.

Attributes:

cli_name - The usual name of this tool on the command line. more_help - Additional help text. summary - A one-line summary of this tool’s functionality.

Functions:

commandline - Execute a command as if invoked from the command-line. register - Register a new command. populate - Register many commands automatically.

commandline(argv)[source]

Run as if invoked from the command line. ‘argv’ is a Unix-style list of arguments, where the zeroth item is the program name (which is ignored here). Usage help is printed if deemed appropriate (e.g., no arguments are given). This function always terminates with an exception, with the exception being a SystemExit(0) in case of success.

Note that we don’t actually use argv[0] to set argv0 because it will generally be the full path to the script name, which is unattractive.

exception pwkit.cli.multitool.UsageError(fmt, *args)[source]

Raised if illegal command-line arguments are used in a Multitool program.

pwkit.cli.multitool.invoke_tool(namespace, tool_class=None)[source]

Invoke a tool and exit.

namespace is a namespace-type dict from which the tool is initialized. It should contain exactly one value that is a Multitool subclass, and this subclass will be instantiated and populated (see Multitool.populate()) using the other items in the namespace. Instances and subclasses of Command will therefore be registered with the Multitool. The tool is then invoked.

pwkit.cli.propagate_sigint() and pwkit.cli.unicode_stdio() are called at the start of this function. It should therefore be only called immediately upon startup of the Python interpreter.

This function always exits with an exception. The exception will be SystemExit (0) in case of success.

The intended invocation is invoke_tool (globals ()) in some module that defines a Multitool subclass and multiple Command subclasses.

If tool_class is not None, this is used as the tool class rather than searching namespace, potentially avoiding problems with modules containing multiple Multitool implementations.