Convenience functions for working with the Cmd module, the BaseCommand class for constructing command line programmes, and other command line related stuff.
Project description
Convenience functions for working with the Cmd module, the BaseCommand class for constructing command line programmes, and other command line related stuff.
Latest release 20220315: _BaseSubCommand.init: hook in the class USAGE_KEYWORDS for methods.
Class BaseCommand
A base class for handling nestable command lines.
This class provides the basic parse and dispatch mechanisms
for command lines.
To implement a command line
one instantiates a subclass of BaseCommand
:
class MyCommand(BaseCommand):
GETOPT_SPEC = 'ab:c'
USAGE_FORMAT = r"""Usage: {cmd} [-a] [-b bvalue] [-c] [--] arguments...
-a Do it all.
-b But using bvalue.
-c The 'c' option!
"""
...
and provides either a main
method if the command has no subcommands
or a suite of cmd_
subcommand methods, one per subcommand.
Running a command is done by:
MyCommand(argv).run()
or via the convenience method:
MyCommand.run_argv(argv)
Modules which implement a command line mode generally look like this:
... imports etc ...
... other code ...
class MyCommand(BaseCommand):
... other code ...
if __name__ == '__main__':
sys.exit(MyCommand.run_argv(sys.argv))
Instances have a self.options
attribute on which optional
modes are set,
avoiding conflict with the attributes of self
.
Subclasses with no subcommands
generally just implement a main(argv)
method.
Subclasses with subcommands
should implement a cmd_
subcommand(argv)
instance method
for each subcommand.
If a subcommand is itself implemented using BaseCommand
then it can be a simple attribute:
cmd_subthing = SubThingCommand
Returning to methods, if there is a paragraph in the method docstring
commencing with Usage:
then that paragraph is incorporated automatically
into the main usage message.
Example:
def cmd_ls(self, argv):
""" Usage: {cmd} [paths...]
Emit a listing for the named paths.
Further docstring non-usage information here.
"""
... do the "ls" subcommand ...
The subclass is customised by overriding the following methods:
apply_defaults()
: prepare the initial state ofself.options
before any command line options are applied.apply_opt(opt,val)
: apply an individual getopt global command line option toself.options
.apply_opts(opts)
: apply theopts
toself.options
.opts
is an(option,value)
sequence as returned bygetopot.getopt
. The default implementation iterates over these and callsapply_opt
.cmd_
subcmd(argv)
: if the command line options are followed by an argument whose value is subcmd, then the methodcmd_
subcmd(subcmd_argv)
will be called wheresubcmd_argv
contains the command line arguments following subcmd.main(argv)
: if there are no command line arguments after the options or the first argument does not have a correspondingcmd_
subcmd method then methodmain(argv)
will be called whereargv
contains the command line arguments.run_context()
: a context manager to provide setup or teardown actions to occur before and after the command implementation respectively, such as to open and close a database.
Editorial: why not arparse?
Primarily because when incorrectly invoked
an argparse command line prints the help/usage messgae
and aborts the whole programme with SystemExit
.
Method BaseCommand.__init__(self, argv=None, *, cmd=None, **kw_options)
:
Initialise the command line.
Raises GetoptError
for unrecognised options.
Parameters:
argv
: optional command line arguments including the main command name ifcmd
is not specified. The default issys.argv
. The contents ofargv
are copied, permitting desctructive parsing ofargv
.options
: a optional object for command state and context. If not specified a newSimpleNamespace
is allocated for use asoptions
, and prefilled with.cmd
set tocmd
and other values as set by.apply_defaults()
if such a method is provided.cmd
: optional command name for context; if this is not specified it is taken fromargv.pop(0)
. Other keyword arguments are applied toself.options
as attributes.
The command line arguments are parsed according to
the optional GETOPT_SPEC
class attribute (default ''
).
If getopt_spec
is not empty
then apply_opts(opts)
is called
to apply the supplied options to the state
where opts
is the return from getopt.getopt(argv,getopt_spec)
.
After the option parse,
if the first command line argument foo
has a corresponding method cmd_
foo
then that argument is removed from the start of argv
and self.cmd_
foo(argv,options,cmd=
foo)
is called
and its value returned.
Otherwise self.main(argv,options)
is called
and its value returned.
If the command implementation requires some setup or teardown
then this may be provided by the run_context
context manager method,
called with cmd=
subcmd for subcommands
and with cmd=None
for main
.
BaseCommand.OPTIONS_CLASS
Method BaseCommand.__init_subclass__()
:
Update subclasses of BaseCommand
.
Appends the usage message to the class docstring.
Method BaseCommand.apply_defaults(self)
:
Stub apply_defaults
method.
Subclasses can override this to set up the initial state of self.options
.
Method BaseCommand.apply_opt(self, *a, **kw)
:
Handle an individual global command line option.
This default implementation raises a RuntimeError
.
It only fires if getopt
actually gathered arguments
and would imply that a GETOPT_SPEC
was supplied
without an apply_opt
or apply_opts
method to implement the options.
Method BaseCommand.apply_opts(self, opts)
:
Apply command line options.
Method BaseCommand.apply_preargv(self, argv)
:
Do any preparsing of argv
before the subcommand/main-args.
Return the remaining arguments.
This default implementation returns argv
unchanged.
Method BaseCommand.cmd_help(argv)
:
Usage: {cmd} [-l] [subcommand-names...]
Print the full help for the named subcommands,
or for all subcommands if no names are specified.
-l Long help even if no subcommand-names provided.
Method BaseCommand.getopt_error_handler(cmd, options, e, usage, subcmd=None)
:
The getopt_error_handler
method
is used to control the handling of GetoptError
s raised
during the command line parse
or during the main
or cmd_
subcmd` calls.
This default handler issues a warning containing the exception text,
prints the usage message to standard error,
and returns True
to indicate that the error has been handled.
The handler is called with these parameters:
cmd
: the command nameoptions
: theoptions
objecte
: theGetoptError
exceptionusage
: the command usage orNone
if this was not providedsubcmd
: optional subcommand name; if notNone
, is the name of the subcommand which caused the error
It returns a true value if the exception is considered handled,
in which case the main run
method returns 2.
It returns a false value if the exception is considered unhandled,
in which case the main run
method reraises the GetoptError
.
To let the exceptions out unhandled
this can be overridden with a method which just returns False
.
Otherwise,
the handler may perform any suitable action
and return True
to contain the exception
or False
to cause the exception to be reraised.
Method BaseCommand.run(self, **kw_options)
:
Run a command.
Returns the exit status of the command.
May raise GetoptError
from subcommands.
Any keyword arguments are used to override self.options
attributes
for the duration of the run,
for example to presupply a shared RunState
from an outer context.
If the first command line argument foo
has a corresponding method cmd_
foo
then that argument is removed from the start of argv
and self.cmd_
foo(cmd=
foo)
is called
and its value returned.
Otherwise self.main(argv)
is called
and its value returned.
If the command implementation requires some setup or teardown
then this may be provided by the run_context
context manager method,
called with cmd=
subcmd for subcommands
and with cmd=None
for main
.
Method BaseCommand.run_argv(argv, **kw)
:
Create an instance for argv
and call its .run()
method.
Method BaseCommand.run_context()
:
Stub context manager which surrounds main
or cmd_
subcmd.
Method BaseCommand.subcommand_usage_text(subcmd, usage_format_mapping=None, short=False)
:
Return the usage text for a subcommand.
Parameters:
subcmd
: the subcommand nameshort
: just include the first line of the usage message, intented for when there are many subcommands
Method BaseCommand.subcommands()
:
Return a mapping of subcommand names to subcommand specifications
for class attributes which commence with cls.SUBCOMMAND_METHOD_PREFIX
by default 'cmd_'
.
Method BaseCommand.usage_text(*, cmd=None, format_mapping=None, subcmd=None, short=False)
:
Compute the "Usage:" message for this class
from the top level USAGE_FORMAT
and the 'Usage:'
-containing docstrings
from its cmd_*
methods.
Parameters:
cmd
: optional command name, default derived from the class nameformat_mapping
: an optional format mapping for filling in format strings in the usage textsubcmd
: constrain the usage to a particular subcommand namedsubcmd
; this is used to produce a shorter usage for subcommand usage failures
Function docmd(dofunc)
Decorator for cmd.Cmd
subclass methods
to supply some basic quality of service.
This decorator:
- wraps the function call in a
cs.pfx.Pfx
for context - intercepts
getopt.GetoptError
s, issues awarning
and runsself.do_help
with the method name, then returnsNone
- intercepts other
Exception
s, issues anexception
log message and returnsNone
The intended use is to decorate cmd.Cmd
do_
* methods:
from cmd import Cmd
from cs.cmdutils import docmd
...
class MyCmd(Cmd):
@docmd
def do_something(...):
... do something ...
Release Log
Release 20220315: _BaseSubCommand.init: hook in the class USAGE_KEYWORDS for methods.
Release 20220311: BaseCommand: big refactor of subcommand internals and make the "cmd_foo=FooCommand" implementation work properly.
Release 20211208: BaseCommand: better handle an unknown subcommand.
Release 20210927:
- Usage: show only the per subcommand usage for in-subcommand GetoptError.
- Usage: show terse usage when the subcommand cannot be recognised.
- Usage: support bare -h, -help, --help.
Release 20210913: New BaseCommand.apply_preargv method to gather special arguments before subcommands.
Release 20210906:
- BaseCommand.cmd_help: bugfix obsolete parameter list.
- BaseCommand.SUBCOMMAND_ARGV_DEFAULT: support a single str value, turn into list.
Release 20210809: Bugfix BaseCommand.cmd_help for modern API.
Release 20210731:
- BaseCommand.run: apply optional keyword arguments to self.options during the run.
- Look for self.SUBCOMMAND_ARGV_DEFAULT if no subcommand is supplied.
- Bugfix case for "main" method and no "cmd_*" methods.
- Bugfix BaseCommand.cmd_help.
Release 20210420:
- BaseCommand.getopt_error_handler: replace error print() with warning().
- Docstring improvements.
Release 20210407.1: BaseCommand: bugfix for init_subclass docstring update.
Release 20210407:
- BaseCommand.init_subclass: behave sanely if the subclass has no initial doc.
- BaseCommand: new .run_argv convenience method, obviates the "def main" boilerplate.
Release 20210404: BaseCommand subclasses: automatically add the main usage message to the subclass docstring.
Release 20210306:
- BREAKING CHANGE: rework BaseCommand as a more normal class instantiated with argv and with most methods being instance methods, getting the former
options
parameter from self.options. - BaseCommand: provide default
apply_opt
andapply_opts
methods; subclasses will generally just override the former.
Release 20210123: BaseCommand: propagate the format mapping (cmd, USAGE_KEYWORDS) to the subusage generation.
Release 20201102:
- BaseCommand.cmd_help: supply usage only for "all commands", full docstring for specified commands.
- BaseCommand: honour presupplied options.log_level.
- BaseCommand.usage_text: handle missing USAGE_FORMAT better.
- BaseCommand.run: provide options.upd.
- BaseCommand subclasses may now override BaseCommand.OPTIONS_CLASS (default SimpleNamespace) in order to provide convenience methods on the options.
- BaseCommand.run: separate variable for subcmd with dash translated to underscore to match method names.
- Minor fixes.
Release 20200615: BaseCommand.usage_text: do not mention the "help" command if it is the only subcommand (it won't be available if there are no other subcommands).
Release 20200521.1: Fix DISTINFO.install_requires.
Release 20200521:
- BaseCommand.run: support using BaseCommand subclasses as cmd_* names to make it easy to nest BaseCommands.
- BaseCommand: new hack_postopts_argv method called after parsing the main command line options, for inferring subcommands or the like.
- BaseCommand: extract "Usage:" paragraphs from subcommand method docstrings to build the main usage message.
- BaseCommand: new cmd_help default command.
- Assorted bugfixes and small improvements.
Release 20200318:
- BaseCommand.run: make argv optional, get additional usage keywords from self.USAGE_KEYWORDS.
- @BaseCommand.add_usage_to_docstring: honour cls.USAGE_KEYWORDS.
- BaseCommand: do not require GETOPT_SPEC for commands with no defined options.
- BaseCommand.run: call cs.logutils.setup_logging.
Release 20200229:
Improve subcommand selection logic, replace StackableValues with stackattrs, drop cmd
from arguments passed to main/cmd_* methods (present in options
).
Release 20200210:
- New BaseCommand.add_usage_to_docstring class method to be called after class setup, to append the usage message to the class docstring.
- BaseCommand.run: remove spurious Pfx(cmd), as logutils does this for us already.
Release 20190729: BaseCommand: support for a USAGE_FORMAT usage message format string and a getopt_error_handler method.
Release 20190619.1: Another niggling docstring formatting fix.
Release 20190619: Minor documentation updates.
Release 20190617.2: Lint.
Release 20190617.1: Initial release with @docmd decorator and alpha quality BaseCommand command line assistance class.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file cs.cmdutils-20220315.tar.gz
.
File metadata
- Download URL: cs.cmdutils-20220315.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 028f462059c3517f520e8fe6b5104b4a2564852164ad1530ee0e5e802c0edfa9 |
|
MD5 | 5142e2e590c3edf829ead99097f1cd85 |
|
BLAKE2b-256 | 40a1001a1e7f7f9ba65eb364715a6b9b26f733a2c60de1625779297f2546f96e |