Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tasks.json watcher launched by debugger never flags as a ready background task #676

Closed
tigerhawkvok opened this issue Jul 21, 2021 · 10 comments
Assignees

Comments

@tigerhawkvok
Copy link

Environment data

  • VS Code version: 1.58.2
  • Extension version (available under the Extensions sidebar): v2021.7.1050252941
  • OS and version: Windows 10
  • Python version (& distribution if applicable, e.g. Anaconda): Python 3.7.8
  • Type of virtual environment used (N/A | venv | virtualenv | conda | ...): Poetry
  • Value of the python.languageServer setting: pylance

Was initially filed under microsoft/vscode#129121

  • VS Code Version:
    Version: 1.58.2 (user setup)
    Commit: c3f126316369cd610563c75b1b1725e0679adfb3
    Date: 2021-07-14T22:10:15.214Z
    Electron: 12.0.13
    Chrome: 89.0.4389.128
    Node.js: 14.16.0
    V8: 8.9.255.25-electron.0
    OS: Windows_NT x64 10.0.19043
  • OS Version: Windows 10 19403.1110

Steps to Reproduce:

  1. Have a prerequisite prelaunch task for the debugger to run that must be in the background during the debug session
  2. Run the debugger

I'm trying to run my debug environment as a Poetry session, so I can properly debug encapsulated.

So, my launch.json is straightforward:

        {
            "name": "Poetry",
            "type": "python",
            "request": "attach",
            "connect": {
                "host": "localhost",
                "port": 5710
            },
            "preLaunchTask": "poetryDebugSession"
        }

and I adapted my tasks.json to try to launch debugpy in Poetry first (this works if I manually run the command in the terminal then run the launch.json without the preLaunchTask)

{
            "label": "poetryDebugSession",
            "type": "shell",
            "command": "poetry",
            "args": [
                "run",
                "python",
                "-m",
                "debugpy",
                "--log-to-stderr",
                "--wait-for-client",
                "--listen",
                "5710",
                "${relativeFile}"
            ],
            "presentation": {
                "panel": "dedicated",
                "clear": true
            },
            "group": "test",
            "isBackground": true, // probably redundant now
            "runOptions":{
                "instanceLimit": 1
            },
            // This task is run before the launch.json task. Since it needs to run in the
            // background and not wait for completion, though, we need to jump through hoops
            "problemMatcher": [
                {
                    "owner": "python",
                    "fileLocation": "absolute",
                    "pattern": [
                        {
                            "regexp": "^\\s+File \"(.*)\", line (\\d+), in (.*)$",
                            "file": 1,
                            "line": 2
                        },
                        {
                            "regexp": "^\\s+(.*)$",
                            "message": 1
                        }
                    ],
                    "background": {
                        "activeOnStart": true,
                        "beginsPattern": "^D[0-9\\.: \\+]+wait_for_client",
                        "endsPattern": ".*",
                    }
                }
            ]
        }

When I start debugging, the task is properly launched, and debugpy gets all the way to the message I am waiting for that I want the preluanch task to be marked as "ready":

> Executing task: poetry run python -m debugpy --log-to-stderr --wait-for-client --listen 5710 d:\path\to\myfile.py <
# stuff

I+00000.344: pydevd is connected to adapter at 127.0.0.1:61443

D+00000.344: wait_for_client()

I could have sworn I had this working last week but as of 1.58.2 after a restart this morning it doesn't progress past wait_for_client() display, so the debugger never attaches. I'm also a little suspicious that ${relativeFile} includes a full path in my output but that probably doesn't matter.

Logs

No relevant logs, only pylint scoring

@karthiknadig
Copy link
Member

karthiknadig commented Jul 22, 2021

You don't need a prelaunch task to run an app under poetry.
image

Is there a particular reason you are running it like that with a prelauch task?

if you really need the to work as expected then you need to run this with command like this:
python -m debugpy --log-to-stderr --wait-for-client --listen 5710 -m poetry <poetry arguments>
You should have PYTHONPATH=<path to where poetry library is installed>.

To test this do it in this order:

> set PYTHONPATH=<path to where poetry library is installed>
> python -c "import poetry" 

if the above two succeed, then navigate to your project from command line, and then launch code .

@karthiknadig karthiknadig self-assigned this Jul 22, 2021
@tigerhawkvok
Copy link
Author

tigerhawkvok commented Jul 23, 2021

Because that's not at all what I'm trying to do. I'm trying to run an arbitrary script, not an app, and your example fails before doing anything:

image

image

Without enumerating each and every potential script in pyproject.toml (not feasible, especially for the rest of the team that should have it "just work") this is a no-go.

The second solution is unideal as it puts a top-level dependency requirement on debugpy, instead of abstracting it all to poetry. Still fails anyway.

image

Giving

C:\Python37\python.exe: No module named poetry

and can't set it with a prelaunch task because it's run in a different terminal instance

{
            "label": "poetryPyPath",
            "type":"shell",
            "command": "set",
            "args": [
                "PYTHONPATH= $env:userprofile\\.poetry\\bin\\poetry"
            ],
        }

By running it with a prelaunch task:

  1. My global space is 100% irrelevant, which is important and a good thing.
  2. Any arbitrary file can be debugged, not just an "app". My org is just starting to embrace python for limited tasks, and we are years away from a full python pipeline in anything (we are classically a Windows+SQL shop).

I know that the base case works, because I can run, say,

poetry run python -m debugpy --wait-for-client --listen 5710 ./tests.py

in PowerShell then run a "dumb" debugger of

        {
            "name": "Poetry",
            "type": "python",
            "request": "attach",
            "connect": {
                "host": "localhost",
                "port": 5710
            }
        }

and it "Just Works". Fundamentally all I'm trying to do is automate that script part for the rest of the team.

@karthiknadig
Copy link
Member

@tigerhawkvok Thanks for the details. I will transfer this to the debugger repo.

There might be two separate issues here. Both in the debugger.

  1. Debugger not getting past wait_for_client. For this one, can you check the debugger version if it is version 1.4.0 then can you try with 1.3.0 (essentially rolling back) and see if it does not have the issue. I am suspecting this is due to 1.4.0. We released in on Tuesday.
  2. @fabioz The poetry script case should not fail in the manner it does. From the command line it looks like it should just work.

@karthiknadig karthiknadig transferred this issue from microsoft/vscode-python Jul 23, 2021
@fabioz
Copy link
Collaborator

fabioz commented Jul 23, 2021

I'll investigate.

@fabioz fabioz assigned fabioz and unassigned karthiknadig Jul 23, 2021
@fabioz
Copy link
Collaborator

fabioz commented Jul 23, 2021

As a note, regarding the NoneType is not iterable, the error in this traceback is from 1.3 -- the codebase changed a bit there -- I'm not sure it actually fixes the error, but by reviewing the code (https://github.com/microsoft/debugpy/blob/main/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_process_net_command_json.py#L412), short of having watchDirectories be directly specified as [null], I couldn't really determine how a None could end up being in watch_dirs in the current version (so, it may be fixed already).

@fabioz
Copy link
Collaborator

fabioz commented Jul 23, 2021

As a note, I couldn't get the solution to work properly (because "isBackground": true is defined in tasks.json, it tries to attach right away before it gets to start the launch, but when removing the "isBackground": true, it seems it never gets to run the attach after the debugger is already listening -- launching in the terminal instead of using the preload works, so, this is mostly on how to config that in the vscode side and the issue itself doesn't seem related to the debugger).

This may be due to some misunderstanding on my part, but from what I can tell, the process is correctly stopped in the wait_for_client() call waiting for the attach, but the process is not considered complete by vscode so that the attach can be done.

I'm not very knowledgeable on how the prelaunch with a task defined in the tasks.json should signal that the main launch should proceed (the "background" in the "problemMatcher" seems to be being used for that, but I have no idea if that's how it's actually supposed to work)... @karthiknadig should that actually work?

Still, I was thinking that what's being done is essentially the same thing as a launch with the following contents:

        {
            "name": "Python: Poetry current file",
            "type": "python",
            "request": "launch",
            "python": "</path/to/python/with/poetry/installed/python.exe>",
            "module": "poetry",
            "args": ["run", "python", "${file}"],
            "console": "integratedTerminal"
        }

Which should automatically attach to the subprocess which poetry launches and seems to do everything requested for me (without needing a prelaunch task) -- @tigerhawkvok could that be a better solution for your use case?

@tigerhawkvok
Copy link
Author

Poetry by design doesn't install "into" a python distro: https://python-poetry.org/docs/#installation

Poetry provides a custom installer that will install poetry isolated from the rest of your system by vendorizing its dependencies. This is the recommended way of installing poetry.
[ ... ]
The installer installs the poetry tool to Poetry’s bin directory. On Unix it is located at $HOME/.poetry/bin and on Windows at %USERPROFILE%.poetry\bin.
This directory will be automatically added to your $PATH environment variable, by appending a statement to your $HOME/.profile configuration (or equivalent files). If you do not feel comfortable with this, please pass the --no-modify-path flag to the installer and manually add the Poetry’s bin directory to your path.

which is why, I'm pretty sure, yesterday's suggestion failed. I'm skeptical about changing something into an unsupported configuration to monkey-patch something else.

I did interpret the base issue being the attacher in vscode like you do, @fabioz , but at microsoft/vscode#129121 they closed this issue and punted me over here.

Just in case I updated the debugpy version but it didn't resolve the issue.

image

@fabioz
Copy link
Collaborator

fabioz commented Jul 24, 2021

Poetry by design doesn't install "into" a python distro: https://python-poetry.org/docs/#installation

Poetry provides a custom installer that will install poetry isolated from the rest of your system by vendorizing its dependencies. This is the recommended way of installing poetry.
[ ... ]
The installer installs the poetry tool to Poetry’s bin directory. On Unix it is located at $HOME/.poetry/bin and on Windows at %USERPROFILE%.poetry\bin.
This directory will be automatically added to your $PATH environment variable, by appending a statement to your $HOME/.profile configuration (or equivalent files). If you do not feel comfortable with this, please pass the --no-modify-path flag to the installer and manually add the Poetry’s bin directory to your path.

Actually, that's all smoke and mirrors... If you take a better look at it, you'll see that it'll just use the python that's in your PATH, it doesn't really create a standalone tool (if you try to execute poetry without python in the PATH, it'll fail -- you can see that there's no real poetry executable, if you open the poetry file, it's actually a plain .py file which adds python "%USERPROFILE%\.poetry\lib to the PYTHONPATH and then runs something akin to python -m poetry and all that the poetry.bat does is calling python "%USERPROFILE%\.poetry\bin\poetry" %*).

Still, I agree there's one difference, it's forcing to use the poetry at %USERPROFILE%/.poetry/lib, not the one installed at a python installation, but that's simple to solve by adding it to the PYTHONPATH:

        {
            "name": "Python: Poetry current file",
            "type": "python",
            "request": "launch",
            "module": "poetry",
            "python": "<path/to/bare/bones/python>",
            "args": ["run", "python", "${file}"],
            "console": "integratedTerminal",
            "env": {
                "PYTHONPATH": "${env:USERPROFILE}/.poetry/lib"
            }
        }

-- although I must say I personally prefer to just choose a python base environment to have poetry installed there and run things with python -m poetry instead of the poetry pseudo-executable as I have more control over the python environment being used... Anyways, both approaches seem valid for me ;)

@fabioz
Copy link
Collaborator

fabioz commented Jul 24, 2021

Actually, I saw that it does one thing different in how it vendors some dependencies so that it can be executed in any env, so, the solution above isn't 100% correct, a better approach to use the global poetry is just launching ${env:USERPROFILE}/.poetry/bin/poetry directly, since it's a plain python script (which will fix the PYTHONPATH to use the proper vendored libraries).

i.e.:

        {
            "name": "Python: Poetry current file",
            "type": "python",
            "request": "launch",
            "program": "${env:USERPROFILE}/.poetry/bin/poetry",
            "python": "<path/to/bare/bones/python>",
            "args": ["run", "python", "${file}"],
            "console": "integratedTerminal",
        }

@tigerhawkvok
Copy link
Author

@fabioz that's a thing of beauty that "just works". Closing issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants