Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson


00:00 In the previous lesson, I showed you how to write your own action. In this lesson, I’ll be covering sub-parsers.

00:08 A sub-parser gives you the ability to write commands within your script. This allows you to write scripts that have different actions. depending on the arguments, like git does with checkout, status, and its other commands.

00:22 A common pattern is to associate a function with each subcommand. Rather than writing a giant ifelse block of all the possible commands, you can use the .set_defaults() trick. .set_defaults() allows you to set values onto the namespace explicitly.

00:37 You can use it to set a value that points to your command function and then just invoke the value. Confused? Yeah, it takes a little. Let’s go look at it in some code.

00:50 This script supports three subcommands, One for each of the Indiana Jones movies. There were only three. Again, I’ll fight you. I’ve defined a function for each of the subcommands.

01:02 The first one is raiders(), and it takes args as a parameter. This isn’t required by the sub-parser, but it is good practice when using the methodology that I’m going to be showing you. By passing in the namespace object, your subcommand can get at any parameters that were passed to it.

01:19 My raiders() subcommand prints out a quote and uses the animal argument from the args namespace. The doom() command is similar. As I’m passing in args, I can use any of the argument definitions you’ve seen up until now. The doom() subcommand uses a repeat flag.

01:38 And for the final movie—you heard me—I use an argument to specify just how many camels Sallah brought. With the commands defined, let’s see how to wire this into the parser.

01:49 Scrolling down … This should be familiar, nothing different with this line. But here’s the new bit. Similar to creating mutually exclusive groups, you use the parser to create a sub-parser.

02:03 The title parameter is used in the help message, and the dest attribute indicates where to store the subcommand name. As I only want the user using the sub-parser and nothing else, I’ve set it to be required. Now to add the subcommands.

02:20 You take the sub-parser and add a parser. I’ve called mine sub. The name of the subcommand gets passed into the .add_parser() call.

02:30 This is the argument that goes after the subcommand. If you invoke the Indy script with the raiders subcommand, you have to give it the name of an animal. Spoiler alert. It’ll be snakes.

02:42 It’s always snakes. Here’s that func trick I so badly attempted to explain before. The .set_defaults() method on any parser, sub-parser or otherwise, sets one or more name-value pairs on the namespace. Here, I’m setting something called func with a value of the raiders function.

03:02 That’s a reference to the function itself. In a few lines, I’ll be using this default argument to invoke my subcommand function. For the doom command, I do something similar: another sub-parser, a new argument—this time, for repeating—and I use the .set_defaults() to point the func argument at the doom function. I also snuck something extra in here.

03:25 The metavar parameter to the .add_argument() method changes the name of the variable in the help message. Without this, you’d see -r and then REPEAT in all caps. With it, you see -r and NUM in all caps.

03:41 And the third subcommand, in the same vein: new parser, new argument, new association for the func argument, this time pointing to the crusade function. Scrolling down … Line 37 is no different than any other parser you’ve built.

03:58 The magic is on line 38. Line 37 creates the namespace like usual. depending on what subcommand was invoked, a different .set_defaults() method will have been called, changing the value of func inside of the namespace.

04:14 This overwriting mechanism means you can take the value of func and invoke it as a function. Each subcommand was associated with a different function at the top of the script. So this call will invoke the corresponding function. Tricky, huh?

04:30 You’ll recall that I wrote each of the subcommands to take the args namespace as a parameter. This is why on line 38, when I invoke the function, I pass in the args namespace.

04:41 This gives the subcommands access to the entire argument space. It’s that a swelling orchestra I hear? Let’s try this out.

04:55 There’s my first subcommand, which required an animal positional argument.

05:03 My doom subcommand, using its default value …

05:10 or the same subcommand, setting its repeat flag to 2.

05:19 And there’s the crusade command.

05:25 Like our other scripts, if you don’t have any positional arguments, you get the help message. It even shows what the choices for the subcommands are in the usage statement.

05:39 Let me just scroll back a little. As usual, using -h, you get the full help message. There’s the usage statement, then a list of the options, then the subcommands.

05:53 The subcommands themselves also support help.

06:00 By putting the -h after the doom subcommand, you get the doom subcommand’s help info. This is where that metavar parameter comes into play. Without it, the NUM here would say REPEAT in all caps. That probably have been a better choice, but then I wouldn’t have been able to demonstrate metavar. Don’t forget, you can also set the help parameter in the .add_argument() method to put more detailed information on this line, as well.

06:31 Wow. That was a lot of info on command line argument paassing. In the last lesson, I’ll summarize the course and point you at some other tools you can use to accomplish similar things.

Become a Member to join the conversation.