| 1 | Allow using pydevd as a regular dependency.
|
| 2 | Submitted upstream at: https://github.com/microsoft/debugpy/pull/902
|
| 3 |
|
| 4 | diff -rup a/setup.py b/setup.py
|
| 5 | |
| 6 | |
| 7 | @@ -11,6 +11,9 @@ import subprocess
|
| 8 | import sys
|
| 9 |
|
| 10 |
|
| 11 | +DEBUGPY_BUNDLING_DISABLED = bool(os.getenv('DEBUGPY_BUNDLING_DISABLED'))
|
| 12 | +
|
| 13 | +
|
| 14 | sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 15 | import versioneer # noqa
|
| 16 |
|
| 17 | @@ -18,12 +21,15 @@ del sys.path[0]
|
| 18 |
|
| 19 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
|
| 20 | import debugpy
|
| 21 | -import debugpy._vendored
|
| 22 | +
|
| 23 | +if not DEBUGPY_BUNDLING_DISABLED:
|
| 24 | + import debugpy._vendored
|
| 25 |
|
| 26 | del sys.path[0]
|
| 27 |
|
| 28 |
|
| 29 | -PYDEVD_ROOT = debugpy._vendored.project_root("pydevd")
|
| 30 | +PYDEVD_ROOT = (None if DEBUGPY_BUNDLING_DISABLED else
|
| 31 | + debugpy._vendored.project_root("pydevd"))
|
| 32 | DEBUGBY_ROOT = os.path.dirname(os.path.abspath(debugpy.__file__))
|
| 33 |
|
| 34 |
|
| 35 | @@ -46,7 +52,7 @@ def get_buildplatform():
|
| 36 | # relevant setuptools versions.
|
| 37 | class ExtModules(list):
|
| 38 | def __bool__(self):
|
| 39 | - return True
|
| 40 | + return not DEBUGPY_BUNDLING_DISABLED
|
| 41 |
|
| 42 |
|
| 43 | def override_build(cmds):
|
| 44 | @@ -72,6 +78,8 @@ def override_build_py(cmds):
|
| 45 | # in data files for binary builds.
|
| 46 | def finalize_options(self):
|
| 47 | original(self)
|
| 48 | + if DEBUGPY_BUNDLING_DISABLED:
|
| 49 | + return True
|
| 50 |
|
| 51 | # Ensure that pydevd extensions are present for inclusion into data_files.
|
| 52 | self.announce(
|
| 53 | @@ -140,6 +148,20 @@ with open("DESCRIPTION.md", "r") as fh:
|
| 54 |
|
| 55 |
|
| 56 | if __name__ == "__main__":
|
| 57 | + if debugpy.__bundling_disabled__ != DEBUGPY_BUNDLING_DISABLED:
|
| 58 | +
|
| 59 | + with open(os.path.join(DEBUGBY_ROOT, '__init__.py'), 'r') as f:
|
| 60 | + lines = f.readlines()
|
| 61 | + with open(os.path.join(DEBUGBY_ROOT, '__init__.py'), 'w') as f:
|
| 62 | + edited = []
|
| 63 | + for line in lines:
|
| 64 | + if line.startswith('__bundling_disabled__'):
|
| 65 | + edited.append(
|
| 66 | + f'__bundling_disabled__ = {DEBUGPY_BUNDLING_DISABLED}\n')
|
| 67 | + else:
|
| 68 | + edited.append(line)
|
| 69 | + f.writelines(edited)
|
| 70 | +
|
| 71 | extras = {}
|
| 72 | platforms = get_buildplatform()
|
| 73 | if platforms is not None:
|
| 74 | @@ -149,6 +171,18 @@ if __name__ == "__main__":
|
| 75 | override_build(cmds)
|
| 76 | override_build_py(cmds)
|
| 77 |
|
| 78 | + data = {"debugpy": ["ThirdPartyNotices.txt"]}
|
| 79 | + packages = [
|
| 80 | + "debugpy",
|
| 81 | + "debugpy.adapter",
|
| 82 | + "debugpy.common",
|
| 83 | + "debugpy.launcher",
|
| 84 | + "debugpy.server",
|
| 85 | + ]
|
| 86 | + if not DEBUGPY_BUNDLING_DISABLED:
|
| 87 | + data.update({"debugpy._vendored": list(iter_vendored_files())})
|
| 88 | + packages.append("debugpy._vendored")
|
| 89 | +
|
| 90 | setuptools.setup(
|
| 91 | name="debugpy",
|
| 92 | version=versioneer.get_version(),
|
| 93 | @@ -177,23 +211,10 @@ if __name__ == "__main__":
|
| 94 | "License :: OSI Approved :: MIT License",
|
| 95 | ],
|
| 96 | package_dir={"": "src"},
|
| 97 | - packages=[
|
| 98 | - "debugpy",
|
| 99 | - "debugpy.adapter",
|
| 100 | - "debugpy.common",
|
| 101 | - "debugpy.launcher",
|
| 102 | - "debugpy.server",
|
| 103 | - "debugpy._vendored",
|
| 104 | - ],
|
| 105 | - package_data={
|
| 106 | - "debugpy": ["ThirdPartyNotices.txt"],
|
| 107 | - "debugpy._vendored": [
|
| 108 | - # pydevd extensions must be built before this list can be computed properly,
|
| 109 | - # so it is populated in the overridden build_py.finalize_options().
|
| 110 | - ],
|
| 111 | - },
|
| 112 | + packages=packages,
|
| 113 | + package_data=data,
|
| 114 | ext_modules=ExtModules(),
|
| 115 | - has_ext_modules=lambda: True,
|
| 116 | + has_ext_modules=lambda: not DEBUGPY_BUNDLING_DISABLED,
|
| 117 | cmdclass=cmds,
|
| 118 | # allow the user to call "debugpy" instead of "python -m debugpy"
|
| 119 | entry_points={"console_scripts": ["debugpy = debugpy.server.cli:main"]},
|
| 120 | diff -rup a/src/debugpy/__init__.py b/src/debugpy/__init__.py
|
| 121 | |
| 122 | |
| 123 | @@ -34,5 +34,6 @@ assert sys.version_info >= (3, 7), (
|
| 124 | # SyntaxError on Python 2 and preventing the above version check from executing.
|
| 125 | from debugpy.public_api import * # noqa
|
| 126 | from debugpy.public_api import __version__
|
| 127 | +__bundling_disabled__ = False
|
| 128 |
|
| 129 | del sys
|
| 130 | diff -rup a/src/debugpy/server/attach_pid_injected.py b/src/debugpy/server/attach_pid_injected.py
|
| 131 | |
| 132 | |
| 133 | @@ -6,6 +6,7 @@
|
| 134 |
|
| 135 | import os
|
| 136 |
|
| 137 | +import debugpy
|
| 138 |
|
| 139 | __file__ = os.path.abspath(__file__)
|
| 140 | _debugpy_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
| 141 | @@ -28,25 +29,29 @@ def attach(setup):
|
| 142 | def on_critical(msg):
|
| 143 | print(msg, file=sys.stderr)
|
| 144 |
|
| 145 | - pydevd_attach_to_process_path = os.path.join(
|
| 146 | - _debugpy_dir,
|
| 147 | - "debugpy",
|
| 148 | - "_vendored",
|
| 149 | - "pydevd",
|
| 150 | - "pydevd_attach_to_process",
|
| 151 | - )
|
| 152 | - assert os.path.exists(pydevd_attach_to_process_path)
|
| 153 | - sys.path.insert(0, pydevd_attach_to_process_path)
|
| 154 | + if debugpy.__bundling_disabled__:
|
| 155 | + from pydevd_attach_to_process import attach_script
|
| 156 | + else:
|
| 157 | + pydevd_attach_to_process_path = os.path.join(
|
| 158 | + _debugpy_dir,
|
| 159 | + "debugpy",
|
| 160 | + "_vendored",
|
| 161 | + "pydevd",
|
| 162 | + "pydevd_attach_to_process",
|
| 163 | + )
|
| 164 | + assert os.path.exists(pydevd_attach_to_process_path)
|
| 165 | + sys.path.insert(0, pydevd_attach_to_process_path)
|
| 166 |
|
| 167 | - # NOTE: that it's not a part of the pydevd PYTHONPATH
|
| 168 | - import attach_script
|
| 169 | + # NOTE: that it's not a part of the pydevd PYTHONPATH
|
| 170 | + import attach_script
|
| 171 |
|
| 172 | attach_script.fix_main_thread_id(
|
| 173 | on_warn=on_warn, on_exception=on_exception, on_critical=on_critical
|
| 174 | )
|
| 175 |
|
| 176 | - # NOTE: At this point it should be safe to remove this.
|
| 177 | - sys.path.remove(pydevd_attach_to_process_path)
|
| 178 | + if not debugpy.__bundling_disabled__:
|
| 179 | + # NOTE: At this point it should be safe to remove this.
|
| 180 | + sys.path.remove(pydevd_attach_to_process_path)
|
| 181 | except:
|
| 182 | import traceback
|
| 183 |
|
| 184 | diff -rup a/src/debugpy/server/__init__.py b/src/debugpy/server/__init__.py
|
| 185 | |
| 186 | |
| 187 | @@ -2,6 +2,50 @@
|
| 188 | # Licensed under the MIT License. See LICENSE in the project root
|
| 189 | # for license information.
|
| 190 |
|
| 191 | +from importlib import import_module
|
| 192 | +import os
|
| 193 | +
|
| 194 | # "force_pydevd" must be imported first to ensure (via side effects)
|
| 195 | # that the debugpy-vendored copy of pydevd gets used.
|
| 196 | -import debugpy._vendored.force_pydevd # noqa
|
| 197 | +import debugpy
|
| 198 | +if debugpy.__bundling_disabled__:
|
| 199 | + # Do what force_pydevd.py does, but using the system-provided
|
| 200 | + # pydevd.
|
| 201 | +
|
| 202 | + # XXX: This is copied here so that the whole '_vendored' directory
|
| 203 | + # can be deleted when DEBUGPY_BUNDLING_DISABLED is set.
|
| 204 | +
|
| 205 | + # If debugpy logging is enabled, enable it for pydevd as well
|
| 206 | + if "DEBUGPY_LOG_DIR" in os.environ:
|
| 207 | + os.environ[str("PYDEVD_DEBUG")] = str("True")
|
| 208 | + os.environ[str("PYDEVD_DEBUG_FILE")] = \
|
| 209 | + os.environ["DEBUGPY_LOG_DIR"] + str("/debugpy.pydevd.log")
|
| 210 | +
|
| 211 | + # Work around https://github.com/microsoft/debugpy/issues/346.
|
| 212 | + # Disable pydevd frame-eval optimizations only if unset, to allow opt-in.
|
| 213 | + if "PYDEVD_USE_FRAME_EVAL" not in os.environ:
|
| 214 | + os.environ[str("PYDEVD_USE_FRAME_EVAL")] = str("NO")
|
| 215 | +
|
| 216 | + # Constants must be set before importing any other pydevd module
|
| 217 | + # due to heavy use of "from" in them.
|
| 218 | + pydevd_constants = import_module('_pydevd_bundle.pydevd_constants')
|
| 219 | + # The default pydevd value is 1000.
|
| 220 | + pydevd_constants.MAXIMUM_VARIABLE_REPRESENTATION_SIZE = 2 ** 32
|
| 221 | +
|
| 222 | + # When pydevd is imported it sets the breakpoint behavior, but it needs to be
|
| 223 | + # overridden because by default pydevd will connect to the remote debugger using
|
| 224 | + # its own custom protocol rather than DAP.
|
| 225 | + import pydevd # noqa
|
| 226 | + import debugpy # noqa
|
| 227 | +
|
| 228 | + def debugpy_breakpointhook():
|
| 229 | + debugpy.breakpoint()
|
| 230 | +
|
| 231 | + pydevd.install_breakpointhook(debugpy_breakpointhook)
|
| 232 | +
|
| 233 | + # Ensure that pydevd uses JSON protocol
|
| 234 | + from _pydevd_bundle import pydevd_constants
|
| 235 | + from _pydevd_bundle import pydevd_defaults
|
| 236 | + pydevd_defaults.PydevdCustomization.DEFAULT_PROTOCOL = pydevd_constants.HTTP_JSON_PROTOCOL
|
| 237 | +else:
|
| 238 | + import debugpy._vendored.force_pydevd # noqa
|
| 239 | diff -rup a/tests/tests/test_vendoring.py b/tests/tests/test_vendoring.py
|
| 240 | |
| 241 | |
| 242 | @@ -3,6 +3,11 @@
|
| 243 | # for license information.
|
| 244 |
|
| 245 |
|
| 246 | +import pytest
|
| 247 | +
|
| 248 | +import debugpy
|
| 249 | +
|
| 250 | +@pytest.mark.skipif(debugpy.__bundling_disabled__, reason='Bundling disabled')
|
| 251 | def test_vendoring(pyfile):
|
| 252 | @pyfile
|
| 253 | def import_debugpy():
|