Stefan Rickli
Stefan's Journey

Stefan's Journey

VS Code: Run currently opened Python script as a module

Stefan Rickli's photo
Stefan Rickli
·Aug 5, 2022·

3 min read

Table of contents

  • Setup
  • Running scripts directly
  • Running specific scripts using -m
  • Running open scripts of root folder using -m
  • Running any open script using -m

TLDR;

I'm lazy and want to start all open Python scripts by hitting F5 and expect absolute and relative imports to work fine, no matter where the script resides within the folder structure.

Skip to the end to access a ready-made launch.json configuration.

Setup

Imagine your VS Code workspace looks as follows:

.
│   foo.py
│   bar.py
│
└───folder
│   │   baz.py
│   
└───utils
    │   handy_module.py

Additionally, bar.py as well as baz.py both reference handy_module.py with an import such as import utils.handy_module.

Running scripts directly

Running foo.py as well as bar.py directly as a script works just fine, but running baz.py using the command line python folder/baz.py ends up with the error "ModuleNotFoundError: No module named 'utils'". I'm no expert in the exact mechanics of how packages work (see this SO article as well as this RealPython article for a start), but the gist is that we would need to run baz.py with the -m switch, such as python -m folder.baz.

Running specific scripts using -m

Although VS Code gives you the option to run a script as a module, using the -m option, the launch.json configuration generally expects a specific module name.

One entry would usually look like this:

{
    "name": "Python: Launch baz.py as module",
    "type": "python",
    "request": "launch",
    "module": "folder.baz",
    "justMyCode": true
}

This is fine as long as you don't want to run a lot of different files. Then the debug configuration menu gets clogged very quickly, and as a lazy user, I just want to be able to hit F5 with any open script and expect it to work. Also, referring to the scripts explicitly makes it harder to rename them later, as I would have to edit launch.json each time. So this is no bueno for larger projects.

Running open scripts of root folder using -m

If the scripts that you want to run reside in the root folder of the current workspace (as is the case for foo.py and bar.py), then you could make them run dynamically by replacing foo with ${fileBasenameNoExtension} as per VS Code's variables documentation.

{
    "name": "Python: Launch open file as module (works in root folder)",
    "type": "python",
    "request": "launch",
    "module": "${fileBasenameNoExtension}",
    "justMyCode": true
}

But, if your scripts reside in a subfolder of your workspace (as is the case for folder/baz.py), then the built-in variables of VS Code don't allow you to build a syntactically correct module path, effectively replacing all path separators with dots.

Running any open script using -m

You can overcome this by using the enhanced variables of the VS Code extension "Command Variable". Installing it from the extensions marketplace gives you access to the variable ${command:extension.commandvariable.file.relativeDirDots}. This finally gives you the following launch.json configuration:

{
    // This one needs the VS Code Extension "Command Variable"
    "name": "Python: Launch as Module",
    "type": "python",
    "request": "launch",
    "module": "${command:extension.commandvariable.file.relativeDirDots}.${fileBasenameNoExtension}",
    "justMyCode": true
}

Hooray! I can now finally run all open scripts directly by hitting F5, and the absolute/relative imports work as well.

 
Share this