microsoft / debugpy

An implementation of the Debug Adapter Protocol for Python
https://pypi.org/project/debugpy/
Other
1.83k stars 136 forks source link

PreLaunchTask correctly waits for background task to wait for client connection, then fails with vague popuop #1699

Open jasondamour opened 1 week ago

jasondamour commented 1 week ago

Environment data

Actual behavior

I'm using Pants to run python tests. The program behaves as expected (starts the test with pdb and waits for client connection):

➜  pants test --debug-adapter example_test.py
12:16:25.45 [INFO] Launching debug adapter at '127.0.0.1:5678', which will wait for a client connection...

I would like to use a launch configuration with a preLaunchTask to make debugging easy. However, VS Code does not behave as expected with the background task. I have tried seemingly every possible combination of isBackground, problemMatcher.background, and other fields. Below is what I believe should work according to documentation. When the "Pants: Debug Test" launch configuration is triggered, it calls the correct shell command and correctly waits for the "Launching debug adapter" endPattern to be printed, but then fails with a vague popup

Image

launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Pants: Debug Test",
      "preLaunchTask": "Pants Debug Test (Current File)",
      "type": "debugpy",
      "request": "attach",
      "pathMappings": [
        {
          "localRoot": "${workspaceFolder}",
          "remoteRoot": "."
        }
      ],
      "connect": {
        "host": "localhost",
        "port": 5678
      }
    }
  ]
}

tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Pants Debug Test (Current File)",
      "type": "shell",
      "command": "pants test --debug-adapter ${file} ",
      "group": "test",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared",
        "showReuseMessage": false,
        "clear": true
      },
      "isBackground": true,
      "problemMatcher": {
        "owner": "pants",
        "source": "pytest",
        "fileLocation": "relative",
        "background": {
          "activeOnStart": true,
          "beginsPattern": ".",
          "endsPattern": ".*Launching debug adapter.*",
        },
        "pattern": [
          {
            "regexp": ".",
            "file": 1,
            "location": 2,
            "message": 3
          }
        ]
      }
    }
  ]
}

Expected behavior

PreLaunchTask to run, and debugpy to attach to remote configuraiton

Steps to reproduce:

Above launch.json/task.json and a sample pants project

jasondamour commented 1 week ago

If I manually run the task, then start the debugger (with preLaunchtask commented out), then it attaches as expected.

Also, if I change localhost to 127.0.0.1 in launch.json, then I finally get an error in the popup:

connect ECONNREFUSED 127.0.0.1:5678

So maybe this is a race condition between the line being printed and pdb listening on the port?

jasondamour commented 1 week ago

Answering my own question a little: Pants does print that line before listening. So this is probably a race condition, and can be solved outside of debugpy. https://github.com/pantsbuild/pants/blob/main/src/python/pants/core/goals/test.py#L868

However, it is still frustrating/confusing that vscode doesn't print connection refused when using localhost

jasondamour commented 1 week ago

And full circle!

Since Pants just uses debugpy under the hood and doesn't micromanage the process, it doesn't really know when the process is successfully listening. So I need debugpy to print a log line after it starts listening, that I can use in the tasks.json endPattern to trigger vscode attaching.

Is there such an option to print a log line after debugpy --wait-for-client is listening?

jasondamour commented 1 week ago

Here's the log line I'm looking to trigger tasks.json on: https://github.com/microsoft/debugpy/blob/main/src/debugpy/server/api.py#L276

But I need this printed to stdout...

jasondamour commented 1 week ago

Alright, I have my workaround:

This works and is done "the right way" without wrapper scripts, sleeps, etc. However, now debugpy is logging tons of stuff to stderr, 258 log lines at the start of every test!

Ask: Can debugpy please signal that it is successfully listening in a concise manner?

jasondamour commented 1 week ago

Submitted a PR for a quick fix: https://github.com/microsoft/debugpy/pull/1700