user [email protected] usertags 1123355 python3.15 tags 1123355 patch thanks
Hi! While rebuilding the python related packages against the Python 3.15rc2 version I ran into this issue [1]. I have picked a few patches from upstream that take care of the problem: - Upstream commit 886bc9d: Use curframe.f_locals instead of curframe_locals in debugger for newer Python versions [2] - Upstream commit 155fa01: Fix test_functions_with_locals_in_pdb in Python 3.14 [3] Additionally, I had to add one patch of my own, overriding the get_trace function to workaround a recent change in the pdb behaviour. This patch should be shared with upstream in https://github.com/spyder-ide/spyder-kernels/issues/583 And finally, the autopkgtest test named pytest had a hardcoded PYS=python3.13, replacing the use of py3version -s, not sure why that was there, but since we are removing python3.13 from the archive I assume that you don't want it anymore. Using the original py3versions -s call, the autopkgtest is green again. I've applied these fixes in the sandbox [4] to verify that it builds successfully, please consider applying them to support the upcoming 3.15 version. Happy hacking, [1]: https://debusine.debian.net/debian/r-python-python3.15/artifact/4589710/ [2]: https://github.com/spyder-ide/spyder-kernels/commit/886bc9d2c613f96ea9b323ee4a1f7e827c29cc00 [3]: https://github.com/spyder-ide/spyder-kernels/commit/155fa010d96a3436c575cefb0ea6eb313e1c280c [4]: https://debusine.debian.net/debian/r-python-python3.15/ --"UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity."
-- Dennis Ritchie Saludos /\/\ /\ >< `/
From cffff55b9190d23a71d33122eec8ab9d611d26e1 Mon Sep 17 00:00:00 2001 From: "Lumberbot (aka Jack)" <[email protected]> Date: Mon, 8 Jun 2026 01:34:00 +0200 Subject: [PATCH] Backport PR #591 on branch 3.x (PR: Use generic args/kwargs in `SpyderPdb` init method) (#592) --- spyder_kernels/console/tests/test_console_kernel.py | 15 ++++++++++++--- spyder_kernels/customize/spyderpdb.py | 3 +-- 2 files changed, 13 insertions(+), 5 deletions(-) Index: spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py =================================================================== --- spyder-kernels.orig/spyder_kernels/console/tests/test_console_kernel.py +++ spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py @@ -1070,9 +1070,18 @@ def test_functions_with_locals_in_pdb(ke This is a regression test for spyder-ide/spyder-kernels#345 """ pdb_obj = SpyderPdb() - Frame = namedtuple("Frame", ["f_globals"]) - pdb_obj.curframe = Frame(f_globals=kernel.shell.user_ns) - pdb_obj.curframe_locals = kernel.shell.user_ns + + if sys.version_info[:2] >=(3, 14): + Frame = namedtuple("Frame", ["f_globals", "f_locals"]) + pdb_obj.curframe = Frame( + f_globals=kernel.shell.user_ns, + f_locals=kernel.shell.user_ns + ) + else: + Frame = namedtuple("Frame", ["f_globals"]) + pdb_obj.curframe = Frame(f_globals=kernel.shell.user_ns) + pdb_obj.curframe_locals = kernel.shell.user_ns + kernel.shell._namespace_stack = [pdb_obj] # Create a local function. Index: spyder-kernels/spyder_kernels/customize/spyderpdb.py =================================================================== --- spyder-kernels.orig/spyder_kernels/customize/spyderpdb.py +++ spyder-kernels/spyder_kernels/customize/spyderpdb.py @@ -81,8 +81,7 @@ class SpyderPdb(ipyPdb): - Add completion to non-command code. """ - def __init__(self, completekey='tab', stdin=None, stdout=None, - skip=None, nosigint=False): + def __init__(self, *args, **kwargs): """Init Pdb.""" self.curframe_locals = None # Only set to true when calling debugfile
From 886bc9d2c613f96ea9b323ee4a1f7e827c29cc00 Mon Sep 17 00:00:00 2001 From: Nowa Ammerlaan <[email protected]> Date: Fri, 12 Jun 2026 16:56:09 +0200 Subject: [PATCH] spyderpdb.py: replace curframe_locals with curframe.f_locals From the python 3.14 changelog: The undocumented pdb.Pdb.curframe_locals attribute is now a deprecated read-only property, which will be removed in a future version of Python. The low overhead dynamic frame locals access added in Python 3.13 by PEP 667 means the frame locals cache reference previously stored in this attribute is no longer needed. Derived debuggers should access pdb.Pdb.curframe.f_locals directly in Python 3.13 and later versions. Signed-off-by: Nowa Ammerlaan <[email protected]> --- spyder_kernels/console/shell.py | 5 ++- .../console/tests/test_console_kernel.py | 34 ++++++++++++++-------- spyder_kernels/customize/spyderpdb.py | 24 ++++++++++++--- 3 files changed, 46 insertions(+), 17 deletions(-) Index: spyder-kernels/spyder_kernels/console/shell.py =================================================================== --- spyder-kernels.orig/spyder_kernels/console/shell.py +++ spyder-kernels/spyder_kernels/console/shell.py @@ -297,7 +297,10 @@ class SpyderShell(ZMQInteractiveShell): for session in self._namespace_stack[::-1]: if isinstance(session, SpyderPdb) and session.curframe is not None: if frame is None or frame == session.curframe: - return session.curframe_locals + if sys.version_info[:2] <= (3, 12): + return session.curframe_locals + else: + return session.curframe.f_locals elif frame is None and isinstance(session, NamespaceManager): return session.ns_locals Index: spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py =================================================================== --- spyder-kernels.orig/spyder_kernels/console/tests/test_console_kernel.py +++ spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py @@ -975,7 +975,8 @@ def test_comprehensions_with_locals_in_p """ pdb_obj = SpyderPdb() pdb_obj.curframe = inspect.currentframe() - pdb_obj.curframe_locals = pdb_obj.curframe.f_locals + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = pdb_obj.curframe.f_locals kernel.shell._namespace_stack = [pdb_obj] # Create a local variable. @@ -991,7 +992,8 @@ def test_comprehensions_with_locals_in_p assert kernel.get_value('in_globals') is False pdb_obj.curframe = None - pdb_obj.curframe_locals = None + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = None def test_comprehensions_with_locals_in_pdb_2(kernel): @@ -1002,7 +1004,8 @@ def test_comprehensions_with_locals_in_p """ pdb_obj = SpyderPdb() pdb_obj.curframe = inspect.currentframe() - pdb_obj.curframe_locals = pdb_obj.curframe.f_locals + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = pdb_obj.curframe.f_locals kernel.shell._namespace_stack = [pdb_obj] # Create a local variable. @@ -1016,7 +1019,8 @@ def test_comprehensions_with_locals_in_p assert kernel.get_value('res') == [[(1, 3), (1, 4)], [(2, 3), (2, 4)]] pdb_obj.curframe = None - pdb_obj.curframe_locals = None + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = None def test_namespaces_in_pdb(kernel): @@ -1028,7 +1032,8 @@ def test_namespaces_in_pdb(kernel): kernel.shell.user_ns["test"] = 0 pdb_obj = SpyderPdb() pdb_obj.curframe = inspect.currentframe() - pdb_obj.curframe_locals = pdb_obj.curframe.f_locals + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = pdb_obj.curframe.f_locals kernel.shell._namespace_stack = [pdb_obj] # Check adding something to globals works @@ -1051,7 +1056,10 @@ def test_namespaces_in_pdb(kernel): assert not pdb_obj._error_occured # Test locals are visible - pdb_obj.curframe_locals["test4"] = 0 + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals["test4"] = 0 + else: + pdb_obj.curframe.f_locals["test4"] = 0 pdb_obj.default("%timeit test4") assert not pdb_obj._error_occured @@ -1060,7 +1068,8 @@ def test_namespaces_in_pdb(kernel): assert pdb_obj._error_occured pdb_obj.curframe = None - pdb_obj.curframe_locals = None + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = None def test_functions_with_locals_in_pdb(kernel): @@ -1071,7 +1080,7 @@ def test_functions_with_locals_in_pdb(ke """ pdb_obj = SpyderPdb() - if sys.version_info[:2] >=(3, 14): + if sys.version_info[:2] >= (3, 13): Frame = namedtuple("Frame", ["f_globals", "f_locals"]) pdb_obj.curframe = Frame( f_globals=kernel.shell.user_ns, @@ -1100,7 +1109,8 @@ def test_functions_with_locals_in_pdb(ke assert kernel.get_value('zz') == 1 pdb_obj.curframe = None - pdb_obj.curframe_locals = None + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = None def test_functions_with_locals_in_pdb_2(kernel): @@ -1112,7 +1122,8 @@ def test_functions_with_locals_in_pdb_2( baba = 1 # noqa pdb_obj = SpyderPdb() pdb_obj.curframe = inspect.currentframe() - pdb_obj.curframe_locals = pdb_obj.curframe.f_locals + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = pdb_obj.curframe.f_locals kernel.shell._namespace_stack = [pdb_obj] # Create a local function. @@ -1139,7 +1150,8 @@ def test_functions_with_locals_in_pdb_2( assert "baba" not in kernel.get_value('gg') pdb_obj.curframe = None - pdb_obj.curframe_locals = None + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = None def test_locals_globals_in_pdb(kernel): @@ -1149,7 +1161,8 @@ def test_locals_globals_in_pdb(kernel): a = 1 # noqa pdb_obj = SpyderPdb() pdb_obj.curframe = inspect.currentframe() - pdb_obj.curframe_locals = pdb_obj.curframe.f_locals + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = pdb_obj.curframe.f_locals kernel.shell._namespace_stack = [pdb_obj] assert kernel.get_value('a') == 1 @@ -1181,7 +1194,8 @@ def test_locals_globals_in_pdb(kernel): assert kernel.get_value('test') is True pdb_obj.curframe = None - pdb_obj.curframe_locals = None + if sys.version_info[:2] <= (3, 12): + pdb_obj.curframe_locals = None @pytest.mark.flaky(max_runs=3) Index: spyder-kernels/spyder_kernels/customize/spyderpdb.py =================================================================== --- spyder-kernels.orig/spyder_kernels/customize/spyderpdb.py +++ spyder-kernels/spyder_kernels/customize/spyderpdb.py @@ -83,7 +83,8 @@ class SpyderPdb(ipyPdb): def __init__(self, *args, **kwargs): """Init Pdb.""" - self.curframe_locals = None + if sys.version_info[:2] <= (3, 12): + self.curframe_locals = None # Only set to true when calling debugfile self.continue_if_has_breakpoints = False self.pdb_ignore_lib = False @@ -159,7 +160,10 @@ class SpyderPdb(ipyPdb): if cmd == "debug": return self.do_debug(arg) - local_ns = self.curframe_locals + if sys.version_info[:2] >= (3, 13): + local_ns = self.curframe.f_locals + else: + local_ns = self.curframe_locals global_ns = self.curframe.f_globals if self.pdb_use_exclamation_mark: @@ -424,12 +428,22 @@ class SpyderPdb(ipyPdb): if ipython_do_complete: # Make complete call with current frame if self.curframe: - if self.curframe_locals: - Frame = namedtuple("Frame", ["f_locals", "f_globals"]) - frame = Frame(self.curframe_locals, - self.curframe.f_globals) + if sys.version_info[:2] >= (3, 13): + if self.curframe.f_locals: + Frame = namedtuple("Frame", ["f_locals", "f_globals"]) + frame = Frame( + self.curframe.f_locals, self.curframe.f_globals + ) + else: + frame = self.curframe else: - frame = self.curframe + if self.curframe_locals: + Frame = namedtuple("Frame", ["f_locals", "f_globals"]) + frame = Frame( + self.curframe_locals, self.curframe.f_globals + ) + else: + frame = self.curframe self.shell.set_completer_frame(frame) result = await self.shell.kernel._do_complete(code, cursor_pos) # Reset frame
Subject: Allow set_trace to accept generic args and kwargs
In Python 3.14+, pdb.set_trace() calls set_trace(..., commands=commands).
Override set_trace in SpyderPdb to accept *args and **kwargs and forward to pdb.Pdb,
preventing a TypeError when called with commands=None.
---
spyder_kernels/customize/spyderpdb.py | 10 ++++++++++
1 file changed, 10 insertions(+)
Index: spyder-kernels/spyder_kernels/customize/spyderpdb.py
===================================================================
--- spyder-kernels.orig/spyder_kernels/customize/spyderpdb.py
+++ spyder-kernels/spyder_kernels/customize/spyderpdb.py
@@ -265,6 +265,16 @@ class SpyderPdb(ipyPdb):
self.message("\nProgram interrupted. (Use 'cont' to resume).")
self.set_step()
+ def set_trace(self, frame=None, *args, **kwargs):
+ """Start debugging from frame."""
+ if frame is None:
+ frame = sys._getframe().f_back
+ self.initial_frame = frame
+ try:
+ return super(ipyPdb, self).set_trace(frame, *args, **kwargs)
+ except TypeError:
+ return super(ipyPdb, self).set_trace(frame)
+
def set_quit(self):
"""Register that debugger is not tracing."""
self.shell.remove_pdb_session(self)
signature.asc
Description: PGP signature

