For one of my projects, I wrote a new endpoint in a Flask application. My project had many pieces that built on each other, so I wanted to test in various ways and expand my backend debugging tool belt. Here are 3 tools I learned to use and now regularly use for debugging Python code. 🐍
curl is a command line tool for making HTTP requests. I like it because it’s a quick way to test endpoints are doing what I expect, but I found writing a curl confusing at first.
is optional and stands for verbose. With it, you’ll see all the details of the request and response that are normally hidden, which can be useful for debugging.
stands for header, and it’s how to specify extra headers to include in the request, such as an authentication token. In my example, the endpoint can only be accessed by school employees, so I’ve added a header to indicate that I am making an internal origin request. Otherwise, the request response would say I’m unauthorized. (It's not necessary to know what Envoy is for the example, but here’s more info if you’re curious: 1 & 2)
You don’t always have to specify extra headers (depends on the API or type of request), and you can include many headers in your request.
will perform a POST request.
-X allows you to change the HTTP method used because the default is GET.
stands for data. With this option, you can specify what data you’re sending to the HTTP server, in the same way that a browser does when you fill out a form and click the submit button. There are various ways to pass data in a curl POST request; in my example, I’m sending JSON.
Since I’m sending data, I need to let the server know the format of the data.
The Python interpreter is a tool that comes with your Python installation. It’s an interactive REPL in which you can type and execute Python code. I use it often to import and interact with the files I’ve written.
is how I launch the interpreter. But it’s more commonly invoked by typing
python3 (depending on your installation). Note: IPython provides extra features than the standard Python interpreter, but the examples I’m showing can be performed in the standard interpreter as well.
from app.models.student import *
imports the specific file to use in the interpreter. I am specifying the directory path of the student.py file: there’s a folder app at the top level directory which contains the folder models which contains the file student.py.
import * states that I want everything (
*) in that file. Note: when importing a file, do not add the file ending.
The import statement is necessary; without it, in my example,
.save() would be undefined and the Python interpreter would throw an error message.
Everything’s setup, and now I can test if my code is working as expected!
In this example, I'm testing a specific method
get_students in the Python interpreter.
What are some investigations I could do? Perhaps I can test what happens when a user passes in a string value. Or I can see what happens if a user passes in a valid integer value but a student with that id doesn't exist. Am I returning a helpful error message? In the method
get_students, I haven't done error handling...yet! In my experience, testing in the Python interpreter has been great for "ooooh yeah need to add that" realizations.
Pytest is a Python testing framework that can be setup quickly to run tests and report the results. It’s also another command line tool!
Here’s an example of an integration test that tests that a GET call returns the expected data.
I learned how to write tests by studying examples, and I was confused by what values were in a test, like json_body. So, I'd take tests a part and add print statements, like in the example below. But when running the test, I wouldn't see the output of the print statements. 🧐
python -m pytest
is how to invoke testing through the Python interpreter.
service_venv is specific to my development environment.
is the directory path of the file I want to test.
is the star of this example. Adding this option allows all print statements in tests to get printed in the terminal when the tests is run. Now I'd be able to see the value of print(json_body).
Pytest is a powerful tool with powerful features, but this small
-s flag has helped me to debug and learn how to write tests.
And that's it! I'm excited to see what other debugging tools I pick up as I continue to work on backend projects.