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

Debugger attempts to debug MicroPython subprocesses #781

Closed
Josverl opened this issue Nov 11, 2021 · 11 comments
Closed

Debugger attempts to debug MicroPython subprocesses #781

Josverl opened this issue Nov 11, 2021 · 11 comments
Labels
bug Something isn't working

Comments

@Josverl
Copy link

Josverl commented Nov 11, 2021

Issue Type: Bug

  • create two tests
    [tests/test_101.py][] just as a sanity check
    [tests/test_spr.py][] using subprocess.run to run a linux process

Expected :

[ ] pytest to run both tests successfully
[ ] vscode python testing to run both tests successfully
[ ] vscode to be able to debug both tests successfully

Actual

[x] pytest to run both tests successfully
[x] vscode python testing to run both tests successfully
[x] tests/test_101.py
[x] tests/test_spr.py

[ ] vscode to be able to debug both tests successfully
[x] tests/test_101.py
[ ] tests/test_spr.py subprocess.run Fails while debugging with the below error:

Traceback (most recent call last):
  File "/home/jos/.vscode-server/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/_vendored/pydevd/pydevd.py", line 24, in <module>
  File "/home/jos/.vscode-server/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_constants.py", line 4, in <module>
ImportError: no module named \'__future__\'\

Full repro in repo : https://github.com/Josverl/pytest_subprocess_run

Extension version: 2021.11.1422169775
VS Code version: Code 1.62.1 (f4af3cbf5a99787542e2a30fe1fd37cd644cc31f, 2021-11-05T10:57:55.946Z)
OS version: Windows_NT x64 10.0.22000
Restricted Mode: No
Remote OS version: Linux x64 5.10.60.1-microsoft-standard-WSL2
Remote OS version: Linux x64 5.10.60.1-microsoft-standard-WSL2

System Info
Item Value
CPUs Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz (8 x 2112)
GPU Status 2d_canvas: enabled
gpu_compositing: enabled
multiple_raster_threads: enabled_on
oop_rasterization: enabled
opengl: enabled_on
rasterization: enabled
skia_renderer: enabled_on
video_decode: enabled
vulkan: disabled_off
webgl: enabled
webgl2: enabled
Load (avg) undefined
Memory (System) 15.92GB (6.20GB free)
Process Argv --crash-reporter-id ede7f3a0-1b74-4e0a-8927-2f38c66cb4a5
Screen Reader no
VM 0%
Item Value
Remote WSL: Ubuntu-20.04
OS Linux x64 5.10.60.1-microsoft-standard-WSL2
CPUs Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz (8 x 2111)
Memory (System) 7.73GB (5.83GB free)
VM 0%
Item Value
Remote WSL: Ubuntu-20.04
OS Linux x64 5.10.60.1-microsoft-standard-WSL2
CPUs Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz (8 x 2111)
Memory (System) 7.73GB (5.83GB free)
VM 0%
A/B Experiments
vsins829:30139715
vsliv368:30146709
vsreu685:30147344
vspor879:30202332
vspor708:30202333
vspor363:30204092
vshan820:30294714
vscod805cf:30301675
vsccppwt:30393681
bridge0708:30335490
bridge0723:30353136
vsaa593:30376534

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

fabioz commented Nov 15, 2021

This is really strange... which Python version are you using?

That line in pydevd_constants.py should read: from __future__ import nested_scopes and that should work (maybe that's not needed anymore for any recent version of Python, but it should also definitely not crash anywhere).

Also, I find it strange that your error says:

ImportError: no module named \'__future__\'\

when it should actually say:

ImportError: no module named __future__

Those quotes around __future__ seem really suspicious (definitely not something I would expect), but maybe your environment is somehow customized... if you just remove the from __future__ import nested_scopes from pydevd_constants.py, do you have a different error afterwards?

@Josverl
Copy link
Author

Josverl commented Nov 15, 2021

sorry that i left that out :
Windows : ./.venv

home = C:\Users\josverl\AppData\Local\Programs\Python\Python39
include-system-site-packages = false
version = 3.9.7

Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64 bit (AMD64)]

Linux: ./.venv-ub

home = /usr/bin
include-system-site-packages = false
version = 3.8.10

Python 3.8.10 (default, Sep 28 2021, 16:10:42)
[GCC 9.3.0]

@Josverl
Copy link
Author

Josverl commented Nov 15, 2021

also I have done no customization that I am aware of, and I run into the same sort of issues when I use codespaces rather than my own WSL2-Ubunto 20.04 .
I can try to extend the repro to codespaces. then it's not just 'on my machine'

@int19h
Copy link
Collaborator

int19h commented Nov 15, 2021

The error message comes from the subprocess. This is also why single quotes are themselves quoted: the exception is raised like so:

assert subproc.returncode == 0, "createstubs ran with an error :" + str(subproc.stderr)

However, subproc.stderr is a bytes object, not a string, so str() on it is equivalent to repr() - i.e. b'...'. If you look closely at the screenshot, you can spot the b prefix in the output:
image
So it really was reporting a failure to import __future__. And that's because the subprocesses here are running under MicroPython, which doesn't have it:

cmd = [
        os.path.abspath("tests/tools/micropython_v1_16"),
        "main.py",
    ]

Now, pydevd and debugpy do not support MicroPython (and I don't think we ever will - there's too much functionality missing there to port our existing code). So the proper behavior would be for the subprocess to not have pydevd running in it at all. However, it looks like it still gets pydevd injected into it - that would be the bug here.

The workaround is to use "subProcess": false in your launch.json test config to disable subprocess debugger injection.

@Josverl
Copy link
Author

Josverl commented Nov 16, 2021

Actually the goal is not to debug the MicroPython code;
The goal was to start a linux executable using subprocess.run ( and yes , that is indeed a MicroPython executable )
( sorry for the Meta here, as im actually working on several projects to allow vscode / pylance to provide better support for Micropython through typeshed stubs)

I added some more test to the pattern :

  • cmd = [ exe.absolute().as_posix(), "main.py",]
    this is the original pattern
    • run OK
    • debug Fails with 'ImportError: no module named 'future'

additions:

  • cmd = ["node", "--version"]

    • run OK
    • debug OK
  • cmd = [ exe.absolute().as_posix(), "-X", "compile-only","main.py",]

    • run OK
    • debug OK

So it appears that the MicroPython ( for linux) runtime somehow detects that the python debugger is active, when MicroPython runs the code and that this causes the issue.

I did not expect that to be honest, and am not sure how to verify that theory

I took a (very brief) look at debugpy, and the one thing that catches my eye is that it can be configured to ignore subprocesses
https://github.com/microsoft/debugpy/#ignoring-subprocesses

How can I set this to ignore in the VSCode debug configuration ?
Or perhaps debugpy sets environment variables that get picked-up by MicroPython ?

I found : https://github.com/microsoft/debugpy/blob/main/doc/Subprocess%20debugging.md
and I love the overview that this gives, but it is also a quite complex process, so I appreciate any insight that you can give.

There only a few variables that MicroPython reads , documented, and I would not expect these to get set by debugpy.

But if i know what to look for then I could perhaps clear these to allow me to debug subsequent steps in the test

@int19h
Copy link
Collaborator

int19h commented Nov 16, 2021

"subProcess": false in debug configuration is the supported way to make debugpy ignore subprocesses.

I don't think this is a MicroPython issue - it cannot really "detect" the debugger in the parent process. However, on the debugger side, we have code that, when subprocess debugging is enabled, tries to detect spawned subprocesses, and if they appear to be Python, edits the command line used to spawn them to inject the debugger before any user code runs. So this is most likely what's happening here with the MicroPython subprocess. The debugpy bug, then, is that MicroPython subprocesses are treated as regular Python subprocesses, even though we can't actually debug them.

@int19h int19h added the bug Something isn't working label Nov 16, 2021
@int19h int19h changed the title VsCode / Python unable to debug pytest test using subprocess.run Debugger attempts to debug MicroPython subprocesses Nov 16, 2021
@int19h
Copy link
Collaborator

int19h commented Nov 16, 2021

So we basically assume that it's Python if the binary name for the subprocess contains "python" (among other things):

def is_python(path):
single_quote, double_quote = _get_str_type_compatible(path, ["'", '"'])
if path.endswith(single_quote) or path.endswith(double_quote):
path = path[1:len(path) - 1]
filename = os.path.basename(path).lower()
for name in _get_str_type_compatible(filename, ['python', 'jython', 'pypy']):
if filename.find(name) != -1:
return True
return False

if not is_python(unquoted_args[0]):
pydev_log.debug("Process is not python, returning.")
return original_args

A whitelist isn't viable here, unfortunately, since there are so many possible variations on the Python binary name. We'll probably have to specifically exclude MicroPython, CircuitPython etc.

OTOH it means that if you rename your MicroPython binary, or symlink to it, it should work.

@Josverl
Copy link
Author

Josverl commented Nov 26, 2021

just to circle back : setting "subProcess": false in the debug configuration works well and allows me to debug my CPython code .

it would be very cool if that could debug MicroPython, but trust you when you say that this is not possible.

@int19h
Copy link
Collaborator

int19h commented Nov 30, 2021

It's possible in principle, since MicroPython has the requisite sys.settrace() API these days. But it's missing many of the Python standard library modules, including stuff that we rely on, and internals (that we sometimes need to fiddle with) are also drastically different. So a DAP-based debugger for it is certainly feasible, but it would likely have to be implemented from scratch.

@fabioz
Copy link
Collaborator

fabioz commented Apr 1, 2022

@int19h @karthiknadig do you think we should do something in this issue or is the status quo reasonable right now?

@int19h
Copy link
Collaborator

int19h commented Apr 1, 2022

I think we're good for now. If there are more similar issues, we might consider adding an exclusion list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants