Subject: [bug#70995] [PATCH v3 2/2] gnu: python-debugpy: Update to 1.8.0.

From: Nicolas Graves <[email-masked]>
Date: Tue, 28 May 2024 10:46:11 +0200

* gnu/packages/python-xyz.scm (python-debugpy): Update to 1.8.0.
* gnu/packages/patches/python-debugpy-unbundle-pydevd.patch: Update it.

Change-Id: Ice5f869fc36b29cb9d0ad998684b0526c16ab79d
---
 .../python-debugpy-unbundle-pydevd.patch      | 318 +++++++++++-------
 gnu/packages/python-xyz.scm                   |   6 +-
 2 files changed, 201 insertions(+), 123 deletions(-)

diff --git a/gnu/packages/patches/python-debugpy-unbundle-pydevd.patch b/gnu/packages/patches/python-debugpy-unbundle-pydevd.patch
index 7a6ad544896..dabdbd2b526 100644
--- a/gnu/packages/patches/python-debugpy-unbundle-pydevd.patch
+++ b/gnu/packages/patches/python-debugpy-unbundle-pydevd.patch
@@ -1,137 +1,194 @@
 Allow using pydevd as a regular dependency.
-Submitted upstream at: https://github.com/microsoft/debugpy/pull/902
+Submitted upstream at: https://github.com/microsoft/debugpy/pull/1586
 
 diff --git a/setup.py b/setup.py
-index 5fc40070..3a530a29 100644
+index 0bb4f00c..59fab822 100644
 --- a/setup.py
 +++ b/setup.py
-@@ -11,6 +11,9 @@ import subprocess
+@@ -11,6 +11,8 @@ import subprocess
  import sys

-+DEBUGPY_BUNDLING_DISABLED = bool(os.getenv('DEBUGPY_BUNDLING_DISABLED'))
-+
++BUNDLE_DEBUGPY = not (os.getenv("BUNDLE_DEBUGPY").strip().lower() == "0")
 +
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
  import versioneer  # noqa
  
-@@ -18,12 +21,15 @@ del sys.path[0]
+@@ -18,12 +20,14 @@ del sys.path[0]
  
  sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
  import debugpy
 -import debugpy._vendored
 +
-+if not DEBUGPY_BUNDLING_DISABLED:
++if BUNDLE_DEBUGPY:
 +    import debugpy._vendored
  
  del sys.path[0]
  
- 
+-
 -PYDEVD_ROOT = debugpy._vendored.project_root("pydevd")
-+PYDEVD_ROOT = (None if DEBUGPY_BUNDLING_DISABLED else
-+               debugpy._vendored.project_root("pydevd"))
++if BUNDLE_DEBUGPY:
++    PYDEVD_ROOT = debugpy._vendored.project_root("pydevd")
  DEBUGBY_ROOT = os.path.dirname(os.path.abspath(debugpy.__file__))

-@@ -67,7 +73,7 @@ def iter_vendored_files():
+@@ -46,7 +50,7 @@ def get_buildplatform():
  # relevant setuptools versions.
  class ExtModules(list):
      def __bool__(self):
 -        return True
-+        return not DEBUGPY_BUNDLING_DISABLED
++        return BUNDLE_DEBUGPY

  def override_build(cmds):
-@@ -133,9 +139,24 @@ with open("DESCRIPTION.md", "r") as fh:
+@@ -147,7 +151,28 @@ if __name__ == "__main__":
  
- 
- if __name__ == "__main__":
--    if not os.getenv("SKIP_CYTHON_BUILD"):
-+    if not (os.getenv("SKIP_CYTHON_BUILD") or DEBUGPY_BUNDLING_DISABLED):
-         cython_build()
- 
-+    # Etch bundling status in the source.
-+    if debugpy.__bundling_disabled__ != DEBUGPY_BUNDLING_DISABLED:
-+
-+        with open(os.path.join(DEBUGBY_ROOT, '__init__.py'), 'r') as f:
-+            lines = f.readlines()
-+        with open(os.path.join(DEBUGBY_ROOT, '__init__.py'), 'w') as f:
-+            edited = []
-+            for line in lines:
-+                if line.startswith('__bundling_disabled__'):
-+                    edited.append(
-+                        f'__bundling_disabled__ = {DEBUGPY_BUNDLING_DISABLED}\n')
-+                else:
-+                    edited.append(line)
-+            f.writelines(edited)
-+
-     extras = {}
-     platforms = get_buildplatform()
-     if platforms is not None:
-@@ -145,6 +166,18 @@ if __name__ == "__main__":
+     cmds = versioneer.get_cmdclass()
      override_build(cmds)
-     override_build_py(cmds)
- 
+-    override_build_py(cmds)
++    if BUNDLE_DEBUGPY:
++        override_build_py(cmds)
++
 +    data = {"debugpy": ["ThirdPartyNotices.txt"]}
 +    packages = [
-+            "debugpy",
-+            "debugpy.adapter",
-+            "debugpy.common",
-+            "debugpy.launcher",
-+            "debugpy.server",
-+        ]
-+    if not DEBUGPY_BUNDLING_DISABLED:
-+        data.update({"debugpy._vendored": list(iter_vendored_files())})
++        "debugpy",
++        "debugpy.adapter",
++        "debugpy.common",
++        "debugpy.launcher",
++        "debugpy.server",
++    ]
++    if BUNDLE_DEBUGPY:
++        data.update(
++            {
++                "debugpy._vendored": [
++                    # pydevd extensions must be built before this list can
++                    # be computed properly, so it is populated in the
++                    # overridden build_py.finalize_options().
++                ]
++            }
++        )
 +        packages.append("debugpy._vendored")
-+
+ 
      setuptools.setup(
          name="debugpy",
-         version=versioneer.get_version(),
-@@ -173,20 +206,10 @@ if __name__ == "__main__":
+@@ -176,16 +201,10 @@ if __name__ == "__main__":
              "License :: OSI Approved :: MIT License",
          ],
          package_dir={"": "src"},
--        packages=[
--            "debugpy",
--            "debugpy.adapter",
--            "debugpy.common",
--            "debugpy.launcher",
--            "debugpy.server",
--            "debugpy._vendored",
--        ],
+-        packages=setuptools.find_namespace_packages(where="src", include=["debugpy*"]),
 -        package_data={
 -            "debugpy": ["ThirdPartyNotices.txt"],
--            "debugpy._vendored": list(iter_vendored_files()),
+-            "debugpy._vendored": [
+-                # pydevd extensions must be built before this list can be computed properly,
+-                # so it is populated in the overridden build_py.finalize_options().
+-            ],
 -        },
 +        packages=packages,
 +        package_data=data,
          ext_modules=ExtModules(),
 -        has_ext_modules=lambda: True,
-+        has_ext_modules=lambda: not DEBUGPY_BUNDLING_DISABLED,
++        has_ext_modules=lambda: BUNDLE_DEBUGPY,
          cmdclass=cmds,
          **extras
      )
 diff --git a/src/debugpy/__init__.py b/src/debugpy/__init__.py
-index baa5a7c5..7b7a29aa 100644
+index 975bec79..512219d7 100644
 --- a/src/debugpy/__init__.py
 +++ b/src/debugpy/__init__.py
-@@ -206,6 +206,8 @@ def trace_this_thread(should_trace):
+@@ -24,6 +24,13 @@ __all__ = [  # noqa
  
- __version__ = _version.get_versions()["version"]
+ import sys
  
-+__bundling_disabled__ = False
++try:
++    import debugpy._vendored  # noqa
 +
- # Force absolute path on Python 2.
- __file__ = os.path.abspath(__file__)
++    is_pydevd_bundled = True
++except ImportError:
++    is_pydevd_bundled = False
++
+ assert sys.version_info >= (3, 7), (
+     "Python 3.6 and below is not supported by this version of debugpy; "
+     "use debugpy 1.5.1 or earlier."
+diff --git a/src/debugpy/_vendored/force_pydevd.py b/src/debugpy/_vendored/force_pydevd.py
+index cfd89275..99622f8c 100644
+--- a/src/debugpy/_vendored/force_pydevd.py
++++ b/src/debugpy/_vendored/force_pydevd.py
+@@ -3,7 +3,6 @@
+ # for license information.
  
+ from importlib import import_module
+-import os
+ import warnings
+ 
+ from . import check_modules, prefix_matcher, preimport, vendored
+@@ -17,23 +16,12 @@ if _unvendored:
+     # raise ImportError(msg)
+     warnings.warn(msg + ':\n {}'.format('\n  '.join(_unvendored)))
+ 
+-# If debugpy logging is enabled, enable it for pydevd as well
+-if "DEBUGPY_LOG_DIR" in os.environ:
+-    os.environ[str("PYDEVD_DEBUG")] = str("True")
+-    os.environ[str("PYDEVD_DEBUG_FILE")] = os.environ["DEBUGPY_LOG_DIR"] + str("/debugpy.pydevd.log")
+-
+-# Disable pydevd frame-eval optimizations only if unset, to allow opt-in.
+-if "PYDEVD_USE_FRAME_EVAL" not in os.environ:
+-    os.environ[str("PYDEVD_USE_FRAME_EVAL")] = str("NO")
+-
+ # Constants must be set before importing any other pydevd module
+-# # due to heavy use of "from" in them.
++# due to heavy use of "from" in them.
+ with warnings.catch_warnings():
+     warnings.simplefilter("ignore", category=DeprecationWarning)
+     with vendored('pydevd'):
+         pydevd_constants = import_module('_pydevd_bundle.pydevd_constants')
+-# We limit representation size in our representation provider when needed.
+-pydevd_constants.MAXIMUM_VARIABLE_REPRESENTATION_SIZE = 2 ** 32
+ 
+ # Now make sure all the top-level modules and packages in pydevd are
+ # loaded.  Any pydevd modules that aren't loaded at this point, will
+@@ -50,32 +38,3 @@ with warnings.catch_warnings():
+         'pydevd_plugins',
+         'pydevd',
+     ])
+-
+-# When pydevd is imported it sets the breakpoint behavior, but it needs to be
+-# overridden because by default pydevd will connect to the remote debugger using
+-# its own custom protocol rather than DAP.
+-import pydevd  # noqa
+-import debugpy  # noqa
+-
+-
+-def debugpy_breakpointhook():
+-    debugpy.breakpoint()
+-
+-
+-pydevd.install_breakpointhook(debugpy_breakpointhook)
+-
+-# Ensure that pydevd uses JSON protocol
+-from _pydevd_bundle import pydevd_constants
+-from _pydevd_bundle import pydevd_defaults
+-pydevd_defaults.PydevdCustomization.DEFAULT_PROTOCOL = pydevd_constants.HTTP_JSON_PROTOCOL
+-
+-# Enable some defaults related to debugpy such as sending a single notification when
+-# threads pause and stopping on any exception.
+-pydevd_defaults.PydevdCustomization.DEBUG_MODE = 'debugpy-dap'
+-
+-# This is important when pydevd attaches automatically to a subprocess. In this case, we have to
+-# make sure that debugpy is properly put back in the game for users to be able to use it.
+-pydevd_defaults.PydevdCustomization.PREIMPORT = '%s;%s' % (
+-    os.path.dirname(os.path.dirname(debugpy.__file__)), 
+-    'debugpy._vendored.force_pydevd'
+-)
 diff --git a/src/debugpy/server/__init__.py b/src/debugpy/server/__init__.py
-index e6a1ad66..5f29a87a 100644
+index 42d5367f..a27c6bf4 100644
 --- a/src/debugpy/server/__init__.py
 +++ b/src/debugpy/server/__init__.py
-@@ -4,6 +4,50 @@
- 
- from __future__ import absolute_import, division, print_function, unicode_literals
+@@ -2,6 +2,70 @@
+ # Licensed under the MIT License. See LICENSE in the project root
+ # for license information.
  
++from __future__ import absolute_import, division, print_function, unicode_literals
++
 +from importlib import import_module
 +import os
 +
@@ -139,52 +196,70 @@ index e6a1ad66..5f29a87a 100644
  # that the debugpy-vendored copy of pydevd gets used.
 -import debugpy._vendored.force_pydevd  # noqa
 +import debugpy
-+if debugpy.__bundling_disabled__:
-+    # Do what force_pydevd.py does, but using the system-provided
-+    # pydevd.
 +
-+    # XXX: This is copied here so that the whole '_vendored' directory
-+    # can be deleted when DEBUGPY_BUNDLING_DISABLED is set.
++# If debugpy logging is enabled, enable it for pydevd as well
++if "DEBUGPY_LOG_DIR" in os.environ:
++    os.environ[str("PYDEVD_DEBUG")] = str("True")
++    os.environ[str("PYDEVD_DEBUG_FILE")] = os.environ["DEBUGPY_LOG_DIR"] + str(
++        "/debugpy.pydevd.log"
++    )
 +
-+    # If debugpy logging is enabled, enable it for pydevd as well
-+    if "DEBUGPY_LOG_DIR" in os.environ:
-+        os.environ[str("PYDEVD_DEBUG")] = str("True")
-+        os.environ[str("PYDEVD_DEBUG_FILE")] = \
-+            os.environ["DEBUGPY_LOG_DIR"] + str("/debugpy.pydevd.log")
++# Disable pydevd frame-eval optimizations only if unset, to allow opt-in.
++if "PYDEVD_USE_FRAME_EVAL" not in os.environ:
++    os.environ[str("PYDEVD_USE_FRAME_EVAL")] = str("NO")
 +
-+    # Work around https://github.com/microsoft/debugpy/issues/346.
-+    # Disable pydevd frame-eval optimizations only if unset, to allow opt-in.
-+    if "PYDEVD_USE_FRAME_EVAL" not in os.environ:
-+        os.environ[str("PYDEVD_USE_FRAME_EVAL")] = str("NO")
++BUNDLE_DEBUGPY = bool(os.getenv("BUNDLE_DEBUGPY"))
 +
-+    # Constants must be set before importing any other pydevd module
-+    # due to heavy use of "from" in them.
-+    pydevd_constants = import_module('_pydevd_bundle.pydevd_constants')
-+    # The default pydevd value is 1000.
-+    pydevd_constants.MAXIMUM_VARIABLE_REPRESENTATION_SIZE = 2 ** 32
-+
-+    # When pydevd is imported it sets the breakpoint behavior, but it needs to be
-+    # overridden because by default pydevd will connect to the remote debugger using
-+    # its own custom protocol rather than DAP.
-+    import pydevd   # noqa
-+    import debugpy  # noqa
-+
-+    def debugpy_breakpointhook():
-+        debugpy.breakpoint()
-+
-+    pydevd.install_breakpointhook(debugpy_breakpointhook)
-+
-+    # Ensure that pydevd uses JSON protocol
-+    from _pydevd_bundle import pydevd_constants
-+    from _pydevd_bundle import pydevd_defaults
-+    pydevd_defaults.PydevdCustomization.DEFAULT_PROTOCOL = pydevd_constants.HTTP_JSON_PROTOCOL
++# Constants must be set before importing any other pydevd module
++# due to heavy use of "from" in them.
++if BUNDLE_DEBUGPY:
++    try:
++        import debugpy._vendored.force_pydevd  # noqa
++    except Exception as e:
++        raise e
 +else:
-+    import debugpy._vendored.force_pydevd  # noqa
++    pydevd_constants = import_module("_pydevd_bundle.pydevd_constants")
++
++# We limit representation size in our representation provider when needed.
++pydevd_constants.MAXIMUM_VARIABLE_REPRESENTATION_SIZE = 2**32
++
++# When pydevd is imported it sets the breakpoint behavior, but it needs to be
++# overridden because by default pydevd will connect to the remote debugger using
++# its own custom protocol rather than DAP.
++import pydevd  # noqa
++import debugpy  # noqa
++
++
++def debugpy_breakpointhook():
++    debugpy.breakpoint()
++
++
++pydevd.install_breakpointhook(debugpy_breakpointhook)
++
++# Ensure that pydevd uses JSON protocol
++from _pydevd_bundle import pydevd_constants
++from _pydevd_bundle import pydevd_defaults
++
++pydevd_defaults.PydevdCustomization.DEFAULT_PROTOCOL = (
++    pydevd_constants.HTTP_JSON_PROTOCOL
++)
++
++# Enable some defaults related to debugpy such as sending a single notification when
++# threads pause and stopping on any exception.
++pydevd_defaults.PydevdCustomization.DEBUG_MODE = "debugpy-dap"
++
++# This is important when pydevd attaches automatically to a subprocess. In this case, we have to
++# make sure that debugpy is properly put back in the game for users to be able to use it.
++if not BUNDLE_DEBUGPY:
++    pydevd_defaults.PydevdCustomization.PREIMPORT = "%s;%s" % (
++        os.path.dirname(os.path.dirname(debugpy.__file__)),
++        "debugpy._vendored.force_pydevd",
++    )
 diff --git a/src/debugpy/server/attach_pid_injected.py b/src/debugpy/server/attach_pid_injected.py
-index e6345996..87cfdd53 100644
+index a8df6e1e..06e49600 100644
 --- a/src/debugpy/server/attach_pid_injected.py
 +++ b/src/debugpy/server/attach_pid_injected.py
-@@ -8,6 +8,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera
+@@ -6,6 +6,7 @@
  
  import os
  
@@ -192,7 +267,7 @@ index e6345996..87cfdd53 100644
  
  __file__ = os.path.abspath(__file__)
  _debugpy_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
-@@ -30,25 +31,29 @@ def attach(setup):
+@@ -28,25 +29,29 @@ def attach(setup):
                  def on_critical(msg):
                      print(msg, file=sys.stderr)
  
@@ -205,10 +280,7 @@ index e6345996..87cfdd53 100644
 -                )
 -                assert os.path.exists(pydevd_attach_to_process_path)
 -                sys.path.insert(0, pydevd_attach_to_process_path)
--
--                # NOTE: that it's not a part of the pydevd PYTHONPATH
--                import attach_script
-+                if debugpy.__bundling_disabled__:
++                if not debugpy.is_pydevd_bundled:
 +                    from pydevd_attach_to_process import attach_script
 +                else:
 +                    pydevd_attach_to_process_path = os.path.join(
@@ -220,7 +292,9 @@ index e6345996..87cfdd53 100644
 +                    )
 +                    assert os.path.exists(pydevd_attach_to_process_path)
 +                    sys.path.insert(0, pydevd_attach_to_process_path)
-+
+ 
+-                # NOTE: that it's not a part of the pydevd PYTHONPATH
+-                import attach_script
 +                    # NOTE: that it's not a part of the pydevd PYTHONPATH
 +                    import attach_script
  
@@ -230,25 +304,29 @@ index e6345996..87cfdd53 100644
  
 -                # NOTE: At this point it should be safe to remove this.
 -                sys.path.remove(pydevd_attach_to_process_path)
-+                if not debugpy.__bundling_disabled__:
++                if debugpy.is_pydevd_bundled:
 +                    # NOTE: At this point it should be safe to remove this.
 +                    sys.path.remove(pydevd_attach_to_process_path)
              except:
                  import traceback
  
 diff --git a/tests/tests/test_vendoring.py b/tests/tests/test_vendoring.py
-index dd6c4269..28c03702 100644
+index 9cf44220..3188eb9e 100644
 --- a/tests/tests/test_vendoring.py
 +++ b/tests/tests/test_vendoring.py
-@@ -1,3 +1,8 @@
+@@ -3,6 +3,12 @@
+ # for license information.
+ 
+ 
 +import pytest
 +
 +import debugpy
 +
[email-masked](debugpy.__bundling_disabled__, reason='Bundling disabled')
++
[email-masked](not debugpy.is_pydevd_bundled, reason="pydevd is not bundled")
  def test_vendoring(pyfile):
      @pyfile
      def import_debugpy():
 -- 
-2.34.0
+2.41.0
 
diff --git a/gnu/packages/python-xyz.scm b/gnu/packages/python-xyz.scm
index 1a3c825faab..1468da48999 100644
--- a/gnu/packages/python-xyz.scm
+++ b/gnu/packages/python-xyz.scm
@@ -16801,7 +16801,7 @@ (define-public python-pydevd
 (define-public python-debugpy
   (package
     (name "python-debugpy")
-    (version "1.6.0")
+    (version "1.8.0")
     (source
      (origin
        (method git-fetch)
@@ -16816,7 +16816,7 @@ (define-public python-debugpy
        (patches (search-patches "python-debugpy-unbundle-pydevd.patch"))
        (sha256
         (base32
-         "1dpfzs3p51648i7f3fz8dw5d0vrj39iwn1jhn0226idc02ybyqih"))))
+         "0li02v3d6msr9qp12znzq2h1dki2zsivz6gzi0x06rskrdxxbnd7"))))
     (build-system pyproject-build-system)
     (arguments
      (list
@@ -16848,7 +16848,7 @@ (define-public python-debugpy
             (lambda _
               ;; This adjusts the behavior of debugpy to load pydevd from
               ;; Python site packages.
-              (setenv "DEBUGPY_BUNDLING_DISABLED" "1"))))))
+              (setenv "BUNDLE_DEBUGPY" "0"))))))
     (native-inputs
      ;; See: https://raw.githubusercontent.com/microsoft/debugpy/
      ;;      main/tests/requirements.txt.
-- 
2.41.0