Retrieving the CommandLine in Python scripts

Retrieving the CommandLine in Python scripts

Overview

In this post we dive into the world of automation and agility with Python, exploring how the argparse module makes command-line work simple. Through clear, concise examples, we will see how to make our scripts more powerful and flexible, opening up new possibilities for daily programming tasks. Get ready to add a valuable tool to your Python development toolkit.

Using command lines in Python scripts is reasonably simple. The script below works in Python 2.8 or higher. There are more options and alternatives to read the command line, but let's stick to the basics for now.

 1import argparse as args
 2
 3parser = args.ArgumentParser(description='Analyzing commandline...')
 4parser.add_argument("-b", "--blockfile"
 5                    , default="blocklist.txt"
 6                    , required=False
 7                    , help="File containing the sites that should be blocked. One site per line.")
 8
 9parsed_args = parser.parse_args()
10
11print(parsed_args.blockfile)

Explaining the code above:

  • First we import the class that processes command-line input;
  • Then we create a Parser to analyze the command line. The "description" attribute will be displayed when this line is processed;
  • The next step is to add each argument you want to receive in your script;
    • The first two attributes are the name and the flag for the argument. Either value can be used on the command line to define the value;
    • default is the default value for this argument, if it is omitted;
    • required defines whether the argument is mandatory. If it is required, the default attribute is ignored;
    • help is the text that will be displayed when the script is run with -h (or --help);
  • Once all the arguments are set, just use the function parse_args() to retrieve the values passed on the command line. This function returns a variable with all the argument values.

This will be the result of the above code, if the script is executed with no arguments:

1python demo.py
2
3blocklist.txt

...if we change the required attribute to true and still don't pass any arguments:

1python demo.py
2
3usage: PyGuestWatcher.py [-h] -b BLOCKFILE
4PyGuestWatcher.py: error: the following arguments are required: -b/--blockfile

...running the script, passing the argument using the name (-b) and the flag (--blockfile):

1python demo.py -b 'foo.bar'
2
3'foo.bar'
1python demo.py --blockfile 'foo.bar'
2
3'foo.bar'

Update: 13/09/2018

Before the content update, a quick context: the example above is from a script I wrote to block access to websites. It reads the blocklist.txt file and adds those sites to the hosts file, pointing them to localhost.

Ok. Let's update the content...

The previous example works well, but argparse has other useful options.

Let's imagine a new script with a new command line. The first thing you should do is instantiate the parser:

1# Instanciating commandline argument parser
2parser = args.ArgumentParser("Analyzing commandline...")

Now let's add some arguments with different configurations. At the end, I show a summary of these configuration options.

Required numeric argument

1    parser.add_argument("-i", "--number",
2                        required=True,
3                        dest="arg_num",
4                        type=int,
5                        help="This is a required numeric argument.")

In the code above there are two parameters that were not used in the earlier example:

  1. dest: Indicates the name of the variable that stores this argument's value. If not set, the value is stored in a variable with the argument's name. In this case, if I had not set the dest parameter, the value would be accessed through a property named "number";
  2. type: Indicates the type of the argument value. That means the arg_num variable will hold a numeric value and not a string (which is the default);

Required string argument

1    parser.add_argument("-s", "--string",
2                        required=True,
3                        dest="arg_str",
4                        type=str,
5                        help="This is a required string argument.")

Similar to the previous argument, but with the type set to string (str), which is the default.

Optional numeric argument

1    parser.add_argument("-oi", "--optional-number",
2                        required=False,
3                        dest="arg_opt_num",
4                        type=int,
5                        help="This is an optional numeric argument.")

Optional string argument

1    parser.add_argument("-oi2", "--optional-number2",
2                        required=False,
3                        dest="arg_opt_num2",
4                        help="This is an optional numeric argument without a type defined.")

In this argument I say I am expecting a number, but since type is not defined as int, the value will always be a string.

Another optional string argument

1    parser.add_argument("-os", "--optional-string",
2                        required=False,
3                        dest="arg_opt_str",
4                        type=str,
5                        help="This is an optional string argument.")

This argument is optional (required=False) and is explicitly defined as string (type=str).

One more optional string argument

1    parser.add_argument("-os2", "--optional-string2",
2                        required=False,
3                        dest="arg_opt_str2",
4                        action="store",
5                        type=str,
6                        help="This is an optional string argument with explicit store action defined.")

This argument is similar to the previous one, but has an extra parameter, action. It defines what will be done with the provided argument. The default value is "store", which simply stores the argument value in a variable.

Flag argument (sets value to True)

1    parser.add_argument("-t", "--true",
2                        required=False,
3                        dest="arg_true",
4                        action="store_true",
5                        default=False,
6                        help="This is a flag argument. If informed, will be set to true, otherwise, will be false.")

The argument above has a different action, store_true. This indicates that if you use this flag, the value stored in the dest variable will be True. The default value for this argument is (for obvious reasons) False.

By flag I mean an argument you use by itself. Unlike a numeric argument (-i 42), you only use the argument itself (-t or --true).

Flag argument (sets value to False)

1    parser.add_argument("-f", "--false",
2                        required=False,
3                        dest="arg_false",
4                        action="store_false",
5                        default=True,
6                        help="This is a flag argument. If informed, will be set to false, otherwise, will be true.")

This argument is similar to the previous one, but its values are inverted: by default, this argument is considered True and if it is provided, it changes to False. This is defined by the action value store_false.

Flag argument without a default value

1    parser.add_argument("-n", "--no-default",
2                        required=False,
3                        dest="arg_flag",
4                        action="store_false",
5                        help="This is a flag argument. If informed, will be set to false. No default configured for this.")

The argument above does not have a default value, but its action is set to store_false, so if it is omitted, the arg_flag variable will end up with the value True.

This shows that argparse is smart enough to understand that if you want to store False in a variable when the argument is used, then that variable should have the opposite value (True) by default.

List argument

1    parser.add_argument("-l", "--list",
2                        required=False,
3                        dest="arg_list",
4                        default=[],
5                        action="append",
6                        help="This is an optional list argument with default value defined.")

The argument above is a list, meaning you can use it multiple times on the command line, and each value will be appended to the variable. This behavior is defined by the append value in the action parameter.

List argument (numeric)

1    parser.add_argument("-li", "--list-int",
2                        required=False,
3                        dest="arg_list_int",
4                        type=int,
5                        action="append",
6                        help="This is an optional list of numbers argument with no default value defined.")

This argument is similar to the previous one. The first difference is that it defines a type for the values passed (type=int) and that implies the variable will hold a list of integers.

The other difference is that we did not define a default value (default=[]) for this argument. That means if this argument is not used, the arg_list_int variable will have the value None instead of an empty list ([]).

List of constants argument

 1    parser.add_argument("-lc1", "--list-const1",
 2                        required=False,
 3                        dest="arg_list_const",
 4                        action="append_const",
 5                        const="Flag 1",
 6                        help="This is a flag that adds a constant value to a list.")
 7
 8    parser.add_argument("-lc2", "--list-const2",
 9                        required=False,
10                        dest="arg_list_const",
11                        action="append_const",
12                        const="Flag 2",
13                        help="This is a flag that adds another constant value to a list.")

Above are two arguments, but they are part of the same process. Both are defined with action set to append_const, which means they add a pre-defined value to the variable, resulting in a list of predefined values.

The difference between append and append_const is that append adds the value the user provides to the list, while append_const adds the value you defined.

For this action to work correctly, the dest parameter must be the same for all relevant arguments.

Version argument

1    parser.add_argument("-v", "--version",
2                        action="version",
3                        version="{} | ver {}".format(__file__, __version__),
4                        help="Argument that prints the current version of your application.")

Just like the help argument (-h or --help), an argument with action set to version will override other arguments and display only its information. That means you cannot mix a version argument with others on the same command line.

This argument standardizes a way to display your application's version. When used, it shows the text defined in the version parameter.

Summarizing the parameters for add_argument

  • First parameter (positional) receives the argument "nickname" (example: -v);
  • Second parameter (positional) receives the full argument name. If the dest parameter is not set, this will be the variable name that stores the argument value;
  • required: Indicates whether the argument is required (True/False);
  • dest: Indicates the name of the variable that receives the argument value;
  • action: Indicates which action will be taken for the argument. Possible values are:
    1. store (default): Stores the argument value in the variable;
    2. store_true: Stores True if the argument is used. Otherwise, the value will be False;
    3. store_false: Stores False if the argument is used. Otherwise, the value will be True;
    4. append: Adds the argument value to a list;
    5. append_const: Adds a pre-defined value to a list. You should add several arguments, one for each value that can be added to the list;
    6. version: Prints the application version (defined in the version parameter);
  • const: Used only when action is set to append_const. In that case, the value defined in this parameter will be added to the list;
  • default: Default argument value, if the user does not provide it;
  • version: Used only when the action is set to "version". In that case, the value informed in this parameter will be displayed to the user;

To make it easier, I made an example on GitHub where you can pass these values and see the result in the console. It will only show the variable name passed via the command line, its value, and the value type.

I hope this helps!

Reference:

Translations: