Debug your Flask(Python) web application using Visual Studio Code

There are several articles for helping us to learn how to debug flask applications in Visual Studio Code but they all didn’t help me at all because of one mistake. I hope this article will help some people like me who are banging their heads to figure out why they are unable to debug their flask application.

To build a small API or web application in Python I think Flask is the best framework candidate to start with. Whenever we look for an example mostly we will get the code sample looking like this.

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Hello, Flask!"

if __name__ == "__main__":
    app.run(port=1234, threaded=True)

To run this code we need python I am assuming you have it already if not please install I will recommend installing Python 3. Then you need to install Flask package. To do that run following command.

pip install Flask

Let’s assume you stored the above code in app.py. If you run below command you can see your application is up and running.

python app.py

If you open http://localhost:1234 in the browser you will see this

Congrats!!! your application is up. Let’s say you want to add little extra touch like creating a new API where you can page view counter. So we need to maintain somewhere it’s counter right when the server stops so we will store in a file at the time of server start we will load it.

# Usual imports
from flask import Flask
import os,signal

# Flask constructor takes the name of current module (__name__) as argument.
app = Flask(__name__)

page_view_counter = 0
counter_file_name = "visitor_counter.txt"


def init():
    """
    Page view counter loads from the file 
    where we stored last time when the application stopped.
    """
    global page_view_counter
    if os.path.exists(counter_file_name):
        counter_file = open(counter_file_name, "r")
        counter = counter_file.read()
        page_view_counter = int(counter)
        counter_file.close()

def on_stop(*args):
    """
    This function is triggered when the application stops and 
    then writes the current page view counter into the file for future use.
    """
    global page_view_counter
    counter_file = open(counter_file_name, "w")
    counter_file.write(str(page_view_counter))
    counter_file.close()

@app.route("/")
def home():
    return "Hello, Flask!"

@app.route("/hello/<name>")
def hello_there(name):
    """
    This function triggers when the hello route is called.
    This takes the value next to \/hello\/ as argument and 
    forms greeting text with the current page view counter.
    """
    global page_view_counter
    page_view_counter += 1
    content = "Hello there, " + name + "! This page viewed so far " + str(page_view_counter) + " time(s)"
    return content

if __name__ == "__main__":
    """
    This is where code execution starts when the application starts.
    It calls the init() method to load page view counter where we ended last time and 
    convey at what port we need to start the flask application too.
    """
    init()
    app.run(port=1234, threaded=True)

# Adding function on_stop() as listener function when the application stops.
signal.signal(signal.SIGTERM, on_stop)
os.kill(os.getpid(), signal.SIGTERM)

Code comments pretty much explain what exactly each function does. If you run app.py using below command your flask application starts

python app.py

If you open http://localhost:1234/hello/ashok in the browser you will see this

Hello there, ashok! This page viewed so far 1 time(s)

If you refresh the page or hit the URL again then the page viewed so far number changes. So, far everything is happy but if you want to debug this code then the problem arises.

I am using VS Code(Visual Studio Code) as IDE. In that, there is an option to debug the flask application. To do that I followed the following steps

In VS Code on the left, you will find the activity bar in that you can see icons in those you need to select Debug and Run.

Then we will get options like Debug with Python and Run with Python. Click on Debug with Python to run our application and then debug.

Then we will get options to choose for what kind of application you want to debug we wrote flask application so we usually click on Flask and it gives text box to enter what’s the path of the application file(app.py) once you give the relative path in my case flask-debugging/app.py then things get weird from here onwards

We don’t get anything when we hit URL(http://localhost:1234/hello/ashok) in the browser which used to work perfectly. If we see the terminal you will get something like this

env PTVSD_LAUNCHER_PORT=44957 /usr/bin/python3 /home/ashok/.vscode/extensions/ms-python.python-2020.2.63072/pythonFiles/lib/python/new_ptvsd/no_wheels/ptvsd/launcher -m flask run --no-debugger --no-reload 
 * Serving Flask app "flask-debugging/app.py"
 * Environment: development
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Let’s understand what it is saying, first of all, it doesn’t run the code which we have in if __name__ == “__main__”: so it runs on default port 5000 and one more thing it doesn’t run init function so it will never read our last page view counter at all.

After doing research I understood that Flask application runs run function and Python script starts from if __name__ == “__main__”: because python interpreter is running that module (the source file) as the main program, it sets the special name variable to have a value “main”.

So, we wrote Flask application like a normal Python script that’s why we are able to run the application by simply running the usual command python app.py.

To debug the application we need to choose Python File option after clicking on Debug with Python instead of Flask like this.

Then everything works fine you can put debug point where you want then with the respective operation debug stops there. I put the debug point at hello_there function and then hit the URL(http://localhost:1234/hello/ashok)

You can see the variable name value on left and page_view_counter value when you mouseover there. You will see 0 there because I deleted the visitor_counter.txt file.

To move the Execution from there you need to click on continue or hit F5 on keyboard.

If you open the browser you can see the output.

Hello there, ashok! This page viewed so far 1 time(s)

If you want to debug it as Flask application then remove if __name__ == “__main__”: block and put init() function. Now code looks like this

# Usual imports
from flask import Flask
import os,signal

# Flask constructor takes the name of current module (__name__) as argument.
app = Flask(__name__)

page_view_counter = 0
counter_file_name = "visitor_counter.txt"


def init():
    """
    Page view counter loads from the file 
    where we stored last time when the application stopped.
    """
    global page_view_counter
    counter_file = open(counter_file_name, "a+")
    counter = counter_file.read()
    if counter:
        page_view_counter = int(counter)
    counter_file.close()

def on_stop(*args):
    """
    This function is triggered when the application stops and 
    then writes the current page view counter into the file for future use.
    """
    global page_view_counter
    counter_file = open(counter_file_name, "w")
    counter_file.write(str(page_view_counter))
    counter_file.close()

@app.route("/")
def home():
    return "Hello, Flask!"

@app.route("/hello/<name>")
def hello_there(name):
    """
    This function triggers when the hello route is called.
    This takes the value next to \/hello\/ as argument and 
    forms greeting text with the current page view counter.
    """
    global page_view_counter
    page_view_counter += 1
    content = "Hello there, " + name + "! This page viewed so far " + str(page_view_counter) + " time(s)"
    return content

init()
# Adding function on_stop() as listener function when the application stops.
signal.signal(signal.SIGTERM, on_stop)
os.kill(os.getpid(), signal.SIGTERM)

Peace. Happy Coding.

Related Post