Skip to content

9.0 -- Scripting basics

Getting started with scripting in Python

Learning objectives

By the end of this tutorial you should:

  • Understand the basic building-blocks of a python script
  • Understand how the __main__ keyword defines the behavior of the script
  • Be able to use argparse to allow scripts to accept arguments of different kinds.
  • Use print statements for simple debugging

What is a script?

A script is just a text file that contains computer code. Python scripts should end with .py. Python scripts are executable at the command line, and this makes them very useful for developing bioinformatics tools. Let's see how scripts are developed.

Hello world, the simplest example script

Here is the simplest executable python script (which I will call myFirstScript.py).

#!/usr/bin/env python

if __name__ == "__main__":
    print("Hello world")

You can probably guess what this script does, but you can try running it yourself on the command line: python myFirstScript.py.

What makes this script executable is the funny looking if __name__ == "__main__" conditional test. Everything inside this if statement is run when the code is executed at the command line.

Adding imports and functions

Lets add a bit of functionality to generate a random password of a given length. We'll need the string and random from the standard library, so we'll import those at the top (as usual).

Now we write a new function inside our script called random_password which accepts 1 argument, being the length of the password, and we call this function from inside the __main__ block.

#!/usr/bin/env python

import random
import string

def random_password(length=10):
    # Define the set of available characters to sample from
    chars = string.ascii_letters + string.digits + string.punctuation

    # Generate a sample from this list
    password = random.choices(chars, k=length)

    # password is a list of characters here so `join` them together into
    # a string
    return "".join(password)

if __name__ == "__main__":
    print(random_password())

Adding flexibility with arguments

This is great because the passwords look strong, but what if you want to generate passwords of different lengths? The argparse module gives you a powerful way of adding command line arguments to your python scripts. Let's import it at the top of the file (Note: imports are normally sorted alphabetically, unless you have a good reason not to).

#!/usr/bin/env python

import argparse
import random
import string

def random_password(length=10):
    chars = string.ascii_letters + string.digits + string.punctuation
    password = random.choices(chars, k=length)
    return "".join(password)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-l", help="Password length in characters", 
                        dest='length', type=int, default=10)
    args = parser.parse_args()

    print(random_password(length=args.length))

There are 3 things happening here, most of the action is in the second part (adding new arguments to the parser):

  • You create the parser object
  • You add arguments to the parser, which themselves can take many different arguments
  • You call parse_args() to return a dictionary-like object containing data for the arguments specified.

When declaring arguments there can be few or many argument parameters. In the above example these were:

  • -l: The command line flag to identify this argument
  • help: The help message to print for argument usage
  • dest: The destination variable for the value of this argument (notice that we access the value as args.length)
  • type: The int type directs argparse to cast the value to an integer
  • default: Set the default value, in the case no value is passed in for this argument. If no default is set then the command line will complain about missing required values.

Here's another nice thing argparse does for you. It automatically generates a helpful help message when -h is passed in at the command line, e.g.:

$ python myFirstScript.py -h
usage: myFirstScript.py [-h] [-l L]

options:
  -h, --help  show this help message and exit
  -l L        Password length in characters

Providing helpful information with verbose

It's very common for command line programs to have a flag for increasing the verbosity (printing more progress messages). This can also be very helpful for debugging programs, as it allows you to toggle how much or how little your program is communicating to you (which, if it is working fine you probably want it to communicate very little besides the target output).

#!/usr/bin/env python

import argparse
import random
import string

def random_password(length=10, verbose=False):
    if args.verbose:
        print(f"Generating password length: {length}")
    chars = string.ascii_letters + string.digits + string.punctuation
    password = random.choices(chars, k=length)
    return "".join(password)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-l", help="Password length in characters", 
                        dest='length', type=int, default=10)
    parser.add_argument("-v", "--verbose", help="increase output verbosity",
                    action="store_true")
    args = parser.parse_args()

    if args.verbose:
        print(args)

    print(random_password(length=args.length, verbose=args.verbose))

Above we added one more argument now called verbose. Here we are doing a couple things different: We specify that it can be invoked either as -v or as --verbose, and we now tell it to action="store_true". The store_true action sets the value of verbose to True if it is invoked, and False otherwise.

The other thing we did is to propagate the verbose argument into the random_password function, so that we can also toggle verbosity inside this function. This is a very common practice in python scripts.

Check the help message of the new function:

$ python myFirstScript.py -h
usage: myFirstScript.py [-h] [-l LENGTH] [-v]

options:
  -h, --help     show this help message and exit
  -l LENGTH      Password length in characters
  -v, --verbose  increase output verbosity

And check the output with the new arguments:

$ python myFirstScript.py -v -l 30
Namespace(length=30, verbose=True)
Generating password length: 30
;GCM5y20>s+^zOF~QG,M@A+80N[6;#