Python project with Poetry: how to debug it in Visual Studio Code?
Asked Answered
E

7

21

I have a Python project which I created according to basic Poetry instructions.

The project folder is something like this:

my-project
+----my_project
|    +-- my_project.py
|    +-- File1.py
|    +-- File2.py
|
+----pyproject.toml

Example of how I import stuff from one file to another: in my_project.py I have the code

from . import File1, File2

If I want to debug this from VS Code, if I try F5 in the my_project.py, I get the error:

Exception has occurred: ImportError
attempted relative import with no known parent package

However, if I don't express the imports like above, I can't run it using the poetry command.

In the pyproject.toml file, I have this:

[tool.poetry.scripts]
my-project = "my_project.my_project:run"

run is the entry-point method in the my_project.py file.

To run the project from command prompt, I go to the project folder (where the package folder is) and I type poetry run my-project

Again, up to this point, everything according to the Poetry documentation.

How could I debug this project in VS Code?

I know I need to create a launch.json file, but I don't know how the configuration should look.

Expurgate answered 8/9, 2021 at 16:12 Comment(0)
N
14

For Visual Studio Code, you could try this:

  • add an __init__.py file in the sub-directory my_project
  • in the .vscode directory, add a lauch.json file with the following content:
{
    "version": "0.1.0",
    "configurations": [
        {
            "name": "my-project",
            "type": "python",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "module": "my_project",
            "args": []
        }
    ]
}

Here, cwd points to your workspace folder, which should be the parent directory of my-project. You should then be able to run successfully the Run and Debug module of Visual Studio Code.

As for Poetry, try modifying your pyproject.toml like this (there seems to be a typo, hyphen vs underscore):

[tool.poetry.scripts]
my-project = "my-project.my_project:run"

And make sure to set the parent directory of my-project as your current working directory when you run poetry run my-project.

See this post for additional guidance.

Nashner answered 10/9, 2021 at 6:0 Comment(5)
Should __init__.py file be empty ?Eulaeulachon
Hi, I don't think that the content of the __init__.py file matters in that case.Nashner
An empty __init__.py file tells python that the folder it is in is a package. This gets your import references working. You could also put python code into __init__.py, if needed. That code gets executed if someone imports from the package (i.e. named after the parent folder of the __init__.py. These files are one way of managing what exactly gets imported when you import a package. Not typically needed.Squirearchy
This approach results for me in `No module named my_project.__main__; 'my_project' is a package and cannot be directly executed.Guanine
is there any way to run poetry in the debugger script? like poetry run my-project?Kristofer
P
8

None of above worked for me. I have tried this

First run poetry debug info and get your executable path and then

{
  "version": "0.1",
  "configurations": [
    {
      "name": "Python: Poetry",
      "type": "python",
      "request": "launch",
      "python": "your executeable path taken from command above",
      "module": "yourmodulename",
      "args": [],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal"
    }
  ]
}

I hope it helps :)

Pauli answered 22/10, 2023 at 19:55 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Halden
thanks for the info, upvoted. I have kept my entry point as markets/markets/markets.py with "module": "markets","cwd": "${workspaceFolder}/markets",Subternatural
M
4

In the project directory, create the file .vscode/launch.json with the following structure:

{
  // 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": "Your Project Name",
      "type": "python",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "module": "poetry",
      "python": "${workspaceFolder}/.venv/bin/python",
      "args": [
        "run",
        "python",
        "-m",
        "uvicorn",
        "your_app_project:app",
        "--host",
        "localhost",
        "--port",
        "8000",
        "--debug",
        "--reload"
      ],
      "justMyCode": true,
      "stopOnEntry": false,
      "console": "integratedTerminal",
      "env": {
        "SIMPLE_SETTINGS": "your_env_value"
      }
    }
  ]
}

Adjust the name, the args, and the env to fit your project. If you are using pip, the value of the module field should be pytest.

It is also possible to add more configurations and change them during development.

Mastin answered 1/2, 2023 at 12:41 Comment(0)
P
4

The previous answers didn't work for me.

Here is the configuration of the launch.json file I needed to use to get the python debugger running on Visual Studio Code in a Poetry project.

{
    "version": "0.2.0",
    "configurations": [
      {
        "name": "project debug", // Anything you want
        "type": "python",
        "request": "launch",
        "cwd": "C:\\...\\project", // full path to project folder
        "python": "C:\\...\\python.exe", // full path to python.exe (run  poetry env info --path) in terminal to get virtual env folder
        "program": "C:\\...\\file.py", // full path to file to execute
        "console": "integratedTerminal",
        "redirectOutput": true,
        "justMyCode": false,
        "stopOnEntry": false,
      }
    ]
  }

And here's the structure I use(d) for Poetry projects

C:.
│   poetry.lock
│   pyproject.toml
│
├───.vscode
│       launch.json
│
├───decon
│   │   file1.py
│   │   file2.py
│   │   ...
│   │   __init__.py
Plebeian answered 9/7, 2023 at 14:41 Comment(0)
S
0

My proposed solution using the extension Command Variable to set up a configuration in launch.json.

Using the Command Variable extension, we can use a "variable transform" to convert the current file path into a relative path with dots.

This would give the following configuration in launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python (Poetry): Current File",
      "type": "python",
      "request": "launch",
      "module": "${command:extension.commandvariable.file.relativeFileDotsNoExtension}",
      "console": "integratedTerminal",
      "justMyCode": true
    }
  ]
}

So, for a project that looks like:

WorspaceRoot
┬───────────
│
├─┬─ .vscode
│ └─── launch.json
├─┬─ MyProject
│ ├─── __init__.py
│ ├─── file1.py
│ ├─── file2.py
│ └─── ...
├─── poetry.lock
├─── pyproject.toml
└─── ...

by running the configuration on an open file in WorkspaceRoot/MyProject/file1.py, the command command:extension.commandvariable.file.relativeFileDotsNoExtension converts the file path into MyProject.file1. If you have the current Python environment set to be your poetry project, running this should run as a module (essentially -m).

If, however, you have a slightly different project structure, where file1.py is located in WorspaceRoot/src/MyProject/file1.py, then this needs additional work since the passed module will be src.MyProject.file1.

To remove the src prefix, we can make use an input variable along with the extension's command extension.commandvariable.transform, as follows:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python (Poetry): Current File",
      "type": "python",
      "request": "launch",
      "module": "${input:PythonModuleName}",
      "console": "integratedTerminal",
      "justMyCode": true
    }
  ],
  "inputs": [
    {
      "id": "PythonModuleName",
      "type": "command",
      "command": "extension.commandvariable.transform",
      "args": {
        "text": "${command:extension.commandvariable.file.relativeFileDotsNoExtension}",
        "find": "src\\.(.*)",
        "replace": "$1",
      }
    }
  ]
}

The regex pattern src\\.(.*) captures everything after the src. prefix, which is then substituted as the input to our original configuration via the ${input:PythonModuleName} variable replacement.

Supposing answered 16/1 at 4:14 Comment(0)
B
0

To expand on Laurent's great answer here is an updated configuration that will run poetry itself and automatically select the virtual environment:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python Debugger: Poetry my-project with Arguments",
            "type": "debugpy",
            "request": "launch",
            "console": "integratedTerminal",
            "stopOnEntry": false,
            "justMyCode": true,
            "python": "${command:python.interpreterPath}",
            "cwd": "${workspaceFolder}",
            "args": "${command:pickArgs}",
            "module": "poetry run my-project",
        }
    ]
}

Hopefully this helps anyone coming here from a search engine.

Biannulate answered 25/7 at 13:10 Comment(0)
R
0
  1. Run poetry env info in your project root
  2. Copy the value of Virtualenv.Executable to python
  3. Specify ${workspaceFolder:<project-root-folder-name>} for cwd

This is a launch.json example, I run my fastapi app with gunicorn in a workspace using PYTHON_ENV=prod poetry run gunicorn -c gunicorn_conf.py project.main:app --bind 0.0.0.0:8081

{
  "version": "0.1",
  "configurations": [
    {
      "name": "Python: Poetry",
      "type": "debugpy",
      "request": "launch",
      "python": "/home/admin/.cache/pypoetry/virtualenvs/project-ESoVRWd5-py3.10/bin/python",
      "module": "gunicorn",
      "args": [
        "-c",
        "gunicorn_conf.py",
        "project.main:app",
        "--bind",
        "0.0.0.0:8081"
      ],
      "env": { "PYTHON_ENV": "prod" },
      "cwd": "${workspaceFolder:core}",
      "console": "integratedTerminal"
    }
  ]
}
Responsiveness answered 9/8 at 7:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.