• Labs icon Lab
  • Core Tech
Labs

Guided: Debugging in Python

In this Guided Code Lab, you have been given a Python program that appears to be functioning well, but in reality has a few bugs that cause it to crash or produce incorrect results. To fix this, you will be utilizing the pdb module to debug the program by identifying these issues and resolving them. While this lab is Guided, it is recommended to have a decent grasp of Python, as the bulk of this lab will be tailored towards debugging rather than explaining common Python syntax and methods.

Labs

Path Info

Level
Clock icon Beginner
Duration
Clock icon 30m
Published
Clock icon Dec 11, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    Overview

    Welcome to the Debugging in Python lab. The program you will be working with in this lab calculates expected values for certain items in your inventory based on the values of their attributes.

    There are three Python files that you will need to be aware of for this lab. First is the seedData.py file, which is used to populate data within the bad_items.json and items.json. You can run it in the Terminal with the python3 seedData.py command at anytime to reset your inventory to a clean state.

    Second is the calc_util.py file, which contains most of the program's logic, such as calculating expected values, retrieving data from the inventory, and adding new items. However, it is missing a few checks and balances that cause the program to crash or provide incorrect values. You will be responsible for debugging and then fixing these issues during the lab.

    Lastly is the item_calculator.py file, which contains the main logic that runs the program. Like in calc_util.py, there are some edits you will need to make to ensure the program runs correctly. The program can be run in the Terminal with the python3 item_calculator.py command.

    Throughout the lab, you will be using the built-in pdb library to debug the program and identify the causes of these errors. You will then rectify these errors to ensure the program runs as intended. There is also a solutions directory that you can use to check your work. Keep in mind that your code does not need to exactly match the code in the solutions directory as long as you are meeting the objectives or expected behavior for the program.

  2. Challenge

    The Program

    Start with running the seedData.py file to ensure the inventory is in a clean state. Then run the item_calculator.py file. You will see some initial item values and a prompt on whether you'd like to add a new item or exit the program. If you choose to add a new item, you will be able to successfully add a new item so long as you are inputting numbers for A, B, D, and E.

    However, there is some incorrect behavior going on. First of all, if you were to input anything other than a number for the values, the program will immediately crash. You don't want crashes, you want to handle errors in user input gracefully. Secondly, expected values should never be negative. This means that you know there is an error in how the expected value is being calculated, which will be addressed later in the lab.

    First, change the JSON_FILE_PATH variable at the top of the calc_util.py file from 'data/items.json' to 'data/bad_items.json' and then run the program again. It will immediately crash. The first order of business is to fix the program to address the errors causing these crashes, then you'll need to fix the logic for why the expected values are being calculated incorrectly.

  3. Challenge

    Debugging with `pdb`

    To fix these errors, you will need to debug the program using the pdb library. The library has already been imported for you in item_calculator.py, so now you just need to use the function pdb.set_trace() to set breakpoints at any point in the code where you'd need to debug.

    When using set_trace() and running the program, the Terminal will enter an interactive session when the program reaches the breakpoint. You can use specific pdb commands to view variable values, examine surrounding code and the current stack trace, and step into functions to observe how values are calculated, all within this interactive session.

    You can start by debugging the first crash.

    Instructions 1. Run the program again. It should immediately crash, citing a `KeyError: 'E'` along with a traceback that details which line(s) of code caused the error. 2. Read the traceback to see where the error occurs, which is at lines 16-17. Place your breakpoint(`pdb.set_trace()`) right before the `item_val` variable in the for loop. 3. Run the program again to initiate the interactive session. Use the command `l` to display the code around the current breakpoint line. 4. Use `s` to step into the `item_val` variable, which is what is returned from the `calculate_item_value` function. 5. Use `p` to inspect the value of an expression. For instance, `p item["E"]` will print the value of the `"E"` key in `item`. However, doing this will print the `KeyError` that caused the crash. 6. Use `p item` instead to inspect everything inside of `item`. You can see here that the `"E"` key does not even exist, which is what causes the error and crash to occur. 7. Type `exit` or `quit` in the session to end the debugging session.

    As specified in the instructions, you used pdb to set a breakpoint in the code and step into the function call. In that function call, you were able to inspect variables and expressions to see what was occurring in the code, where you identified that the first item was missing a key. This was the cause for the KeyError causing the crash.

    To address this error, head over to the calc_util.py file and check out the validateItem() function at the bottom. You need to add validation to handle when an item is missing one of the required keys.

    Instructions 1. After `required_keys` in the `validateItem()` function, use a `for` loop to iterate through each `key` in `required_keys`. 2. If the `key` is not in `item.keys()`, print an error message of your choosing (ex. `f"Validation Error: Missing key '{key}' in item {item.get('item_id', 'unknown')}."`) then return `False`. 3. Return `True` outside of the conditional. 4. In `item_calculator.py`, use an `if` conditional for `validateItem` within the `for` loop. 5. Nest the `item_val` variable and `print` statement within this conditional.

    After implementing the first portion of validateItem(), you can run the program again. It will crash still, but this time you will see that it printed a validation error for the first item in the inventory, a normal print for the second item (since it is a valid item), then crashed presumably on the third item.


    As you saw previously, the crash should display a traceback that details which line of code was causing the error, along with a message that specifies the error. In this case, there is a TypeError that states only strings can be concatenated with strings. You will once again need to debug to see what's causing the error.

    Instructions 1. Use `pdb.set_trace()` right before `item_val` just like in the previous instruction. 2. You will see a validation error immediately being printed. This affirms that the validation is working and handling errors without causing a crash. 3. Use `c` to continue an iteration, which should print out the value for a valid item. 4. At the next iteration starting at the `item_val` line, use the `s` command repeatedly to step into the function until you see `--Call--`. This means you've entered the function call for `calculate_item_value()`. 5. Use `n` for next line or `s` to continue stepping into the function. You can use `l` as well to check which line of code you are on, but you want to keep using `n` or `s` until you reach the return statement at the end. 6. Use `p` to display the values of all the variables (A, B, C, X). You can view all of them with a single command by listing them separated by a comma.

    If displayed correctly, you should now see the values of A, B, C, and X. Notice how only A is a string, while the rest are numbers. This is the source of the TypeError being received earlier, as you can't add a string to an integer. You should modify validateItem() to address this just like you did for the KeyError.

    Instructions 1. Head to `validateItem()` again in the `calc_util.py` file. 2. Beneath the first conditional, add a second `if` conditional. 3. You should check whether or not the `key` is `"A"`, `"B"`, `"D"`, or `"E"`. 4. If it is, add another nested `if` statement to check whether the value is an integer or a float. One way to do this is `isinstance(item[key], (int, float))`. 5. If the value does not meet this requirement, print an error message of your choosing. An example could be `f"Validation Error: Invalid type for key '{key}' in item {item.get('item_id', 'unknown')}."`, and then return `False`.

    This validation that you added will now check for whether or not each of the weighted values of an item are numbers, otherwise it will handle it by printing an error message.

  4. Challenge

    Finishing Touches

    Recall that there were two other issues present in the program mentioned at the start. Although you have added validation to handle items with malformed properties, the program would still crash if you entered a non-number for any of its weights. You should fix that now.

    Instructions 1. The cited error was a `ValueError` in the `add_new_item()` method in `calc_util.py`. 2. `ValueError` is raised because the function converts user input to a float. If a non-number is supplied, it cannot perform this action and causes a crash. 3. To fix this, utilize a `try-except` block. Wrap the entire body of `add_new_item()` within the `try` clause. 4. For the `except` clause, printing any error message in response to the `ValueError` will suffice.

    Also, remember that all the expected values were incorrect because they kept being printed as negative, but all expected values should be positive. You may have noticed this while using pdb to debug calculate_item_value, where the displayed value for C in that session was a negative value. This would be the source of the incorrect expected values.

    This error differs because it is a logical error rather and a runtime error, meaning that the code will run without issue because all your errors are being handled, but the results are incorrect because the actual calculations have a mistake in them.

    Instructions 1. The flaw here lies in the conditional, which will always make `C` negative. 2. Change it so that it only runs when `D` is greater than `E` instead of less than. 3. Run the program again and check that your item value being printed matches the `expected_value` property for the corresponding items. 4. You can see this property in the `bad_items.json` file in the `data` directory.

    Well done! With all these fixes, the program should now be running as intended. You have managed to debug this program using the pdb library to make it fully functional. You can run it again for either json file (bad_items or items).

    Although you utilized some of the most commonly used commands for pdb for debugging, there are many more commands that pdb offers for debugging. You are encouraged to check them out in the pdb module in the official Python docs.

George is a Pluralsight Author working on content for Hands-On Experiences. He is experienced in the Python, JavaScript, Java, and most recently Rust domains.

What's a lab?

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.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.