From 1727a3e109c6e82927eb49932530b0c95a8b5c11 Mon Sep 17 00:00:00 2001 From: Pavel Minaev Date: Fri, 23 Oct 2020 15:49:39 -0700 Subject: [PATCH] Fix #330: Unable to debug pythonw apps on macOS In the launcher, use "python" instead of sys.executable to spawn the debuggee. Update test for "python" / "pythonPath" / "pythonArgs" to use a helper script to assert the use of a custom Python binary; and test -B instead of -v to minimize test log size and run time. --- src/debugpy/adapter/clients.py | 1 + src/debugpy/launcher/handlers.py | 4 +-- tests/debugpy/test_multiproc.py | 3 ++ tests/debugpy/test_run.py | 49 +++++++++++++++++++++----------- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/debugpy/adapter/clients.py b/src/debugpy/adapter/clients.py index ba23d0e2e..307f615fd 100644 --- a/src/debugpy/adapter/clients.py +++ b/src/debugpy/adapter/clients.py @@ -317,6 +317,7 @@ def property_or_debug_option(prop_name, flag_name): python += request("pythonArgs", json.array(unicode, size=(0,))) request.arguments["pythonArgs"] = python[1:] + request.arguments["python"] = python program = module = code = () if "program" in request: diff --git a/src/debugpy/launcher/handlers.py b/src/debugpy/launcher/handlers.py index 4f5fef2ec..e1be768dd 100644 --- a/src/debugpy/launcher/handlers.py +++ b/src/debugpy/launcher/handlers.py @@ -39,8 +39,8 @@ def property_or_debug_option(prop_name, flag_name): return value - python_args = request("pythonArgs", json.array(unicode, vectorize=True, size=(0,))) - cmdline = [compat.filename(sys.executable)] + python_args + python = request("python", json.array(unicode, size=(1,))) + cmdline = list(python) if not request("noDebug", json.default(False)): port = request("port", int) diff --git a/tests/debugpy/test_multiproc.py b/tests/debugpy/test_multiproc.py index 3ae16ee1e..339b35428 100644 --- a/tests/debugpy/test_multiproc.py +++ b/tests/debugpy/test_multiproc.py @@ -26,6 +26,9 @@ def expected_subprocess_config(parent_session): config = dict(parent_session.config) for key in "args", "listen", "postDebugTask", "preLaunchTask", "processId": config.pop(key, None) + for key in "python", "pythonArgs", "pythonPath": + if key in config: + config[key] = some.thing config.update( { "name": some.str, diff --git a/tests/debugpy/test_run.py b/tests/debugpy/test_run.py index b7ab5fed3..328c07263 100644 --- a/tests/debugpy/test_run.py +++ b/tests/debugpy/test_run.py @@ -137,31 +137,48 @@ def code_to_debug(): assert backchannel.receive() == "1" -@pytest.mark.parametrize("run", runners.all_launch_terminal) -@pytest.mark.parametrize("python_args", ["", "-v"]) -@pytest.mark.parametrize("python", ["", "custompy", "custompy|-O"]) +@pytest.mark.parametrize("run", runners.all_launch) +@pytest.mark.parametrize("python_args", [None, "-B"]) +@pytest.mark.parametrize("python", [None, "custompy", "custompy,-O"]) @pytest.mark.parametrize("python_key", ["python", "pythonPath"]) -def test_custom_python(pyfile, run, target, python_key, python, python_args): +def test_custom_python(pyfile, tmpdir, run, target, python_key, python, python_args): + if sys.platform == "win32": + custompy = tmpdir / "custompy.cmd" + script = """@echo off + set DEBUGPY_CUSTOM_PYTHON=1%DEBUGPY_CUSTOM_PYTHON% + %* + """ + else: + custompy = tmpdir / "custompy.sh" + script = """#!/bin/sh + env DEBUGPY_CUSTOM_PYTHON=1$DEBUGPY_CUSTOM_PYTHON "$@" + """ + custompy.write(script.replace("", sys.executable)) + os.chmod(custompy.strpath, 0o777) + @pyfile def code_to_debug(): + import os import sys + import debuggee from debuggee import backchannel debuggee.setup() - backchannel.send([sys.executable, sys.flags.optimize, sys.flags.verbose]) + backchannel.send( + [ + os.getenv("DEBUGPY_CUSTOM_PYTHON"), + sys.flags.optimize, + sys.flags.dont_write_bytecode, + ] + ) - python = python.split("|") - python_args = python_args.split() + python = [] if python is None else python.split(",") + python = [(custompy.strpath if arg == "custompy" else arg) for arg in python] + python_args = [] if python_args is None else python_args.split(",") python_cmd = (python if len(python) else [sys.executable]) + python_args - class Session(debug.Session): - def run_in_terminal(self, args, cwd, env): - assert args[: len(python_cmd)] == python_cmd - args[0] = sys.executable - return super(Session, self).run_in_terminal(args, cwd, env) - - with Session() as session: + with debug.Session() as session: session.config.pop("python", None) session.config.pop("pythonPath", None) if len(python): @@ -174,9 +191,9 @@ def run_in_terminal(self, args, cwd, env): pass assert backchannel.receive() == [ - sys.executable, + "11" if len(python) else None, # one for launcher, one for debuggee "-O" in python_cmd, - "-v" in python_cmd, + "-B" in python_cmd, ]