I found an issue when debugging in Theia v0.15.0 with Python VS extension. After version 2019.9.34911 there is an error when starting a debug session with the "Python Debug Console" already open.
Python VS extension : 2020.1.58038
OS and Theia version: Ubuntu Disco and Theia v0.15.0. Installation with this Dockerfile. Using the following package.json
Diagnostics:
In the Python Debug console:
~/workspace# /usr/bin/python /tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher /root/workspace/example.py
Traceback (most recent call last):
File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher/__main__.py", line 80, in <module>
main()
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher/__main__.py", line 42, in main
launcher.connect(launcher_port)
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher/../../ptvsd/launcher/__init__.py", line 27, in connect
sock.connect(("127.0.0.1", launcher_port))
ConnectionRefusedError: [Errno 111] Connection refused
In the backend:
root ERROR [hosted-plugin: 111] E+00010.052: /handling #2 request "launch" from IDE[1]/
Handler 'IDE._start_message_handler.<locals>.handle' (file '/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/adapter/components.py', line 160)
couldn't handle #2 request "launch" from IDE[1]:
Traceback (most recent call last):
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/common/messaging.py", line 766, in _handle
result = handler(self)
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/adapter/components.py", line 95, in lock_and_handle
return f(self, message)
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/adapter/ide.py", line 176, in handle
f(self, request)
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/adapter/ide.py", line 278, in launch_request
self.session, request, sudo, args, console, console_title
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/adapter/launchers.py", line 115, in spawn_debuggee
spawn_launcher()
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/adapter/launchers.py", line 98, in spawn_launcher
"env": env,
File "/usr/lib/python3.7/contextlib.py", line 119, in __exit__
next(self.gen)
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/adapter/sessions.py", line 163, in _accept_connection_from
sock, (other_host, other_port) = listener.accept()
File "/usr/lib/python3.7/socket.py", line 212, in accept
fd, addr = self._accept()
socket.timeout: timed out
Stack where logged:
File "/usr/lib/python3.7/threading.py", line 885, in _bootstrap
self._bootstrap_inner()
File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/common/messaging.py", line 1523, in _run_handlers
handler()
File "/tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/adapter/../../ptvsd/common/messaging.py", line 812, in _handle
self.describe(),
I ran into the same issue and did some investigation. It is basically caused by the fact that an already existing terminal does not get the port for the debug session. In doCreateTerminal a new terminal gets all the options as opposed to an already existing terminal. In this case a Python Debug Console does not know anything about the updated port and the connection gets refused.
From the Python Debug console we could see that the launcher is started like this:
/usr/bin/python /tmp/vscode-unpacked/ms-python.python-latest.vsix/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher
What we cannot see here is that the environment variable _PTVSD_LAUNCHER_PORT_ is used by the launcher to know which port to connect to. A quick and quite specific workaround is to add the environment variable _PTVSD_LAUNCHER_PORT_ to the following line in debug-session.tsx. Just replace:
terminal.sendText(args.join(' ') + '\n');
by:
terminal.sendText('PTVSD_LAUNCHER_PORT=' + env['PTVSD_LAUNCHER_PORT'] + ' ' + args.join(' ') + '\n');
This workaround just makes it work for the Python VS extension, but because _debug-session.tsx_ is a general location, a general solution should be used. Therefore, I have a few questions regarding how to best solve this issue:
I thought that env variables are inherited by processes. If not then it is a bug. cc @marechal-p
@tolusha @tsmaeder Is it correct that PTVSD_LAUNCHER_PORT should be inherited by the plugin host process then by the debug adapter process and then by the program process?
@akosyakov env variables are inherited by sub-processes. The issue is that we reuse shells (like VS Code) to run commands sent by debug adapters via runInTerminal requests. This means that a single shell process is spawned, with some env vars, and then never gets updated. We just keep sending commands to it.
The following piece of code will fix this issue, since it encodes the new env into the command that is sent to the everlasting shell: https://github.com/eclipse-theia/theia/pull/6836/files#diff-6121f93c6c9a828c7d6ba245fe1354feR88-R98
@akosyakov env variables are inherited by sub-processes. The issue is that we reuse shells (like VS Code) to run commands sent by debug adapters via
runInTerminalrequests. This means that a single shell process is spawned, with some env vars, and then never gets updated. We just keep sending commands to it.The following piece of code will fix this issue, since it encodes the new env into the command that is sent to the everlasting shell: https://github.com/eclipse-theia/theia/pull/6836/files#diff-6121f93c6c9a828c7d6ba245fe1354feR88-R98
can you elaborate more please what the steps are
thank you
@a-kanaan hm, not sure how to elaborate more, but here it is in other words:
When a debug adapter sends a runInTerminal request, Theia spawns a shell the first time, and then reuses said shell for next runInTerminal requests. This is what VS Code does as well.
In this case, it seems like some use-cases require changing the environment variables between different runInTerminal calls. Issue is: the shell process being re-used, we cannot reset environment variables easily. We usually set the environment when spawning a process, but like I said we don't respawn processes.
The solution is to craft shell commands that will actually contain several commands: some to modify the environment directly inside the running shell, followed by the actual command that runInTerminal wanted to run with the new environment variables.
Doing all of this requires a somewhat robust command-to-shell convertion mechanism, with escaping and all that. I am currently working on this PR, and am down to the last issues with it. My biggest pain by far is to accommodate for Windows with cmd.exe + the weird node-pty mechanism. But I'm getting there.
Hope this helps.
This is still not working out of the box.
Create an empty workspace, add a simple python file (print("hello world!) will do), try to debug using the default configuration "Python: Current file" which will create a launch.json [1] for you.
It won't work and exit with [2].
Setting the "console" paramter in the launch.json to "integratedConsole" makes it work, of course you have to enable the "Debug Console" ("View" --> "Debug Console") then to see anything.
[1]:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
[2]:
Traceback (most recent call last):
File "/home/gitpod/.pyenv/versions/3.7.7/lib/python3.7/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/home/gitpod/.pyenv/versions/3.7.7/lib/python3.7/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/tmp/vscode-extensions/[email protected]/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher/__main__.py", line 74, in <module>
main()
File "/tmp/vscode-extensions/[email protected]/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher/__main__.py", line 36, in main
adapter.connect(session_id, launcher_port)
File "/tmp/vscode-extensions/[email protected]/extension/pythonFiles/lib/python/new_ptvsd/wheels/ptvsd/launcher/../../ptvsd/launcher/adapter.py", line 27, in connect
sock.connect(("127.0.0.1", launcher_port))
ConnectionRefusedError: [Errno 111] Connection refused
It seems that the pull request shown above has not been merged yet.
@denisvasilik the PR was merged.
@ptrxyz What is your platform? And did you try building and running the example applications from the master branch?
While trying to reproduce, I just found an issue with Windows: it seems like shells on Windows expect \r to "submit" commands while we currently send \n.
@marechal-p and @ptrxyz You're right sorry for that. I used the tag v1.0.0 where the pull request has not been integrated.
@marechal-p Would it be fine to assign this issue to you?
@denisvasilik the PR was merged.
@ptrxyz What is your platform? And did you try building and running the example applications from the master branch?
While trying to reproduce, I just found an issue with Windows: it seems like shells on Windows expect
\rto "submit" commands while we currently send\n.
I was running Theia on Gitpod. So probably it was Linux ... no idea about the version though.
Most helpful comment
@a-kanaan hm, not sure how to elaborate more, but here it is in other words:
When a debug adapter sends a
runInTerminalrequest, Theia spawns a shell the first time, and then reuses said shell for nextrunInTerminalrequests. This is what VS Code does as well.In this case, it seems like some use-cases require changing the environment variables between different
runInTerminalcalls. Issue is: the shell process being re-used, we cannot reset environment variables easily. We usually set the environment when spawning a process, but like I said we don't respawn processes.The solution is to craft shell commands that will actually contain several commands: some to modify the environment directly inside the running shell, followed by the actual command that
runInTerminalwanted to run with the new environment variables.Doing all of this requires a somewhat robust command-to-shell convertion mechanism, with escaping and all that. I am currently working on this PR, and am down to the last issues with it. My biggest pain by far is to accommodate for Windows with
cmd.exe+ the weirdnode-ptymechanism. But I'm getting there.Hope this helps.