Adding Exception Handling to a Python Script

45 minutes
  • 3 Learning Objectives

About this Hands-on Lab

Our code won’t always be able to run without issue. So many things can go wrong when running code — network connectivity can fail, file system permissions can be wrong, bad inputs can be passed to our scripts. Thankfully, we can normally tell when these types of issues *might* happen in our code and we can handle them. In this hands-on lab, we’ll add exception handling to an existing script that can run into many of these issues. To feel comfortable completing this lab, you’ll want to know how to perform exception handling in Python (watch the “Handling Exceptions with `try`, `except`, `else`, and `finally`” video from the Certified Associate in Python Programming Certification course).

Learning Objectives

Successfully complete this lab by achieving the following learning objectives:

Add Exception Handling Around Setting the `name` Variable

The first expression in the exception_handling.py script reads from sys.argv, which is a list. If the script is run without any additional positional arguments, there won’t be an item at the index of 1 and we’ll receive an IndexError. Let’s add exception handling around this line to catch the error, print an error message about the number of required arguments, and then use sys.exit(1) to stop the script and exit with a non-zero status code.

~/exception_handling.py

import sys

# 1) Fetch name from the first argument passed to the script.
# If there is no argument, then exist with a readable error message.
# The potential error here is an IndexError.
try:
    name = sys.argv[1]
except IndexError:
    print("Error: please provide a name and a repeat count to the script.")
    sys.exit(1)

# Remainder of file omitted

Now if we run the script without any arguments, we should see this error message:

$ python3.7 exception_handling.py
Error: please provide a name and a repeat count to the script.
$ python3.7 exception_handling.py Kevin
Traceback (most recent call last):
  File "exception_handling.py", line 16, in <module>
    repeat_count = int(sys.argv[2])
IndexError: list index out of range

This next error is related to the next bit of logic in the script.

Handle Potential `ValueError` and `IndexError` When Setting `repeat_count` Variable

When we set the repeat_count variable, we index sys.argv at the index of 2 so we can once again run into an IndexError. In that case, we’ll want to provide the same error message we did for the name variable. Additionally, we can also run into a ValueError if the value provided cannot be cast to an integer, so we’ll need to have a second except statement that handles that and provides a more useful error message.

~/exception_handling.py

# previous code omitted

# 2) Convert the second argument to be an integer so that we can repeatedly print out
# the name argument. We should either a ValueError or an IndexError if there weren't enough
# arguments provided.
try:
    repeat_count = int(sys.argv[2])
except IndexError:
    print("Error: please provide a name and a repeat count to the script.")
    sys.exit(1)
except ValueError:
    print("Error: the repeat count needs to be a number.")
    sys.exit(1)

# remaining code omitted
Handle Potential File IO Errors When Writing to `name_repeated.txt`

The last section of this script deals with interacting with a file, so there are numerous potential errors we could run into. Depending on the version of Python we use to run the script, we could get either an OSError or a PermissionError if we don’t have permissions to interact with a file. To make this script backward-compatible, we’ll catch OSError since PermissionError inherits from OSError and would also be caught. Additionally, we’re going to catch IOError since this is another common error that happens when interacting with files. These error types will both be caught by the same except statement. Our requirements state that we need to print to the screen if we can’t write to a file, and we’re going to keep our try block small by writing to the file in the else branch if we can read from it.

~/exception_handling.py

# previous code omitted

# 3) Open a file called `name_repeated.txt` in the `root_files` directory and write a line for each time the name was
# repeated. If the user running the script doesn't have write permissions for the directory that
# we're writing to then we might see a PermissionError. PermissionError is new as of 3.3, so let's instead catch
# OSError and IOError to make the script more backward compatible. If an error is caught print to the screen instead.
try:
    f = open("root_files/name_repeated.txt", "w")
except (OSError, IOError) as err:
    print("Error: unable to write file (", err, ")")
    for i in range(1, repeat_count + 1):
        print(i, "-", name)
else:
    names = [name + "n" for i in range(1, repeat_count + 1)]
    f.writelines(names)
    f.close()

Now we’ve successfully handled all the common errors we might run into when running this script.

Additional Resources

Right now, the exception_handling.py file has quite a few potential issues that can happen when it is run, and we need to add exception handling so we can recover gracefully from issues that should be expected. For this script, any errors related to the arguments should immediately halt execution, print a readable error message, and exit with a status code of 1. After the arguments have been verified to meet our needs, we'll potentially run into some file IO errors. If we can't write to a file, we should instead print an error message and then print values to the screen.

Logging In

Using the Terminal To Complete the Lab

There are a couple of ways to get in and work with the code. One is to use the credentials provided in the lab, log in with SSH, and use a text editor in the terminal, such as Vim.

Note: When copying and pasting code into Vim from the lab guide, first enter :set paste (and then i to enter insert mode) to avoid adding unnecessary spaces and hashes. To save and quit the file, press Escape followed by :wq. To exit the file without saving, press Escape followed by :q!.

Using VS Code To Complete the Lab

You can also access the lab using VS Code in the browser. If you'd like to go this route, then follow the steps below:

  1. Navigate to the public IP address of the workstation server (provided in your lab credentials) on port 8080, using http (e.g., http://PUBLIC_IP:8080).
  2. If you receive a notification indicating the connection is not secure, click Advanced. Then, proceed to the server.
  3. Use the password provided in your lab credentials.

What are Hands-on Labs

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Sign In
Welcome Back!

Psst…this one if you’ve been moved to ACG!

Get Started
Who’s going to be learning?