# Tutorial

Argh is a small library that provides several layers of abstraction on top of argparse. You are free to use any layer that fits given task best. The layers can be mixed. It is always possible to declare a command with the highest possible (and least flexible) layer and then tune the behaviour with any of the lower layers including the native API of argparse.

## Dive In

Assume we need a CLI application which output is modulated by arguments:

$./greet.py Hello unknown user!$ ./greet.py --name John
Hello John!


def main(name='unknown user'):
return 'Hello {0}!'.format(name)


That was plain Python, nothing CLI-specific. Let's convert the function into a complete CLI application:

argh.dispatch_command(main)


argh.dispatch_commands([load, dump])


And then call your script like this:

$./app.py dump$ ./app.py load fixture.json


### Subcommands

If the application has too many commands, they can be grouped into namespaces:

argh.add_commands(parser, [serve, ping], namespace='www',
title='Web-related commands')


The resulting CLI is as follows:

$./app.py www {serve,ping}  See :doc:subparsers for the gory details. ## Dispatching Commands The last thing is to actually parse the arguments and call the relevant command (function) when our module is called as a script: if __name__ == '__main__': argh.dispatch(parser)  The function :func:~argh.dispatching.dispatch uses the parser to obtain the relevant function and arguments; then it converts arguments to a form digestible by this particular function and calls it. The errors are wrapped if required (see below); the output is processed and written to stdout or a given file object. Special care is given to terminal encoding. All this can be fine-tuned, see API docs. A set of commands can be assembled and dispatched at once with a shortcut :func:~argh.dispatching.dispatch_commands which isn't as flexible as the full version described above but helps reduce the code in many cases. Please refer to the API documentation for details. ### Modular Application As you can see, with argh the CLI application consists of three parts: 1. declarations (functions and their arguments); 2. assembling (a parser is constructed with these functions); 3. dispatching (input → parser → function → output). This clear separation makes a simple script just a bit more readable, but for a large application this is extremely important. Also note that the parser is standard. It's OK to call :func:~argh.dispatching.dispatch on a custom subclass of argparse.ArgumentParser. By the way, argh ships with :class:~argh.helpers.ArghParser which integrates the assembling and dispatching functions for DRYness. ## Single-command application There are cases when the application performs a single task and it perfectly maps to a single command. The method above would require the user to type a command like check_mail.py check --now while check_mail.py --now would suffice. In such cases :func:~argh.assembling.add_commands should be replaced with :func:~argh.assembling.set_default_command: def main(): return 1 argh.set_default_command(parser, main)  There's also a nice shortcut :func:~argh.dispatching.dispatch_command. Please refer to the API documentation for details. ## Generated help Argparse takes care of generating nicely formatted help for commands and arguments. The usage information is displayed when user provides the switch --help. However argparse does not provide a help command. Argh always adds the command help automatically: • help shellshell --help • help web serveweb serve --help See also #documenting-your-commands. ## Returning results Most commands print something. The traditional straightforward way is this: def foo(): print('hello') print('world')  However, this approach has a couple of flaws: • it is difficult to test functions that print results: you are bound to doctests or need to mess with replacing stdout; • terminals and pipes frequently have different requirements for encoding, so Unicode output may break the pipe (e.g.$ foo.py test | wc -l). Of course you don't want to do the checks on every print statement.

Good news: if you return a string, Argh will take care of the encoding:

def foo():
return 'привет'


But what about multiple print statements? Collecting the output in a list and bulk-processing it at the end would suffice. Actually you can simply return a list and Argh will take care of it:

def foo():
return ['hello', 'world']


Note

If you return a string, it is printed as is. A list or tuple is iterated and printed line by line. This is how :func:dispatcher <argh.dispatching.dispatch> works.

This is fine, but what about non-linear code with if/else, exceptions and interactive prompts? Well, you don't need to manage the stack of results within the function. Just convert it to a generator and Argh will do the rest:

def foo():
yield 'hello'
yield 'world'


Syntactically this is exactly the same as the first example, only with yield instead of print. But the function becomes much more flexible.

Hint

If your command is likely to output Unicode and be used in pipes, you should definitely use the last approach.

## Exceptions

Usually you only want to display the traceback on unexpected exceptions. If you know that something can be wrong, you'll probably handle it this way:

def show_item(key):
try:
item = items[key]
except KeyError as error:
print(e)    # hide the traceback
sys.exit()  # bail out (unsafe!)
else:
... do something ...
print(item)


This works, but the print-and-exit tasks are repetitive; moreover, there are cases when you don't want to raise SystemExit and just need to collect the output in a uniform way. Use :class:~argh.exceptions.CommandError:

def show_item(key):
try:
item = items[key]
except KeyError as error:
raise CommandError(error)  # bail out, hide traceback
else:
... do something ...
return item


Argh will wrap this exception and choose the right way to display its message (depending on how :func:~argh.dispatching.dispatch was called).

The decorator :func:~argh.decorators.wrap_errors reduces the code even further:

@wrap_errors(KeyError)        # catch KeyError, show the message, hide traceback
def show_item(key):
return items[key]    # raise KeyError


Of course it should be used with care in more complex commands.