Tutorial 12: Exit Code¶
There are a lot of places execution can go wrong. clik lets you bail
out at any point by yielding a non-None value. The value yielded
is used as the exit code for the invocation.
…well, kind of. When a subcommand yields non-None, clik
immediately starts “unwinding” through the cleanup blocks of the
parent commands. Parent commands can override the exit code from
children.
…and you really can unwind from anywhere. That first yield separating
the “parser config” block from the “do stuff” block? If you yield
non-None from there the application will exit before the parser is
even fully configured. Meaning that it’s a hard fail, and end users
won’t even be able to use -h/--help. In general this isn’t what
you want, but consider a situation where a default value to a critical
argument (say, “database host”) is expected to be in an environment
variable. You control all the machines the app runs on, and it really
is a situation where, if that variable is not set, all kinds of stuff
is wrong. In that case it might be perfectly appropriate to hard fail
without even initializing the parser. The point is: clik gives you the
choice and makes it easy to do that if you want to.
Back to our application:
@todo
def add():
# ... snip ...
if item:
g.item_list.append(item)
# ... snip ...
else:
print('error: empty item', file=sys.stderr)
yield 1 # <--- !!! new code !!! ---
# ... snip ...
@todo
def done():
# ... snip ...
if args.all:
del g.item_list[:]
else:
# ... snip ...
if -1 < index < len(g.item_list):
del g.item_list[index]
else:
print('error: index out of range:', index, file=sys.stderr)
yield 1 # <--- !!! new code !!! ---
# ... snip ...
The application now has an exit code of 1 when the user provides
invalid input and, as a nice side effect, the “Updated list” is no
longer printed when the list is not actually updated:
$ ./todo add ""
error: empty item
$ echo $?
1
$ ./todo add
Item to add:
error: empty item
$ echo $?
1
$ ./todo add "Pick up nails from the hardware store"
Updated list:
0. Pick up nails from the hardware store
$ echo $?
0
$ ./todo done -i asdf
usage: todo done [-h] [-a | -i INDEX]
todo done: error: argument -i/--index: invalid int value: 'asdf'
$ echo $?
1
$ ./todo done -i -1
error: index out of range: -1
$ echo $?
1
$ ./todo done
0. Pick up nails from the hardware store
Item number to remove? 5
error: index out of range: 5
$ echo $?
1
$ ./todo done -i 0
Updated list:
$ echo $?
0
One final tweak and the tutorial is complete!