Setting Up a Flask Application in Visual Studio Code

Posted by
on under

As a follow up to my Setting Up a Flask Application in PyCharm article, today I'm going to show you how to set up your project with Visual Studio Code (Code, for short), which is a free and open source integrated development environment from Microsoft with great support for Python. Like I did in the previous article, you can see me going through all the required steps to set up an example project in the video below. After the video, I provide a short written summary of the process.

Creating a Project in Visual Studio Code

To open a project for the first time in Code you just use the File|Open menu option and select the top level folder of the project. I've found that sometimes Code does not detect a Python project until you open a file with the .py extension, so if you don't see a Python interpreter displayed in the status bar at the bottom of the Code window, just open a Python file to trigger the Python subsystem to initialize. Note that the official Python plugin for Code needs to be installed beforehand.

The status bar shows the selected Python interpreter for the project. In general I've seen code pick up virtual environments that are in the project folder directly. If your virtualenv is somewhere else, click the Python interpreter section of the status bar and then you will be given the option to select your interpreter.

Adding Run and Debug Configurations

In Code, run configurations for a project are created in the debugger section of the user interface. So click on the little bug icon on the left side, and then on the configuration list drop down next to the green "run" button. Because this is a new project, the configuration list is empty and only has an "Add Configuration" option. Click this option and then you will be prompted to select from a list of project types. Very conveniently Flask is one of the list options, so select that. The Flask configuration will then prompt you for the application location, which must be given exactly as you set it in the FLASK_APP environment variable.

The new run configuration is stored in a new file called .vscode/launch.json. Since this is a standard JSON file, you can make changes or tweaks as you see necessary. And if you plan on using the Code configuration often you can also add this file to source control so that it is preserved.

With the configuration created you can now run the application with or without debugging, either from the Debug menu or by using the green "play" icon. When the application is running its output is captured in the bottom panel of the Code window. A small floating toolbar also appears near the top of the window with a Stop button. If you are running with the debugger enabled, you can add breakpoints by clicking in the left margin of the corresponding lines of code. Other buttons in the floating debug toolbar are used to step through the code when the application stops at a breakpoint.

Configuring Unit Tests

By looking at the Code window you will not find any indication that you can add unit testing to your configuration. Unfortunately the support for testing is somewhat hidden. To define unit tests you need to open Code's command palette, using Ctrl+Shift+P (Windows, Linux) or Cmd+Shift+P (Mac). In the command palette, you can type "tests" to search and filter the long list of available functions. Once you locate the function "Python: Discover Tests" select it.

The Discover Tests function will detect that unit testing isn't configured and will ask you if you want to configure it. Click the "Enable and Configure a Test Framework" to begin the configuration process. The test configuration is done with guided prompts, like the run configuration. In the first prompt, you have to select your test runner, which can be unittest, pytest or nose. The second prompt is to select the directory within the project that has all the tests. The third and last prompt is to select the file pattern for the test files. For this third prompt in general I use the *test*.py pattern, which covers pretty much all naming conventions for test files.

When you complete the configuration Code will go off to discover tests in the project. You will also notice that now there is a new icon for tests in the left sidebar. You can click this option to see all the discovered tests, along with options to run or debug all the tests together, or a single test individually.

Better Debug Configuration

The project configuration at this point is almost complete. There is actually one small problem with it, that is not caused by Code but by an old bug in Flask. The problem occurs when the application crashes, at which point a normal Flask application would either show the in-browser debugger when you are in debug mode, or else just show an Internal Server Error page and log the exception to the terminal and/or log file. When working with Code, it would be desirable to have crashes reported in the Code debugger, and this is unfortunately not possible with the current configuration.

The problem is in Flask, which does not properly configure the bubbling up of errors for external debuggers, so any crashes will never make it into Code. The workaround to address this problem is to switch from the flask run method of starting the application to the older app.run() method, which has more configuration options, including one to specify that exceptions should not be caught by Flask and should be let bubble up into another debugger.

To do this, you have to add the familiar app.run() snippet of code to the module that contains the application:

if __name__ == '__main__':
    app.run(use_debugger=False, use_reloader=False, passthrough_errors=True)

This configures the alternative app.run() runner properly for Code, where there is no need to use the in-browser debugger or the reloader. The passthrough_errors option is the one that allows errors to bubble up, an option that is unfortunately not available when you run the application with flask run.

To complete this change you have to go into the .vscode/launch.json file and change the module setting, which was set to flask in the original configuration to the name of your module (without the .py extension). The args options contained run and a couple other options, which now are not needed, so this setting should be change into an empty list.

With these changes the application can properly report unexpected errors and crashes into the Code debugger. It's important to note that flask run can still be used when you want to run your application outside of Code.

Conclusion

I hope this was a useful article and video. You may want to also check out the article and video that I've made for the PyCharm IDE based on the same project.

Become a Patron!

Hello, and thank you for visiting my blog! If you enjoyed this article, please consider supporting my work on this blog on Patreon!

25 comments
  • #1 Tiago said

    Hi Miguel,
    I've been following all your posts and learning a lot. Please, could you prepare an article explaining for example: Where should we keep our business logic in Flask or Django ? What about Fat Model ? It could be very cool.
    Thanks.

  • #2 Miguel Grinberg said

    @Tiago: Have you seen my longer tutorials, like the Mega-Tutorial or my O'Reilly book?

  • #3 Maulin Tolia said

    Do you use a linter on vscode?

  • #4 Miguel Grinberg said

    @Maulin: On some projects I do. But in general I have the linter running from tox, separately from vscode.

  • #5 Oleksis said

    Thanks for the tips, i want add one tip is use the terminal integrantes shell of Git bash.exe in Windows, why default i get the error in Visual Code python debugger: ConnectionRefusedError [WinError 10061]
    Then my settings.json is:

    {
    ....
    "terminal.external.windows Exec": " C:\Program Files\Git\bin\bash.exe",
    "terminal.integrated.shell.windows": " C:\Program Files\Git\bin\bash.exe"
    }

  • #6 Ralf Kretzschmar said

    Hi Miguel,
    first off: Thank you very much for your excelent resources. I am right now working through your book "Flask Web Developement, 2nd Edition". Great stuff! (Especially for me coming from a c#/.net background)

    One remark on debugging in VS Code. If you set the checkbox "On raised exceptions" in the Breakpoint section of the Debugger sidebar, exception break you into the debugger with the default run configuration.

  • #7 Miguel Grinberg said

    @Ralf: My understanding is that when you check "on raised exceptions" you will get a break on any exceptions, even those that are handled. So depending on the codebase you may get breaks on lots of false positives if the code relies on raising exceptions that are then handled in a higher scope. So I would still prefer the solution that I propose here in general.

  • #8 Kristin said

    I've faced the problem - I can't run the application for debugging. It's not running, then shows the exception message about Timeout waiting for debugger connection as described here: https://stackoverflow.com/questions/52462599/visual-studio-code-python-timeout-waiting-for-debugger-connection

    I tried all techniques in that post but nothing worked. Can you please help? Thanks!

  • #9 Miguel Grinberg said

    @Kristin: I suggest you reinstall VSCode, this is probably a bad installation.

  • #10 Brett Castellanos said

    Hi Miguel, thanks for the great content!

    I am working through the Microblog tutorial, but I thought setting up the debugger would be nice along the way. I followed the instructions in this tutorial but for some reason I am still receiving internal server errors.

    When I download the flasky repo and follow the instructions, errors are caught by the VS Code debugger.

    Any ideas what the difference could be?

  • #11 Miguel Grinberg said

    @Brett: you need to set debug mode (FLASK_DEBUG=1), and you also need to use the app.run() method of running the server, same as what I show in this article.

  • #12 Brett Castellanos said

    Thanks @Miguel. I somehow missed FLASK_DEBUG=1.

  • #13 Yanal said

    Hi Miguel,

    Thank you for this video.

    About the bug that prevents code from pausing debugging when an uncaught exception occurs, did you try to tick the "RaisedException" check box at the bottom left corner of VSCode (see at 25'00'' for instance) ?

    On my project, with the default configuration (with falsk run) vs code is pausing when an uncaught exception is raising up.

    Was the bug you are mentioning fixed? Am I missing something?

  • #14 Miguel Grinberg said

    @Yanal: if you tick the raised exception box the debugger will stop for all exceptions, even those that are handled. Depending on the application this could be maddening. The normal behavior with that box not ticked is to only stop for exceptions that are not handled, which is the behavior that we want, but Flask always catches exceptions in handlers due to the bug I refer to in the video. The bug is not fixed, by the way.

  • #15 Jeff said

    Hi Miguel,

    Big Fan. In the last 4-5 years, your content has been one of the few reliable resources I depend on when it comes to web development and learning.

    When can you comment on the changes I need to make to properly move from a Flask Blueprint/Application Factory framework (I use your mega-tutorial approach) to a format that allows for proper debugging in Code? For example, do I need to change the application entry point .py file to the app.run() method you referred to? Or do I need to move away from blueprints/factories all together? Much appreciated!

  • #16 Miguel Grinberg said

    @Jeff: the only change is to add the app.run() call so that you can configure VS Code to use that method to start the app and have a better debugging experience. The structure of your app is not affected by this, it does not need to change at all. Also you can continue to use "flask run" when you run the app outside of VS Code, this change is only to address the debugging issue in Flask when running from an IDE with integrated debugging.

  • #17 Sourav said

    I have a problem when i run flask ...
    when i run in command propt python (whatever the folder name).py then it not giving me ip for running my program it only giving me new command propt

  • #18 Miguel Grinberg said

    @Sourav: did you add the app.run() logic at the bottom of your Python file as I show in this article?

  • #19 Filipe Bezerra said

    I have followed the entire tutorial today and I encountered a problem when trying to use the Code (version 1.46.0 on windows) debugger using the tutorial's approach.

    Here's the bottom of the flask.py file

    if name == 'main':
    app.run(use_reloader=False, use_debugger=False, passthrough_errors=True)

    Here's the launch.json:

    {
    // 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: Flask",
    "type": "python",
    "request": "launch",
    "module": "flask",
    "env": {
    "FLASK_APP": "flasky.py",
    "FLASK_ENV": "development",
    "FLASK_DEBUG": "0"
    },
    "args": [],
    "jinja": true
    }
    ]
    }

    When I press to Start debugging the execution just stops and the terminal shows that:

    (venv) D:\education\handson\miguelgrinberg\setting-up-flask-application-in-visual-studio-code\flasky> cd d:\education\handson\miguelgrinberg\setting-up-flask-application-in-visual-studio-code\flasky && cmd /C "d:\education\handson\miguelgrinberg\setting-up-flask-application-in-visual-studio-code\flasky\venv\Scripts\python.exe c:\Users\filipebezerra.vscode\extensions\ms-python.python-2020.5.86806\pythonFiles\lib\python\debugpy\wheels\debugpy\launcher 52479 -- -m flask "
    Usage: python -m flask [OPTIONS] COMMAND [ARGS]...

    This shell command acts as general utility script for Flask applications.

    It loads the application configured (through the FLASK_APP environment
    variable) and then provides commands either provided by the application or
    Flask itself.

    The most useful commands are the "run" and "shell" command.

    Example usage:

    set FLASK_APP=hello.py
    set FLASK_DEBUG=1
    flask run
    

    Options:
    --version Show the flask version
    --help Show this message and exit.

    Commands:
    db Perform database migrations.
    deploy Run deployment tasks.
    profile Start the application under the code...
    run Runs a development server.
    shell Runs a shell in the app context.
    test Run the unit tests.

    So the debugger couldn't execute the application using the old way. So to fix that I had to add another configuration for our flasky module:

    Here's my final launch.json

    {
    // 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: Módulo",
    "type": "python",
    "request": "launch",
    "module": "flasky"
    },
    {
    "name": "Python: Flask",
    "type": "python",
    "request": "launch",
    "module": "flask",
    "env": {
    "FLASK_APP": "flasky.py",
    "FLASK_ENV": "development",
    "FLASK_DEBUG": "0"
    },
    "args": [],
    "jinja": true
    }
    ]
    }

    Note that we need to set the module property without the .py suffix. With that configuration we can start debugging switching between the flasky module and also the flask module.

  • #20 Miguel Grinberg said

    @Filipe: you haven't changed your run configuration to run python flasky.py instead of flask run.

  • #21 Scott Guthart said

    I'm getting gunicorn critical worker timeout errors when running my app within docker. I am using the way of calling app.run that you suggest. Is it possible that this is causing my timeout error?

  • #22 Miguel Grinberg said

    @Scott: I wouldn't think the method of starting the app would change things, but this is easy enough to try, right? Start your app with flask run instead and see what happens.

  • #23 Scott said

    Thanks, Miguel! You're right it wasn't. It was a very strange thing that was happening with SSL.

    On another note, I am wondering how you usually debug the javascript in your flask apps. Is it possible also to do it in VSCode?

  • #24 Miguel Grinberg said

    @Scott: I use Chrome to debug JS code. I believe it is possible to debug directly inside Code, but I haven't investigated that simply because Chrome is pretty decent to debug.

  • #25 Daniel Guetta said

    Thanks for the characteristically great post!

    Just a quick heads up that for me, automatic reloading did not happen in the vscode debugger, so after many, many hours of Googling, I figured out the right config to get auto-reloading goodness is:

    app.run(use_debugger=False, passthrough_errors=True) # Note that use_reloader is NOT set to False

    And CRUCIALLY, you also need to set "flask":true in your vscode launch.json file. Otherwise when Werkzeug throws an exception (SystemExit: 3) to force itself to restart, VSCode will annoyingly break at that error.

Leave a Comment