Mercurial > hg > CommandParser
changeset 12:e0a3148e67a8
bug fix and a short overhaul of documentation
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Mon, 28 Jan 2013 19:54:36 -0800 |
parents | 03db23600c1f |
children | 6ffd095cf5dd |
files | README.txt commandparser/command.py setup.py tests/simpleexample.py |
diffstat | 4 files changed, 113 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/README.txt Mon Apr 02 10:42:13 2012 -0700 +++ b/README.txt Mon Jan 28 19:54:36 2013 -0800 @@ -1,8 +1,93 @@ CommandParser -=========== +============= change objects to OptionParser instances via reflection +Overview +-------- + +It is a common pattern for command line interfaces to use subcomands (e.g.): + + hg commit -m 'foo bar' + git push origin master + +CommandParser does this via introspection of a given class. When +invoked with a class, CommandParser uses the inspect module to pull +out the mandatory and optional arguments for each of the class's +methods, which are translated to subcommands, and make a OptionParser +instance from them. ``%prog help`` will then display all of the +subcommands and ``%prog help <subcommand>`` will give you help on the +``<subcommand>`` chosen. Methods beginning with an underscore (`_`) +are passed over. This gives an easy way to translate an API class +into a command line program:: + + class Foo(object): + """silly class that does nothing""" + def __init__(self): pass + def foo(self, value): + print "The value is %s" % value + def bar(self, fleem, verbose=False): + """ + The good ole `bar` command + - fleem: you know, that thing fleem + - verbose: whether to print out more things or not + """ + if verbose: + print "You gave fleem=%s" % fleem + return fleem * 2 + + import commandparser + parser = commandparser.CommandParser(Foo) + parser.invoke() + +(From http://k0s.org/hg/CommandParser/file/tip/tests/simpleexample.py ) + +Example invocation:: + + (paint)│./simpleexample.py help + Usage: simpleexample.py [options] command [command-options] + + silly class that does nothing + + Options: + -h, --help show this help message and exit + + Commands: + bar The good ole `bar` command + foo + help print help for a given command + (paint)│./simpleexample.py foo + Usage: simpleexample.py foo <value> + + simpleexample.py: error: Not enough arguments given + (paint)│./simpleexample.py foo 4 + The value is 4 + (paint)│./simpleexample.py bar blah + blahblah + +For optional arguments, the type of the default value will be +inspected from the function signature. Currently, mandatory arguments +are all strings, though this is clearly a shortcoming. + +The class docstring is used for ``%prog --help`` (and ``%prog help``, +same thing). The method docstrings (including those of ``__init__`` +for global options) are used for subcommand help. If the arguments +are listed in the docstring in the form given above +(``- <argument> : <something about the argument``) then these are used +to provide help on the individual options. Otherwise, these are left +blank. + +For straight-forward cases, it may be enough to pass your class +directly to the CommandParser constructor. For more complex cases, it +is an advisable pattern to create a new class (either via subclassing +or e.g. rolling from scratch, as applicable) that is more amenable to +CommandParser rather than modifying an (e.g.) API class to fit what +CommandParser expects. This allows the use of an object-oriented +interface for subcommands without sacrificing your API class, and if +you can subclass then there's really not much extra code to write. + +See http://k0s.org/hg/CommandParser/file/tip/tests for tests and examples. + ---- Jeff Hammel
--- a/commandparser/command.py Mon Apr 02 10:42:13 2012 -0700 +++ b/commandparser/command.py Mon Jan 28 19:54:36 2013 -0800 @@ -23,7 +23,6 @@ self.default=default class CommandParser(OptionParser): - # TODO: add `help` command def __init__(self, _class, description=None): self._class = _class @@ -165,16 +164,16 @@ doc = cleandoc(function.__doc__) else: doc = '' - args, varargs, varkw, defaults = inspect.getargspec(function) + _args, varargs, varkw, defaults = inspect.getargspec(function) if defaults: - args = args[1:-len(defaults)] - optional = dict(zip(args[-len(defaults):], defaults)) + args = _args[1:-len(defaults)] + optional = dict(zip(_args[-len(defaults):], defaults)) else: - args = args[1:] + args = _args[1:] optional = None command = {'doc': doc, 'name': name, - 'args': args, + 'args': args, # mandatory arguments 'optional': optional, 'varargs': varargs }
--- a/setup.py Mon Apr 02 10:42:13 2012 -0700 +++ b/setup.py Mon Jan 28 19:54:36 2013 -0800 @@ -4,7 +4,7 @@ import os -version = "0.1.3" +version = "0.2" dependencies = [] try: @@ -39,7 +39,7 @@ author='Jeff Hammel', author_email='jhammel@mozilla.com', url='http://k0s.org/hg/CommandParser', - license='', + license='MPL', packages=['commandparser'], include_package_data=True, zip_safe=False,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/simpleexample.py Mon Jan 28 19:54:36 2013 -0800 @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +class Foo(object): + """silly class that does nothing""" + def __init__(self): pass + def foo(self, value): + print "The value is %s" % value + def bar(self, fleem, verbose=False): + """ + The good ole `bar` command + - fleem: you know, that thing fleem + - verbose: whether to print out more things or not + """ + if verbose: + print "You gave fleem=%s" % fleem + return fleem * 2 + +import commandparser +parser = commandparser.CommandParser(Foo) +parser.invoke()