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

Callable Types and Custom Actions

00:00 In the previous lesson, I showed you a mix of less common parser features. In this lesson, I’ll show you some advanced parsing mechanisms.

00:09 You’ve used the type parameter to convert the command line string argument into an integer. You can also do this with the float type.

00:18 In fact, you can use any callable. Whatever the user gives you gets sent as the parameter to the callable. This gives some interesting possibilities. You could use the ord function to get the ASCII value or Unicode code point of a character.

00:35 You could directly use the open function to open the given file name. Or you could create a Path object in order to manipulate files.

00:48 But don’t go crazy. Some things are better to be handled in your code rather than as side effects to your argument parser. For example, the reason the store_true action exists instead of just using the bool callable is because bool treats empty strings as false and non-empty strings as true.

01:05 So your string containing 0 will not give the value you might have expected. That open I mentioned earlier, it just feels icky to me. And that could only get worse, if you start using a file decoder of some sort. It will work, but the errors start to become opaque.

01:23 The user won’t be able to see the difference between a bad value for the argument and a good value that points to a file with bad contents. Generally, I recommend sticking to the more common cases and avoiding getting too fancy.

01:36 This is both because you have to be careful with corner cases and also for the readability of your code. Another developer coming along might not expect the namespace to contain an open file, let alone a fully parsed one.

01:51 Title pretty much says it all. You can write your own storage actions. You do that by inheriting from argparse.Action. Let me show you how.

02:03 Before showing you how to write your own, I’m going to show you something slightly simpler, using the built-in action class that doesn’t correspond to an action string name. Instead of giving something like store_true, you can give any class that inherits from argparse.Action.

02:20 The argparse library comes with one of these called BooleanOptionalAction. This one works kind of like store_true, but allows you to use a --no version of the flag.

02:30 I’ll show you what that looks like in a second. The other thing I’ve done in this line is to use the dest parameter. This parameter allows you to specify what the name of the variable in the namespace is. Since try is a keyword in Python, if I attempted to use it as is, I’d get a CompileError.

02:48 But using the dest parameter, I can specify that the namespace store Try with a capital T, which is allowed by the compiler. Let’s try this out. Get it?

02:59 See what I did there? Please tell me I’m clever. I need your approval.

03:07 That’s the --try flag. Pretty much what you’d expect. Now for the difference …

03:15 The BooleanOptionalAction class supports the use of --no in a flag to turn something off. When nine-hundred years old you reach, look as good you will not.

03:30 All right, let’s write a custom action now. To do so, you need to inherit from argparse.Action. The initializer is rather specific. Make sure you get all the parameters correct.

03:42 My action is going to add "Bork, bork, bork!" to the string being stored. As such, I don’t want to handle multiple arguments. Single items only. On lines 6 and 7, I make sure that nargs isn’t set.

03:57 With that check out of the way, I call super() and let the parent class handle everything else. Now for the meat. The .__call__() method is what gets called to store the argument.

04:08 Your method must use these same arguments or it won’t work. What you get passed in is the parser instance, the namespace you’re modifying, the values from the command line, and any option strings. On line 12, I take whatever values I was given and add "Bork, bork, bork!" to the end.

04:27 And then on line 13, I do what all actions should do: store the value in the namespace. Scroll on down. To use the custom action, you need to set the action parameter at your class.

04:41 Note that it’s at the class, not at an instance object. Let’s try this out.

04:56 My script only takes a single argument, so to give it something with spaces in it, I need to surround it with quotes. The operating system uses space to distinguish between arguments sent to the script. By putting it in quotes, my entire sentence from Gonzo is considered as a single argument.

05:13 The sentence is then passed into the borkifying action and is stored with the desired suffix. Hurdy gurdy hurdy gurdy.

05:25 In the next lesson, I’ll show you how to build sub-parsers so that you can write scripts that take subcommands, similar to how Git does.

Become a Member to join the conversation.