Debugging a Tornado/ PythonOnWheels web application with VSCode.

Klaas (khz)
7 min readAug 13, 2019

In this short hands on tutorial you will learn how to debug a Tornado/PythonOnWheels web application with Visual Studio Code (VSCode). In fact this a really simple task. It is really handy to setup debugging in VSCode because it really eases the development flow. You have all information in one place. And it also looks great ;) Since PythonOnWheels is Tornado based, this will also work for any other Tornado Application.

Teaser: this is what we get in the end. Really nice and helpful. Everything in one place.

Why ?

It really eases debugging your apps. I am personally a friend of logging for production systems and just printing to stdout for most of the development debugging. But when you setup debugging in VSCode once you see the advantages.

  • Set breakpoints
  • See all variables in the current execution scope
  • Step into methods or step over them
  • And everything in a single view.

Pre-Prerequisites:

Install PythonOnWheels and create a project. PythonOnWheels is a Tornado based web-framework for Python based on the “ruby on rails workflow”. Installing PythonOnWheels and setting up a project is just a matter of minutes and works on Windows, Linux and Mac. If you don’t know how to do this just read the short getting started documentation (5 Minutes).

Prerequisites:

  • create a new PythonOnWheels (PoW) app called debugtest
  • add a virtual environment in the folder debugtest/venv.
  • install the pow requirements.
  • install VSCcode (if you do not have already)
  • install the python extension for VSCode (if you don’t have that already as well)

Setup debugging in VSCode for your project:

1) Set the python interpreter

In VSCode first select the “correct” python interpreter to use for your project. Which is the one from your project’s virtualenv.

  • Open the Command Palette (Views->Command Palette)
  • choose: Python: Select Interpreter
  • now choose the one pointing to your current ./venv/. (This is a little different on windows :.\venv\Scripts\python.exe and Linux/OSX where it is: ./venv/bin/python)

2) Configure the debugging setup

  • Click on the debug icon to open the VSCode debug view (or go to view->debug)

Right next to the “start debugging” arrow You can see that there is currently no configuration for this project.

  • Just click the dropdown next to “No Configurations” and:
  • Click on “Add configuration”
  • Choose the configuration template for: Python File (This will create and open a dummy launch.json file for us.)

Now the important part: create the configuration for a PythonOnWheels / Tornado project

  • replace the launch.json content with the following
{  
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: PoW",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/server.py",
"args": [],
"console": "integratedTerminal"
}
]
}
  • Now save your launch.json file. This is how it should look now.

This configuration (named: “Python PoW”) will basically just use your configured python interpreter to launch the server.py file in your current project directory (${workspaceFolder}). And this is enough to start and debug your web application with vscode. You can also add command line arguments in the args[] array, or even add environment variables by adding an env[] array , but we don’t need that for the moment.

So let’s test this with a debugging session.

  • Switch back to VSCode file explorer and open your hello_world handler (handlers/hello_world.py)
  • Add a breakpoint in line 10 by just left-click before the line number. This will add a red ball before the line
  • Switch back to debug view: (click the bug icon or go to view->debug). This will open an “empty” debug view. Keeping your current file open so you can still easily see your breakpoint. (You can also see all breakpoints of your project in the bottom left of the debug view.)
  • Now start a debugging session by clicking the green play icon next to your Python PoW config. This will start a debugging session with the setup we just configuired in our launch.json. Make sure that the config is named: Python PoW

You can See in the picture below that this automatically adds a terminal view (if you did not have already one) which shows that the PythonOnWheels application sucessfully started (in the bottom right). And you also get some control icons in the upper right of VSCode. To resume, step in, pause or stop debugging.

Let’s hit the breakpoint

But we don’t see any valuable added debugging informations so far, since the application did not hit our breakpoint yet. It is just executing the Tornado IOLoop, waiting for requests to come. To force hitting the breakpoint:

  • Now open a broser and go to the /hello URL of your project. If anything is default (as in my case) this is:
http://localhost:8080/hello

This is what VSCode shows us now:

You can see the small yellow arrow around our breakpoint. This is where the application is right now. It stopped execution just before executing line 10. If you look at your browser window in parallel, you will also notice that your Browser request does not finish. This is because we did not execute the response:

self.write("hello world")

You can now also see tons of useful information about variables that are currently available to the scope of the HelloHandler instance. These are all loaded by the debugger for us. I think you’ll agree that this is truely much more helpful than just a few prints. But, by the way you can see any print() debug info you want or have already in the Terminal window below as well.

So we really have the best of both worlds here in one single view!

Adinitionally you can also see the call stack (in the bottom left of the debug view). Which shows us the PythonOnWheels application flow.

http request -> Server -> Base Handler -> Route + Request Type (GET, POST.. ) => actual handler / method call.

In this concrete case:

http request (/hello, GET) -> Server -> Base Handler -> /hello+ Request Type (GET) => HelloHandler.hello_world()

Now, let’s continue the application and finish the request.

To control your application you can use the control bar in the upper right. Finish the request by clicking the blue “Pause/Play” icon (Or press F5)

Two things will happen:

  • Your browser now shows “hello world!” (so the request really finished”
  • The debug view becomes empty again, because our application is in the applications IOLoop again, waiting for new requests.

Next: Test it out, play around

I really recommend to play around a little with this and inspect all the infos available to you in the Variable view. I just want to point out the request Variable which contains all the information that the browser send witrh the request and is available to you in the application. This is an excertp which came with the /hello demo call (Firefox). Lot’s of info about the path, request-body, cookies, …..

This is it

Just a short intro but I hope this is as helpful for you, as it was and is for me ;). By the way, this way of configuring debugging is of course also applicable not only for Tornado based applications like PythonOnWheels but for many other python projects you may use. Almost always just define the correct python interpreter and add a basic launch.json as a start.

Read more about PythonOnWheels in the documentation. Like connecting to MongoDB, expose JSON/REST APIs for SQL DBs in a few minutes and more…

--

--

Klaas (khz)

11 to 1 pm spare time software developer. Mostly python.