5

I have the following directory structure for my python practice project:

.
├── data
├── ds-and-algo
├── exercises
|   ├── __init__.py
│   ├── armstrong_number.py
│   ├── extract_digits.py
├── output

The extract_digits.py looks something like this:

def extract_digits(n):
    pass

In the armstrong_number.py I have the following:

from .extract_digits import extract_digits

From root project directory if I run

python exercises/armstrong_number.py

I get ModuleNotFoundError: no module named exercises

Running the following commad with -m flag resolves the error:

python -m exercises.armstrong_number

However using VSCode in order to debug the file, I have the following debug config launch.json:

{
"version": "0.2.0",
    "configurations": [
        {
            "name": "Python Module",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "pythonPath": "${config:python.pythonPath}",
            "module": "exercises.${fileBasenameNoExtension}",
            "cwd": "${workspaceRoot}",
            "env": {"PYTHONPATH":"${workspaceRoot}"}
        }
    ]
}

However this has a few problems:

1) For a different folder, for e.g. ds-and-algo, I have to manually edit the module entry in the launch.json file debug configuration to

"module" : "ds-and-algo.${fileBaseNameNoExtension}"

In case I have nested folder configuration like:

exercises
├── tough
|   | __init__.py
|   ├──ex1.py
|   ├──ex2.py
├── easy

I again have to manually edit the debug config in launch.json file to: (considering the case for the sub-folder tough)

"module": "exercises.tough.${fileBaseNameNoExtension}"

I need to implement a general case where depending on the file being debugged, the "module" entry in the launch.json file should be:

"module": "folder1.folder2.folder3.....foldern.script"

Just like fileBaseNameNoExtension, VSCode has some other predefined variables:

One of the variables is relativeFile, which is the path of the current opened file relative to workspaceFolder So for the file ex1.py, the variable relativeFile will be exercises/tough/ex1.py.

I need to manipulate this string and convert this to exercises.tough.ex1, which is trivial if I can write and execute bash command inside the "module" entry in launch.json file. But I am unable to do that. However, the link predefined variables in VSCode has a section on Command variables, which states:

if the predefined variables from above are not sufficient, you can use any VS Code command as a variable through the ${command:commandID} syntax.

This link has a bunch of other information that may be helpful. I am no expert in python, and definitely don't know any javascript, if that is what is required to solve this problem.

3 Answers 3

6

I can't reproduce your error: ModuleNotFoundError: no module named exercises.

Using the following files

exercises/extract_digits.py

def extract_digits(n):
  return 10

exercises/armstrong_number.py

from extract_digits import extract_digits

def armstrong_number(n):
  return extract_digits(n)

if __name__ == "__main__": 
  print armstrong_number(3)

If you use Python3 change the print statement to: print(armstrong_number(3)) and change the used Python interpreter.

If your current directory is the project root directory and you run

python exercises/armstrong_number.py

You get the number 10 in the console


In Visual Studio Code you use the wrong Launch configuration.

You are just running python programs so you should use the Python: Current File configuration. launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python: Current File",
      "type": "python",
      "request": "launch",
      "program": "${file}",
      "console": "integratedTerminal",
    }
  ]
}
  1. Open the example py file you want to run/debug, in whatever directory it is.
  2. Or make it the current file
  3. Select the Debug Side Bar
  4. Select the Python: Current File configuration
  5. Click the "green" triangle.

Now a complicated command is constructed and run. It will set the CWD to the directory of the current file and start the debugger on the current file.


If you really need the module launch you can use a Multi-Root Workspace in VSC and have a separate configured launch.json for each of the root directories


If you want to use the ${command:commandID} syntax you can construct a simple extension that uses the activeTextEditor and construct a string based on the file name
Edit

Another option is to use Multiple Launch configurations.

I have removed the properties where the default value works or that are not used.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Exercise",
      "type": "python",
      "request": "launch",
      "console": "integratedTerminal",
      "module": "exercises.${fileBasenameNoExtension}",
    },
    {
      "name": "Exercise.Easy",
      "type": "python",
      "request": "launch",
      "console": "integratedTerminal",
      "module": "exercises.easy.${fileBasenameNoExtension}",
    },
    {
      "name": "DS",
      "type": "python",
      "request": "launch",
      "console": "integratedTerminal",
      "module": "ds.${fileBasenameNoExtension}",
    }
  ]
}


You can use the extension Command Variable to get this relative directory with dot separator.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python: Module CmdVar",
      "type": "python",
      "request": "launch",
      "console": "integratedTerminal",
      "module": "${command:extension.commandvariable.file.relativeDirDots}.${fileBasenameNoExtension}",
    }
  ]
}
Sign up to request clarification or add additional context in comments.

3 Comments

My armstrong_number.py has a dot (.) before the import module like this:python from .extract_digits import extract_digits , So, python exercises/armstrong_number.py,gives the following error: ``` ModuleNotFoundError: No module named 'main.extract_digits'; 'main' is not a package I don't want them to act like indiv scripts but a module part of a single project workspace. I do use the Current file config, but that's for one-off scripts. Not inside a project.activeTextEditor``` and ${command:commandID} seem like what I really need. But I am not really sure how.
@AbhishekBhatia Another option is: Multiple Launch configurations. See my edit
This really works! Thanks! I think this is a really new extension, since I had to update vscode from 1.36 to 1.37, to be able to install this.
0

I'm not sure about running bash scripts, although if it's possible to run JavaScript in the file, "ds-and-algo.(${fileBaseNameNoExtension}).split('/').join('.')" should do the trick.

Actually, the reason you need the -m flag at all is because you don't have __init__.py files in your folders. These files may be empty, but they're used by python to identify a module structure and thus allow nested and relative imports. I hope adding those files should allow you to just run python exercises/armstrong_number.py or python ds-and-algo/tough/ex1.py

1 Comment

I already have __init__.py file in the folders. I am sorry I forgot to mention that in the tree structure. I have made the edit now. I tried the split and join command in the module entry of the launch.json file. I edited the file to have ``` "module": "${relativePath}.split('/').join('.')" ``` but I think it definitely executes bash to evaluate the expression as I got the following error: ``` bash: syntax error near unexpected token `(' ```
0

There isn't a way to specify in your launch.json that you want it to calculate what the module you want to debug is. This is because it's technically impossible to get right 100% of the time due to namespace packages letting any directory represent a package. Your best option is to create separate debug configurations per example you want to run in your launch.json (you can have as many as you want). If doing that by hand is too tedious you could write a Python script to generate your launch.json for you.

2 Comments

Is there a way I can run a python script as a task automatically in VSCode, before I start debugging? Basically I would want the module entry in the launch.json file to be different in each. I think I need to read up on namespace packages to really understand where I am going wrong.
@AbhishekBhatia not that I'm aware of. You could write a Python script and set up a task for it so that you can easily run it from within VS Code. And depending on how much effort you want to put into it you could make a daemon process with file watchers to automatically detect when a change occurs to then automatically update launch.json. But that might be a bit too much work for a one-off problem. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.