Advanced Visual Studio Code for Python Developers

Advanced Visual Studio Code for Python Developers

by Anthony Shaw advanced editors tools

Visual Studio Code, or VS Code for short, is a free and open source code editor by Microsoft. You can use VS Code as a lightweight code editor to make quick changes, or you can configure it as an integrated development environment (IDE) through the use of third-party extensions. In this tutorial, you’re going to look at how to get the most out of VS Code for Python development.

During this tutorial, you’ll learn how you can configure, extend, and optimize VS Code for a more effective and productive Python development environment. After finishing this tutorial, you’ll have a variety of tools to help you be more productive using VS Code. It can be a powerful tool for rapid Python development.

In this tutorial, you’ll learn how to:

  • Customize your user interface
  • Run and monitor Python tests
  • Lint and format your code automatically
  • Leverage type annotations and Pylance to write code faster with higher accuracy
  • Configure and utilize both local and remote debugging
  • Set up data science tools

As usual, this tutorial is full of links, tips, and tricks to help you on your way.

If you haven’t already installed Visual Studio Code or the Python extension, you’ll need both for this tutorial. If you’re just getting started with VS Code, you might want to check out Jon Fincher’s tutorial on Python development in Visual Studio Code before continuing with this one.

Mastering the Visual Studio Code User Interface

By default, VS Code’s user interface is designed for everyone—whether you’re writing C++, doing front-end development with JavaScript and CSS, or using data science tools like Jupyter Notebooks. In this first section, you’ll explore how to tailor VS Code to support how you work.

Keyboard Shortcuts

For almost everything that you do in VS Code, you can do it directly from the keyboard. You can map all activities in VS Code, whether they’re built-in or provided via extensions, to a keyboard shortcut.

A small subset of built-in commands is already mapped in Keyboard Shortcuts. If you want to learn these default shortcuts, print out the PDF for Windows, macOS, or Linux and pin it next to your monitor.

As a Python developer, a lot of the commands you’ll use in Visual Studio Code are provided from extensions, similar to the Python extension that you already installed. These don’t come with shortcuts mapped by default, but you can configure them using VS Code’s Keyboard Shortcuts editor.

Using the Keyboard Shortcuts Editor

Open the Keyboard Shortcuts editor by going to File → Preferences → Keyboard Shortcuts or Code → Preferences → Keyboard Shortcuts on macOS:

VS Code Keyboard Shortcut Window

In this editor, you can see a list of all the existing shortcuts along with their details:

  • Command: The command or action to be run
  • Keybinding: The sequence of keys to press to trigger this command, with a blank indicating that there’s no mapping
  • When: Conditions that need to be met for this keybinding to work, with a minus sign (-) indicating that there are no requirements
  • Source: Where this binding was configured, either defined by Default, User, or Extension, the last one indicating that you provided it by installing a keymap extension

To override an existing binding, right-click on the existing action and click Change Keybinding. To assign a keybinding to a command that has no binding, double-click on it. If the key sequence you press is already assigned to something else, VS Code will warn you with a link to see which commands are mapped to this keybinding.

As an example, type python create terminal in the search box at the top. If no results come up, make sure you have the Python extension installed. Press Enter to assign a keybinding, like Ctrl+Alt+T, and then hit Enter again.

To assign that shortcut to only work when you’re editing Python code, right-click on the shortcut and select Change When Expression. Enter the expression editorLangId == 'python':

Assigned keyboard shortcut

There are more conditional operators to choose from if you need something more specific. Here are some examples to get you started:

  • Use resourceFilename == '__init__.py' when the file you’re editing is __init__.py
  • Use editorLangId == 'python' when working with Python. If needed, you can also replace 'python' with another language identifier.
  • Use editorHasSelection for when you’re inside the editor.

Once you’ve configured this extension, open up a Python file in the editor to try it out by pressing your newly assigned keyboard shortcut Ctrl+Alt+T to open up a Python terminal.

Setting Up Keyboard Shortcuts for Commands From the Command Palette

You’ll refer to the Command Palette many times in this tutorial. Most of the functionality in VS Code is accessible through the UI from context menus, but you won’t find everything there. Anything that can be done in the core editor or via an extension is available in the Command Palette. You can get to the Command Palette by pressing one of these keyboard shortcuts:

  • macOS: F1 or Cmd+Shift+P
  • Windows or Linux: F1 or Ctrl+Shift+P

To run a command, type its descriptive name, like Python: Run All Tests. Once the Command Palette is up and the command you want is at the top of the menu, click the cog on the right to assign a keyboard shortcut:

Assigning a shortcut from the command palette

Once you’ve started using the Command Palette regularly, you may find that there are five to ten commands you run really often. Assign some shortcuts to those commands to save yourself a few extra keystrokes.

Installing Keyboard Mappings From Other Editors

If you’ve been working in another editor or IDE for some time, you may have your usual keyboard shortcuts committed to muscle memory.

You’ll find helpful keyboard mappings in extensions for Vim, IntelliJ and PyCharm, Sublime Text, Notepad++, Emacs, and Atom.

If your previous editor isn’t on this list, you may find that someone else has created a mapping extension for you. Keymaps is a helpful category on the VS Code extension marketplace.

Once you’ve installed a keymap extension, you may also find additional options to customize it beyond the defaults. For example, you can use the Vim keymap extension to configure Vim features such as whether to start in insert mode.

Customizing the User Interface

The first things you should do when jumping into the driving seat of a car are to adjust the seat, adjust the rear-view mirror, and set the steering column to the right height. Code editors are no different. They come with a default layout that works okay for everyone but not especially well for anyone. You don’t want to stretch to reach the pedals. Let’s set up your VS Code environment to suit you and make it look great on the way.

First, the Activity Bar on the left-hand side of VS Code is the main navigation tool to switch between the Explorer view used to see your files, the Source Control view, the Search view, the Run and Debug view, and the Extensions view. You’re not limited to these options. Many extensions come with views that are hidden by default. Right-click on the Activity Bar to control which views you see:

VS Code activity bar

You can also use this menu to hide any views that you never use. Keep in mind that you’re not limited to the views on the list. If there are some panels within a main view—for example, you can find some additional panels nested inside the Explorer view—you can drag them to the Activity Bar to create a permanent shortcut:

Dragging an item to the activity bar

Use this feature for views that you use all the time.

Using Split Screens

Python’s style guide, PEP 8, leans toward short line lengths. For wide screens, this leaves a lot of unused screen space.

When you find yourself needing to switch between two or more files, use the split panel functionality to show many editor regions at once. You can access this functionality through the Command Palette with the command View: Split Editor.

Alternatively, you can use the associated keyboard shortcut:

  • macOS: Cmd+\
  • Windows or Linux: Ctrl+\

You can also open the split editor functionality by going to View → Editor Layout or by right-clicking on a file’s tab:

VS Code splitting a panel

This setup is really useful when writing unit tests with your test code on the left and the module you’re testing on the right.

Some file types, like Markdown, have a preview region that you can use instead. Use the Markdown: Open Preview to the Side command to open the preview editor.

Using Zen Mode for Focused Work

If you need your absolute focus on a single file or task in VS Code, then use Zen Mode by going to View → Appearance → Zen Mode to show a full-screen window with just the editor:

VS Code in Zen Mode

This feature is especially useful for blocking out noisy distractions and notifications so that you can just focus on getting your current task done.

Theming

VS Code has a huge library of themes in the VS Code Marketplace. Some of the most popular themes out there are Material Theme, Winter is Coming, Dracula, Noctis, and Monokai Pro.

Let’s focus on the Material Theme as it comes with a broad set of color schemes to suit many tastes. You can install the extension from the Extensions view. Once installed, you can select a color theme by running Preferences: Color Theme in the Command Palette.

The Material Theme looks best with a custom icon theme. Icon themes are separate extensions from the color themes, so you have to install a second extension. Search for pkief.material-icon-theme in the Extensions view to find the most popular Material icon pack for the theme. After installing this, VS Code will prompt you to switch your icon pack.

This is the Material Theme with the Palenight color theme and the Material icon pack:

VS Code with the pale night color theme

You can change the icon theme at any time from the Command Palette by using the command Preferences: File Icon Theme and then selecting one of the icon themes from the list.

Installing a Better Programming Font

Programming fonts are a special group of typefaces, typically with fixed-width characters called monospace. There’s a long list of available fonts to browse at ProgrammingFonts.org:

Selecting a programming font

Once you’ve selected a font, go to Nerd Fonts to download it and install the font on your operating system. The downloads at Nerd Fonts are copies of the monospace fonts with support for glyphs, otherwise known as icons, which you can use inside the terminal prompt.

After installing your selected font, you need to change the editor.fontFamily setting to the name of the new font. You can do that by navigating to Code → Preferences → Settings and then selecting Text Editor → Font in the navigation dropdown. You can change the font your editor will use by adding the name of your new font in the first field of the Font Family setting.

Setting Up Your Terminal

You’ll spend much of your Python development time inside a shell terminal. You can use a separate application, like iTerm2 or Windows Terminal, but VS Code already has a powerful built-in terminal window.

Because VS Code does need a bit of configuration to make it as powerful as a dedicated terminal application, you’ll set that up now.

Changing the Default Shell Provider

You can reconfigure the terminal window to have multiple profiles. These profiles form the dropdown list when you spawn a new terminal.

VS Code allows you to configure multiple terminal profiles. You can’t edit terminal profiles in the settings UI, so you need to use the Preferences: Open Settings (JSON) command in the Command Palette to open the settings.json file. You’ll notice that key-value pairs make up the settings file. Each key represents the configuration setting for VS Code or one of its extensions.

There are three terminal profile settings, which have the following names:

Operating System Terminal Profile Settings
Windows terminal.integrated.profiles.windows
Linux terminal.integrated.profiles.linux
macOS terminal.integrated.profiles.osx

Once you type in the name, the editor autocompletes the default profiles into the JSON file.

Note that there’s no Python REPL profile in the default settings. You can add a profile with the key "python3-repl" to the integrated profiles JSON file so that VS Code makes it available as a profile option and drops you straight onto the REPL prompt:

JSON
"python3-repl": {
    "path": "python3",
    "args": ["-q"]
}

The -q flag is a Python command-line flag to stop the version header from showing. You can add any extra Python command-line flags to "args".

Once configured, your profiles should look something like this, depending on your OS:

JSON
"terminal.integrated.profiles.osx": {
    "bash": {
        "path": "bash",
        "icon": "terminal-bash",
    },
    "zsh": {
        "path": "zsh"
    },
    "pwsh": {
        "path": "pwsh",
        "icon": "terminal-powershell",
    },
    "python3-repl": {
        "path": "python3",
        "args": ["-q"]
    }
},

VS Code has two launch modes for terminals: integrated and external. Once you’ve configured the profiles, you can set the default profile for your integrated terminal by setting the value for "terminal.integrated.defaultProfile.osx":

JSON
"terminal.integrated.defaultProfile.osx": "zsh",

If something gets launched in an external terminal, it will use the default shell of your operating system. If you prefer a different terminal app, like iTerm 2 for macOS or Windows Terminal for Windows, you can change the default external terminal as well:

JSON
"terminal.external.osxExec": "iTerm.app",

With this setting for macOS, for example, you’re saying that VS Code should bring up the iTerm app every time it launches an external terminal window.

There are even more settings you can change in regards to terminals in VS Code. For example, you can make VS Code activate your virtual environment automatically when you bring up a new terminal window, and you can customize the look and feel of your terminal by adding custom prompts. You’ll explore how to do both in this tutorial.

Virtual Environment Activation in the Terminal

Virtual environments are very important for managing multiple dependencies across Python projects. Visual Studio Code will activate any Python virtual environment once the interpreter is selected. If you already have a virtual environment, run Python: Select Interpreter from the Command Palette to select the Python interpreter virtual environment.

If you don’t have one, then create one inside the terminal. VS Code can automatically pick it up if the virtual environment path is named .venv/, env/, or venv/.

After you set the interpreter, you’ll automatically activate the virtual environment when you start a new terminal window inside VS Code:

VS Code with the venv activated

If you already had a terminal open, you can destroy it by clicking the garbage can icon.

Any commands you run inside the terminal, such as python -m pip install, will be for the activated virtual environment.

In the above screenshot, you can see a custom command prompt that uses the Oh My Posh prompt toolkit. In the next section, you’ll install and configure Oh My Posh. Oh My Posh is optional, especially if you already have a custom command prompt installed.

Installing Oh My Posh

Oh My Posh is one of many libraries for customizing the command prompt of your terminal. It works across Linux, macOS, and Windows. It also works with all shells like Bash, Zsh, Fish, and PowerShell. You can install Oh My Posh to spice up your terminal.

If you’re on macOS and using Bash, run the following commands to install Oh My Posh:

Shell
$ brew tap jandedobbeleer/oh-my-posh
$ brew install oh-my-posh
$ curl https://github.com/JanDeDobbeleer/oh-my-posh/raw/main/themes/tonybaloney.omp.json -sLo ~/.mytheme.omp.json
$ echo "eval \"\$(oh-my-posh --init --shell bash --config ~/.mytheme.omp.json)\"" >> ~/.profile
$ . ~/.profile

If you’re on macOS and using Zsh, run the following commands to install Oh My Posh:

Shell
$ brew tap jandedobbeleer/oh-my-posh
$ brew install oh-my-posh
$ curl https://github.com/JanDeDobbeleer/oh-my-posh/raw/main/themes/tonybaloney.omp.json -sLo ~/.mytheme.omp.json
$ echo "eval \"\$(oh-my-posh --init --shell zsh --config ~/.mytheme.omp.json)\"" >> ~/.zprofile
$ . ~/.zprofile

If you’re on Windows and using PowerShell, run the following commands to install Oh My Posh:

Windows PowerShell
PS C:\> Install-Module oh-my-posh -Scope CurrentUser
PS C:\> Add-Content $PROFILE "`nSet-PoshPrompt -Theme tonybaloney"

Finally, if you’re on Linux and using Bash, run the following commands to install Oh My Posh:

Shell
$ sudo wget https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/posh-linux-amd64 -O /usr/local/bin/oh-my-posh
$ sudo chmod +x /usr/local/bin/oh-my-posh
$ curl https://github.com/JanDeDobbeleer/oh-my-posh/raw/main/themes/tonybaloney.omp.json -sLo ~/.mytheme.omp.json
$ echo "eval \"\$(oh-my-posh --init --shell bash --config ~/.mytheme.omp.json)\"" >> ~/.bashrc
$ . ~/.bashrc

When you open up a new terminal in VS Code, you’ll get this prompt:

VS Code Terminal with ohmyposh

The components on the terminal are the folder, Git branch, and Python version. Check out the list of themes for some other options.

By default, the terminal will use the same font face that you configured for the editor, editor.fontFamily. You can override this by defining a different font family for the terminal.integrated.fontFamily identifier. You’ll also need to update any external terminal applications you use.

Team Settings vs Personal Settings

VS Code has two levels of settings:

  1. User settings, which apply to all projects
  2. Workspace settings, which only apply to that workspace

If a setting is declared in both, the workspace setting will override the user setting.

The workspace configuration for VS Code and all of its extensions live within a .vscode/ directory in the workspace root.

It’s a good idea to put your project-agnostic settings into your user settings and your project-specific settings into .vscode/. By separating your personal user settings from your project settings, you and any other developers working on the project can be more effective.

Global User Settings for Python

By default, the Python extension for Visual Studio Code has a very basic configuration. Many features like linting, formatting, and security checks are disabled because you need to install third-party tools like Black, Pylint, and Bandit to use them.

You can install these tools and make them available to every virtual environment by using either pipx or pip install --user. pipx is preferable over pip install --user because it’ll create and maintain a virtual environment for that package, keeping your global site packages smaller and reducing the risk of packaging conflicts.

Once you’ve installed pipx, you can install the common tools:

Shell
$ pipx install pylint && \
  pipx install black && \
  pipx install poetry && \
  pipx install pipenv && \
  pipx install bandit && \
  pipx install mypy && \
  pipx install flake8

Alternatively, use python3 -m pip install --user to install the common tools:

Shell
$ python3 -m pip install --user pylint black poetry pipenv bandit mypy flake8

Once you’ve installed the base tools, open the user settings from the Command Palette with Preferences: Open Settings (JSON). Add settings for the preferences you want to apply to all projects:

JSON
 1"python.pipenvPath": "${env:HOME}/.local/bin/pipenv",
 2"python.poetryPath": "${env:HOME}/.local/bin/poetry",
 3"python.condaPath": "${env:HOME}/.local/bin/conda",
 4"python.linting.enabled": true,
 5"python.linting.banditPath": "${env:HOME}/.local/bin/bandit",
 6"python.linting.banditEnabled": true,
 7"python.linting.pylintPath": "${env:HOME}/.local/bin/pylint",
 8"python.linting.mypyPath": "${env:HOME}/.local/bin/mypy",
 9"python.linting.flake8Path": "${env:HOME}/.local/bin/flake8",
10"python.formatting.blackPath": "${env:HOME}/.local/bin/black",

With these settings, you’ve managed to accomplish a couple of things that’ll be useful for your development workflow across many projects:

  1. Lines 1 to 3 enable package discovery for projects enabled with pipenv, poetry, and conda.
  2. Line 4 enables Python linting.
  3. Lines 5 to 6 enable and set the path to bandit.
  4. Lines 7 to 10 enable Python formatting and set the path to a globally-installed instance of pylint, mypy, flake8, and black.

In each absolute path, you can automatically substitute your home folder by using the macro ${env:HOME}.

Workspace Settings

Outside of the user settings, you can use the .vscode/ directory inside the workspace to configure some project-specific settings:

  • Which commands to run to execute the project
  • How to test and debug the project
  • Which linter and formatter to use and any project-specific parameters

The following files hold the VS Code preferences:

File Purpose
settings.json VS Code settings
launch.json Profiles to execute your project from the Run and Debug menu
tasks.json Any additional tasks to execute, such as build steps

Most of VS Code’s settings, as well as the settings for your extensions, are in these three files.

In the workspace preferences, the following predefined variables are supported:

Predefined Variable Meaning
${env.VARIABLE} Any environment variable
${workspaceFolder} The path of the folder opened in VS Code
${workspaceFolderBasename} The name of the folder opened in VS Code without any slashes (/)
${file} The currently opened file
${fileWorkspaceFolder} The currently opened file’s workspace folder
${relativeFile} The currently opened file relative to workspaceFolder
${cwd} The task runner’s current working directory on startup
${execPath} The path to the running VS Code executable
${pathSeparator} The character used by the operating system to separate components in file paths, for example, forward slash (/) or backslash (\)

Using these variables will keep the project settings agnostic to the environment, so you can commit them into Git.

As an example of working with these settings, if you want to use Black as the default code formatter for this project, you can create the file .vscode/settings.json with this configuration:

JSON
{
    "python.formatting.provider": "black",
}

Anyone who checks out this project will now automatically use Black as the formatter for Python files. You’ll see how this setting influences the autoformatting options in the section about setting format and lint on save.

Using the Settings Sync Extension

If you use VS Code across multiple computers, you can enable the automatic synchronization of Settings, Keyboard Shortcuts, User Snippets, Extensions, and UI State. If you haven’t used Settings Sync before, you’ll need to enable it:

  1. Run Settings Sync: Turn On in your Command Palette.
  2. Follow the setup steps as prompted by VS Code. You can authenticate with GitHub.
  3. Once the setup is done, run Settings Sync: Configure from the Command Palette.
  4. Select what you want to sync.

Once Settings Sync is configured on all the computers you have VS Code installed on, you can see the state for each synced setting by running Settings Sync: Show Synced Data from the Command Palette, where they’ll show up under Synced Machines:

VS Code Settings Sync Data

This view shows you the last synced time for each of the settings and which machines are in sync.

Linting and Formatting

All languages in Visual Studio Code can be formatted using one of the automated formatters, and the Python extension also supports linters. Linters and formatters perform different tasks:

  • A formatter will change how your code looks but not how it works.
  • A linter will warn you about your code’s compliance to standards on style, type adherence, security, and a range of best practices.

The Python extension supports many third-party linters, and they often perform different jobs. For example, Bandit is a linter for security bugs and Flake8 is a linter for style guide compliance.

The Python extension also comes with language server tooling, which performs analysis by loading the interfaces—methods, functions, classes—from your code and the libraries you use.

At the time of writing this tutorial, the latest and greatest language server extension for Python on Visual Studio Code is Pylance.

Setting Up Pylance

Pylance is an extension that works alongside Python in Visual Studio Code to provide deeper language support and introspection of Python code. Pylance will provide auto-completions, automated module imports, better code navigation, type checking, and tons more.

To get Pylance, go to the Extensions menu on the side bar and search Pylance (ms-python.vscode-pylance).

Once you have Pylance installed, there are two default configuration settings you may want to change in your user settings to get the most out of the extension.

The first setting to change is the type checking mode, which you can use to specify the level of type checking analysis performed:

JSON
"python.analysis.typeCheckingMode": "basic"

By default, the type checking mode is set to "off".

The other options are "basic" or "strict". With "basic", rules unrelated to type checking and rules for basic type checking are run. If the mode is set to "strict", it will run all type checking rules at the highest severity of error. Set this to "basic" for a balance between strict and disabled.

The other default setting is python.analysis.diagnosticMode. By default, Pylance will inspect currently open files only. Changing this setting to workspace will inspect all Python files in the workspace, giving you a list of errors and warnings inside the Explorer view:

VS Code Workspace inspections

You should only set python.analysis.diagnosticMode to "workspace" if you have some RAM to spare as it will consume more resources.

Pylance is most effective when it has information about the types used as the arguments to methods and functions as well as the return types.

For external libraries, Pylance will use typeshed to infer the return types and argument types. Pylance also comes with type stubs and intelligence for some of the most popular data-science libraries, like pandas, Matplotlib, scikit-learn, and NumPy. If you’re working with pandas, Pylance will give you information and examples for common functions and patterns:

Pylance with Pandas

For libraries that don’t have type stubs on typeshed, Pylance will do its best to guess what the types are. Otherwise, you can add your own type stubs.

Setting Format and Lint on Save

Format Document is an action that applies formatting to any document in VS Code. For the Python extension, this action executes "python.formatting.provider", which can be set to any of the supported auto-formatters: "autopep8", "black", or "yapf".

Once you have configured the formatter in settings.json, you can set the formatter to run automatically whenever a file is saved. In the VS Code config, you can configure editor settings to only apply to certain file types by putting them in a "[<file_type>]" group:

JSON
...
"[python]": {
    "editor.formatOnSave": true,
},

Along with the execution of the formatter, you can also have the import statements organized both alphabetically and by splitting standard library modules, external modules, and package imports into groups with the following configuration:

JSON
"[python]": {
    ...
    "editor.codeActionsOnSave": {"source.organizeImports": true},
},

Unlike formatting, linting is specific to the Python extension. To enable linting, choose a linter by running Python: Select Linter on the Command Palette. You can also enable one or more linters in your settings. For example, to enable the Bandit and Pylint linters, edit your settings.json:

JSON
...
"python.linting.enabled": true,
"python.linting.banditEnabled": true,
"python.linting.pylintEnabled": true,

To run the enabled linters whenever a file is saved, add the following setting to settings.json:

JSON
...
"python.linting.lintOnSave": true,

You might find it helpful to have more than one linter enabled. Keep in mind that Pylance already provides many of the insights you would get from pylint, so you likely don’t need to enable both pylint and Pylance. In contrast, Flake8 provides stylistic feedback that Pylance doesn’t cover, so you can use those two together.

Testing Your Python Code in Visual Studio Code

Python offers plenty of tools to test your code. The Python extension for VS Code supports the most popular test frameworks, unittest and pytest.

Configuring Test Integration

To enable testing support for Python, run the Python: Configure Tests command from the Command Palette. VS Code will prompt you to select from one of the supported test frameworks and to specify which folder contains your tests.

This wizard adds the configuration options to .vscode/settings.json:

JSON
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": [
    "tests"
],

You can edit python.testing.<framework>Args with your preferred test framework to add any additional command-line flags. The example above shows configuration options for pytest.

If you have more complex settings for pytest, put those in pytest.ini instead of the VS Code settings. That way, you’ll keep the configuration consistent with any automated testing or CI/CD tooling.

Executing Tests

Once you’ve configured the test framework and arguments for the test runner, you can execute your tests by running the Python: Run All Tests command from the Command Palette. This will start the test runner with the configured arguments and put the test output into the Python Test Log output panel:

VS Code executing tests

Once test discovery has completed, each test case will have an inline option to execute or debug that case:

VS Code run test inline

Failed tests will be marked as having an error. You can see the failure from the test runner in both the Python Test Log panel and by hovering over the failed test case in your code:

VS Code test failure

If you’re running tests often, you can improve your testing experience in VS Code with the testing explorer.

To enable the testing panel, right-click the side bar and make sure that Testing is checked. The testing panel shows all the tests that the Python extension discovered and provides you with many features:

VS Code Test Explorer UI

You have a visual representation of the test suite grouping and which tests failed. You also have menu buttons that let you run and debug tests.

VS Code’s test system is powerful, but a lot of the functionality is disabled by default to keep it a lightweight editor. Beyond testing, there are other tasks you might want to run regularly from inside VS Code. This is where the tasks system comes in.

Using the Visual Studio Code Tasks System

Visual Studio Code supports compiled languages like Go, Rust, and C++, as well as interpreted languages like Python and Ruby. VS Code has a flexible system for executing configured tasks that the user defines, like building and compiling the code.

Python code doesn’t normally need to be compiled ahead of time because the Python interpreter does this for you. Instead, you can use the tasks system to have pre-configured tasks that you would otherwise run at the command line, such as:

  • Building a wheel or source distribution
  • Running tasks in frameworks like Django
  • Compiling Python C extensions

VS Code tasks are commands or executables that you can run on demand using the Command Palette. There are two built-in default tasks:

  1. The build task
  2. The test task

Note that you can use tasks for anything that you might otherwise execute over the command line. You’re not restricted to build and test activities.

Using Tasks to Compile Wheels

If you have a setup.py file to build a package for distribution on PyPI, you can use the tasks system to automate building the source (Python) and binary (compiled Python) distribution packages.

Tasks are defined in a .vscode/tasks.json file. To try it out, create .vscode/tasks.json and copy this configuration:

JSON
 1{
 2  "version": "2.0.0",
 3  "tasks": [
 4    {
 5      "type": "shell",
 6      "command": "${command:python.interpreterPath}",
 7      "args": ["setup.py", "bdist_wheel", "sdist"],
 8      "isBackground": true,
 9      "options": {"cwd": "${workspaceFolder}"},
10      "label": "Build Wheel",
11      "group": {
12        "kind": "build",
13        "isDefault": true
14      }
15    }
16  ]
17}

There are a few things to note in this example, so you’ll look at the most important configurations line by line:

  • Line 5: The task type is shell, which specifies that this should run under your configured shell.
  • Line 6: The command is ${command:python.interpreterPath}, which is a built-in variable of the Python interpreter for this environment. That includes any activated virtual environment.
  • Line 9: The option "options": {"cwd": "${workspaceFolder}"} specifies that this should run at the root of the project. You can change this to a subfolder if you need to.
  • Lines 11 to 13: The "group" is set as "build", and this task will be your default task because you set "isDefault" to true. This means that this task will run as the default build task.

To execute the default build task, you can run Tasks: Run Build Task from the Command Palette or use the built-in keyboard shortcut, Cmd+F9 or Ctrl+F9. Under the Terminal tab, you can find the output of the build command called whatever you specified in "label":

VS Code Build Output

You’re not limited to build scripts. The task system is a great solution to Django and Flask’s management commands.

Using Tasks for Django

Are you working with a Django application, and do you want to automate running manage.py from the command line? You can create a task using the shell type. That way, you can execute manage.py with the Django sub-command you wish to run, along with any arguments:

JSON
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "command": "${command:python.interpreterPath}",
      "args": ["manage.py", "makemigrations"],
      "isBackground": true,
      "options": {"cwd": "${workspaceFolder}"},
      "label": "Make Migrations"
    }
  ]
}

To run this task, use the Tasks: Run Task command in the Command Palette and choose the Make Migrations task from the list.

You can copy this snippet and paste it for any Django commands you run on a regular basis, like collectstatic.

Chaining Tasks

If you have multiple tasks that should run in sequence or a task that depends on another task, you can configure task dependencies in tasks.json.

Expanding on the setup.py example, if you want to first build a source distribution of your package, you can add the following task to tasks.json:

JSON
...
{
  "type": "shell",
  "command": "${command:python.interpreterPath}",
  "args": ["setup.py", "sdist"],
  "isBackground": true,
  "options": {"cwd": "${workspaceFolder}"},
  "label": "Build Source",
}

Within the default build task, you can then add a property dependsOn along with a list of the task labels that need to run first:

JSON
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "command": "${command:python.interpreterPath}",
      "args": ["setup.py", "bdist_wheel"],
      "isBackground": true,
      "options": {"cwd": "${workspaceFolder}"},
      "label": "Build Wheel",
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "dependsOn": ["Build Source"]
    }
  ]
}

The next time you run this task, it will run all dependent tasks first.

If you have multiple tasks that this task depends on and they can be run in parallel, add "dependsOrder": "parallel" to the task configuration.

Using Tasks to Run Tox

Now you’ll explore tox, which is a tool that aims to automate and standardize testing in Python. The Python extension for Visual Studio Code doesn’t come with tox integration. Instead, you can use the tasks system to set tox as the default test task.

To automate running tox with your tox configuration, add the following task to tasks.json:

JSON
{
  "type": "shell",
  "command": "tox",
  "args": [],
  "isBackground": false,
  "options": {"cwd": "${workspaceFolder}"},
  "label": "Run tox",
  "group": {
      "kind": "test",
      "isDefault": true
  }
}

You can run this task using Tasks: Run Test Task from the Command Palette, and the task will execute tox with the output within the Terminal tab:

VS Code running Tox

If you have a few tasks and need to run them often, it’s time to explore a great extension that adds some shortcuts in the UI for running configured tasks.

Using the Task Explorer Extension

The Task Explorer extension (spmeesseman.vscode-taskexplorer) adds simple UI controls to run your pre-configured tasks. Once installed, Task Explorer will be a panel within the Explorer view. It scans your project to auto-discover tasks for npm, make, gulp, and many other build tools. You can find your tasks under the vscode group:

VS Code Task Explorer

Click the arrow next to any task to execute it, and click the refresh icon at the top if you change your task’s configuration.

Debugging Your Python Scripts in Visual Studio Code

The Python extension for Visual Studio Code comes bundled with a powerful debugger that supports local and remote debugging.

The simplest way to run and debug a simple Python script is going to the Run → Start Debugging menu and choosing Python File from the selection. This will execute the current file using the configured Python interpreter.

You can set breakpoints anywhere in the code by clicking in the gutter to the left of the line number. When breakpoints are hit as the code executes, the code will pause and wait for instruction:

VS Code at breakpoint

The debugger adds a menu of controls: Continue, Step Over, Step Into, Step Out, Restart, and Stop Execution:

VS Code Debug Controls

On the left panel, you can perform common debugging actions, such as exploring local and global variables and Python’s call stack. You can also set watches, which you’ll learn more about in the next section.

Setting Watches

Watches are expressions that persist between debugging sessions. When you stop execution and start debugging again, you’ll keep any watches from your last session.

You can add a variable to the Watch panel from the Variables panel by right-clicking a variable and selecting Add to Watch.

You can also add any Python expression to the Watch list by clicking the + icon. Expressions can contain:

  • Small Python expressions, such as x == 3
  • Function calls, such as var.upper()
  • Comparisons

You’ll get the current result of each expression in real time whenever a breakpoint is hit. VS Code will also update the value of each watch while you step through your debugging session:

VS Code Watches Panel

You can expand complex types like dictionaries and objects using the arrow on the left.

So far, you’ve seen the debugger for a single Python file, but many Python applications are modules or require special commands to start.

Configuring a Launch File

VS Code has a configuration file for launch profiles, .vscode/launch.json. The Python debugger for VS Code can start any launch configuration and attach the debugger to it.

For an example of working with launch profiles in VS Code, you’ll explore how to use the ASGI server uvicorn to start a FastAPI application. Normally, you might just use the command line:

Shell
$ python -m uvicorn example_app.main:app

Instead, you could set up an equivalent launch configuration in launch.json:

JSON
{
  "configurations": [
    {
      "name": "Python: FastAPI",
      "type": "python",
      "request": "launch",
      "module": "uvicorn",
      "cwd": "${workspaceFolder}",
      "args": [
          "example_app.main:app"
      ],
    }
  ]
}

Here, you set "type" in the configuration to "python", which tells VS Code to use the Python debugger. You also set "module" to specify the Python module to run, which in this case is "uvicorn". You can provide any number of arguments under "args". If your application requires environment variables, you can also set those using the env parameter.

Once you’ve added this configuration, you should find your new launch configuration ready to start under the Run and Debug panel:

VS Code Launch Selection

Whatever you configured as the first launch configuration will run when you press F5 or select Run → Start Debugging from the top menu.

If VS Code doesn’t automatically select the right Python environment for you, then you can also declare an explicit path to the appropriate Python interpreter as an option in your .vscode/launch.json file:

JSON
 1{
 2  "configurations": [
 3    {
 4      "name": "Python: FastAPI",
 5      "type": "python",
 6      "python": "${workspaceFolder}/venv/bin/python",
 7      "request": "launch",
 8      "module": "uvicorn",
 9      "cwd": "${workspaceFolder}",
10      "args": [
11          "example_app.main:app"
12      ],
13    }
14  ]
15}

You can add the path to your Python interpreter as a new entry with the name "python". In this example, the interpreter is located in a Python virtual environment named venv that you created at the root of your workspace folder. If there’s a different Python interpreter you’d like to use, you can define the path to it by editing the path shown in line 6 to fit your setup.

Mastering Remote Development

VS Code supports three remote development profiles:

  1. Containers
  2. Remote Hosts over SSH
  3. Windows Subsystem for Linux (WSL)

All three options are provided by the Remote Development extension pack (ms-vscode-remote.vscode-remote-extensionpack). You need to install this extension pack for the remote debugging features to display in VS Code.

Remote Development With Containers

You need to install the Docker runtime on your machine to use remote debugging for containers. If you don’t already have Docker installed, you can download it from the Docker website.

Once Docker is running, go to the Remote Explorer tab on the left navigation menu. Change the Remote Explorer dropdown to Containers, and you’ll see a view with panels:

VS Code Remote Container Window

These panels aren’t populated if you have a fresh Docker install.

If you already have Docker images installed and running, the three panels might be populated:

  1. Containers: A navigation panel to show the development containers within this workspace or links to some quick-start steps
  2. The name of your container (if running): The attributes and volume mounts of the running container
  3. DevVolumes: A list of dev volumes you can edit and mount to modify code

For example, if you installed the Try Out Development Container: Python by following the steps outlined in VS Code’s containers tutorial, your VS Code Remote Explorer tab will show the name of the running container across the panels mentioned earlier:

The Remote Explorer panel in VS Code showing a running development container

Use these panels as a quick way of managing any Docker containers that your project depends on.

In general, there are three primary ways of running the Remote Containers extension:

  1. Attach to an existing running container to make quick changes
  2. Create a .devcontainer/devcontainer.json file and open the workspace as a remote container
  3. Run the Remote-Containers: Reopen in Container command and select the Python 3 image

Creating a .devcontainer/devcontainer.json file has significant benefits over simply opening a container:

  • Dev containers support GitHub Codespaces
  • Dev containers support the launch profiles and task configurations shown in this tutorial

If you’re planning on working within containers and VS Code a lot, spending the extra time to create a development container will pay off.

A quick way to get started using a dev container is by creating it from your current workspace:

  1. Run the Remote-Containers: Reopen in Container command from the Command Palette.
  2. Select Python 3 and then select the required version of Python.
  3. Accept the default suggested version of Node.js.

VS Code will then port your existing workspace and create a .devcontainer/devcontainer.json configuration based upon a generic Dockerfile for Python.

Dev containers have two required files:

  1. .devcontainer/devcontainer.json, which specifies all the VS Code requirements, such as which extensions are needed and what settings to use
  2. Dockerfile, which specifies what commands will build the environment

In the default setup, Dockerfile is inside the .devcontainer/ directory. If your project already has a Dockerfile, you can reuse that by changing the path in .devcontainer/devcontainer.json.

You’ll use the defaults inside .devcontainer/devcontainer.json to specify:

  • The path to a Dockerfile
  • A name for the container
  • The VS Code settings to apply
  • Any required VS Code extensions to install
  • Any post-create commands you want to run, like python -m pip install <package>, for example

If your application requires additional packages from PyPI, change .devcontainer/devcontainer.json and uncomment the line specifying "postCreateCommand":

JSON
{
  ...
  // Use 'postCreateCommand' to run commands after the Container is created.
  "postCreateCommand": "python3 -m pip install -r requirements.txt",
}

You can also add options for port forwarding if you’re developing an application that provides network services, like a web app. For the full list of options, you can go through the devcontainer.json reference.

After making changes to either the Dockerfile or the devcontainer specification, rebuild the container from the Remote Explorer by right-clicking the running container and selecting Rebuild Container:

VS Code Rebuild Container

By doing this, you’ll rebuild the Docker container with any changes to the configuration and Dockerfile.

Beyond the functionality of the Remote Development extension pack’s extension for remote debugging, there’s a Docker extension for VS Code. You’ll cover this extension at the end of the tutorial and find even more features.

Remote Development With SSH

By running Remote-SSH: Open SSH Configuration File in the Command Palette, you can open up the local SSH configuration file. This is a standard SSH config file for you to list hosts, ports, and paths to private keys. The IdentityFile option defaults to ~/.ssh/id_rsa, so the best way to authenticate is a private and public key pair.

Here’s an example configuration of two hosts:

Configuration File
Host 192.168.86.30
  HostName 192.168.86.30
  User development
  IdentityFile ~/path/to/rsa

Host Test-Box
  HostName localhost
  User vagrant
  Port 2222

Once you save the configuration file, the Remote Explorer tab will list those SSH hosts under the SSH Targets dropdown option:

VS Code SSH Targets

To connect to that server, click on Connect to Host in New Window, which is the icon to the right of any host. This will open a new VS Code window with the remote host.

Once connected, click Open Folder under the Explorer view. VS Code will show you a special folder navigation menu that displays the available folders on the remote host. Navigate to the folder where your code is located, and you can start a new workspace under that directory:

VS Code remote navigation

In this remote workspace, you can edit and save any files live on the remote server. The Terminal tab is automatically set as the SSH terminal for the remote host if you need to run any additional commands.

Remote Development With WSL

Windows Subsystem for Linux, or WSL, is a component for Microsoft Windows that enables users to run any number of Linux distros on their Windows OS without the need for a separate hypervisor.

VS Code supports WSL as a remote target, so you can run VS Code for Windows and develop for Linux under WSL.

Using WSL with VS Code first requires that WSL is installed. Once WSL is installed, you need to have at least one distro available.

The easiest way to install WSL on the latest version of Windows 10 is to open a command prompt and run:

Windows Command Prompt
C:\> wsl --install

The --install command performs the following actions:

  • Enables the optional WSL and Virtual Machine Platform components
  • Downloads and installs the latest Linux Kernel
  • Sets WSL 2 as the default
  • Downloads and installs a Linux distribution, possibly requiring a reboot of your machine

Once you’ve successfully set up WSL on your computer, you also need to install the Remote - WSL (ms-vscode-remote.remote-wsl) extension for VS Code. After that, you’re ready to use WSL in Visual Studio Code.

If you already have code in WSL, run Remote-WSL: Open Folder in WSL from the Command Palette in VS Code. Select the target directory for your code in the Linux subsystem.

If your code was checked out in Windows, run Remote-WSL: Reopen Folder in WSL from the Command Palette.

The Remote Explorer will remember your configured WSL targets and let you reopen them quickly from the WSL Targets dropdown in the Remote Explorer view:

VS Code with WSL

If you want a reproducible environment, consider creating a Dockerfile instead of working directly on the WSL host.

Working With Data Science Tools

VS Code is great for working on Python for application development and web development. It also has a powerful set of extensions and tools for working with data science projects.

So far, you’ve mostly covered the Python extension for VS Code. There’s also the Jupyter Notebooks extension, which integrates the IPython kernel and a notebook editor into VS Code.

Installing the Jupyter Notebook Extension

To get started with Jupyter Notebooks on VS Code, you’ll need the Jupyter Extension (ms-toolsai.jupyter).

Jupyter Notebooks supports pip as the package manager, as well as conda from the Anaconda distribution.

Data science libraries for Python often require compiled modules written in C and C++. You should use conda as the package manager if you’re using a lot of third-party packages because the Anaconda distribution has resolved the build dependencies on your behalf, making it easier to install packages.

Getting Started With Jupyter Notebooks in VS Code

For this example, you’ll open a series of Jupyter Notebooks on wave transformations. Download the repo’s .zip/ folder and unzip it, or clone the GitHub repo and open it with VS Code. The steps described further down will also work with any other workspace containing .ipynb notebook files.

In VS Code, you can use any existing conda environment. Instead of installing packages into the base environment, you can create a conda environment specifically for VS Code from your terminal:

Shell
$ conda create --name vscode python=3.8

After you’ve created the conda environment named vscode, you can install some common dependencies into it:

Shell
$ conda install -n vscode -y numpy scipy pandas matplotlib ipython ipykernel ipympl

Once you’ve installed the dependencies, run the Python: Select Interpreter command from the VS Code Command Palette and search for vscode to select the new conda environment:

VS Code select interpreter

This selection will set your VS Code to use the Python interpreter from your conda environment, vscode.

Once selected, open a notebook in VS Code and click the Select Kernel button on the right or run the Notebook: Select Notebook Kernel command from the Command Palette. Type vscode to select the newly created conda environment with the dependencies installed:

VS Code Select Kernel

Selecting your new conda environment as the kernel for your notebook will give your notebook access to all the dependencies that you installed in that environment. It’s necessary for executing the code cells.

Once the kernel is selected, you can run any or all of the cells and see the output of the operations displayed right inside VS Code:

VS Code Jupyter

Once the notebook has executed, the Jupyter Extension will make any of the intermediate variables such as lists, NumPy arrays, and pandas DataFrames available in the Jupyter: Variables view:

VS Code Variable View

You can bring this view into focus by clicking the Variables button at the top of the notebook or by running the Jupyter: Focus on Variables View command.

For the more complex variables, choose the icon to open the data in the data viewer.

Using the Data Viewer

The Jupyter Extension comes with a data viewer designed for viewing and filtering 2D arrays, such as lists, NumPy’s ndarray, and pandas DataFrames:

VS Code Data Viewer

To access the data viewer, you can expand complex variables inside the variables view by clicking on Show variable in data viewer. This option is represented by an icon shown on the left of a row that represents a complex variable:

Symbol for showing the data viewer for more complex variables in the Jupyter variables view

The data viewer supports inline filtering and paging for large data sets. If you’re plotting large data sets in Matplotlib, the Jupyter Extension supports Matplotlib widgets instead of SVG rendering.

Using the Rainbow CSV Extension

If you work with CSV or TSV input data, there’s a useful extension called Rainbow CSV (mechatroner.rainbow-csv) that enables you to open and visualize CSV files in VS Code:

VS Code Rainbow CSV

Each column is colorized, giving you a quick way to spot missing commas. You can also align all columns by running the Rainbow CSV: Align CSV Columns command from the Command Palette.

The Rainbow CSV extension also comes with a Rainbow Query Language (RBQL) query tool that lets you write RBQL queries on the CSV data to create filtered data sets:

VS Code Rainbow RBQL

You can access the RBQL console by running Rainbow CSV: RBQL in the Command Palette. After executing a query, you’ll see the results in a new tab as a temporary CSV file that you can save and use for further data analysis work.

Throughout this tutorial, you’ve installed a couple of useful extensions for VS Code. There are a lot of useful extensions available. In the final section of this tutorial, you’ll learn about some extra extensions you haven’t covered so far that you might also want to try out.

Adding Bonus Extensions to Visual Studio Code

The VS Code Marketplace has thousands of extensions. The selection of extensions covers anything from language support, themes, spell checkers, and even mini-games.

In this tutorial so far, you’ve covered a number of extensions that make Python development in Visual Studio Code more powerful. These last four extensions are optional—but could make your life easier.

Code Spell Checker

Code Spell Checker (streetsidesoftware.code-spell-checker) is a spell checker that inspects variable names, text inside strings, and Python docstrings:

VS Code Spelling Extension

The Code Spell Checker extension will highlight any suspected misspellings. You can either correct the spelling from the dictionary or add the word to a user or workspace dictionary.

The workspace dictionary will live inside the workspace folder, so you can check it into Git. The user dictionary is persisted across all your projects. If there are lots of keywords and phrases you use often, you can add them to the user dictionary.

Docker

The Docker extension (ms-azuretools.vscode-docker) makes it easy to create, manage, and debug containerized applications:

VS Code docker extension

The Docker extension goes beyond the Remote - Containers extension that you covered earlier. It gives you a UI to manage images, networks, container registries, volumes, and containers.

Thunder Client

Thunder Client (rangav.vscode-thunder-client) is an HTTP client and UI for VS Code designed to aid testing of REST APIs. If you’re developing and testing APIs in frameworks like Flask, FastAPI, or Django Rest Framework, you may already use a tool like Postman or curl to test your application.

Inside Thunder Client, you can create HTTP requests and send them to your API, manipulate headers, and set payloads of text, XML, and JSON:

VS Code Thunder Client

Thunder Client is a great alternative to Postman or curl, and since you can use it right inside of VS Code, you can avoid switching between applications when testing and developing your REST APIs.

VS Code Pets

VS Code Pets (tonybaloney.vscode-pets) is a fun extension that puts one or many small pets in your VS Code window:

VS Code pets

You can customize the pets, customize their environments, and play games with them.

This is just a snapshot of the extensions on the marketplace. There are thousands more to discover for additional language support, UI improvements, or even Spotify Integration.

Conclusion

Visual Studio Code’s Python tooling is evolving rapidly, and the team is putting out updates with bug fixes and new features monthly. Make sure you install any new updates to keep your environment on the latest and greatest.

In this tutorial, you’ve seen an overview of some of the more advanced features in Visual Studio Code, the Python and Jupyter extensions, as well as some bonus extensions.

You learned how to:

  • Customize your user interface with slick UI customizations and keyboard bindings
  • Run and monitor Python tests by integrating your test framework into Visual Studio Code
  • Lint and format code with Pylance and external linters
  • Debug local and remote environments over SSH and Docker
  • Spin up data science tools to work with Jupyter Notebooks

You can use this knowledge to put yourself on track to be a VS Code power user.

Play around with some of these extensions and test them out as you work on your next project. You’ll find that some VS Code features will be more useful for you than others. Once you get a feel for some of the customizations and extensions, you’ll likely find yourself in the VS Code docs looking for more or even coding your own extensions!

🐍 Python Tricks 💌

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

About Anthony Shaw

Anthony is an avid Pythonista and writes for Real Python. Anthony is a Fellow of the Python Software Foundation and member of the Open-Source Apache Foundation.

» More about Anthony

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Master Real-World Python Skills With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

Master Real-World Python Skills
With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

What Do You Think?

Rate this article:

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal.


Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session. Happy Pythoning!