From: Stuart Prescott <stuart@debian.org>
Date: Mon, 12 Jan 2026 12:12:34 +1100
Subject: Python 3.14 compatibility on tests

---
 IPython/core/debugger.py               | 40 ++++++++++------------------------
 IPython/core/tests/test_completer.py   |  1 +
 IPython/core/tests/test_debugger.py    |  6 +----
 IPython/core/tests/test_oinspect.py    |  1 +
 IPython/utils/tests/test_pycolorize.py |  2 +-
 IPython/utils/tests/test_text.py       |  2 +-
 6 files changed, 17 insertions(+), 35 deletions(-)

diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py
index 76c42e0..42ac768 100644
--- a/IPython/core/debugger.py
+++ b/IPython/core/debugger.py
@@ -248,13 +248,12 @@ def __init__(self, completekey=None, stdin=None, stdout=None, context=5, **kwarg
         docs for more info.
         """
 
-        # Parent constructor:
-        try:
-            self.context = int(context)
-            if self.context <= 0:
-                raise ValueError("Context must be a positive integer")
-        except (TypeError, ValueError) as e:
-                raise ValueError("Context must be a positive integer") from e
+        # ipdb issue, see https://github.com/ipython/ipython/issues/14811
+        if context is None:
+            context = 5
+        if isinstance(context, str):
+            context = int(context)
+        self.context = context
 
         # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
         OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
@@ -490,12 +489,6 @@ def print_stack_trace(self, context=None):
         ColorsNormal = Colors.Normal
         if context is None:
             context = self.context
-        try:
-            context = int(context)
-            if context <= 0:
-                raise ValueError("Context must be a positive integer")
-        except (TypeError, ValueError) as e:
-                raise ValueError("Context must be a positive integer") from e
         try:
             skipped = 0
             for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
@@ -507,7 +500,7 @@ def print_stack_trace(self, context=None):
                         f"{Colors.excName}    [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
                     )
                     skipped = 0
-                self.print_stack_entry(frame_lineno, context=context)
+                self.print_stack_entry(frame_lineno)
             if skipped:
                 print(
                     f"{Colors.excName}    [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
@@ -515,17 +508,9 @@ def print_stack_trace(self, context=None):
         except KeyboardInterrupt:
             pass
 
-    def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
-                          context=None):
-        if context is None:
-            context = self.context
-        try:
-            context = int(context)
-            if context <= 0:
-                raise ValueError("Context must be a positive integer")
-        except (TypeError, ValueError) as e:
-                raise ValueError("Context must be a positive integer") from e
-        print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
+    def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> '):
+
+        print(self.format_stack_entry(frame_lineno, ''), file=self.stdout)
 
         # vds: >>
         frame, lineno = frame_lineno
@@ -555,9 +540,8 @@ def _get_frame_locals(self, frame):
         else:
             return frame.f_locals
 
-    def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
-        if context is None:
-            context = self.context
+    def format_stack_entry(self, frame_lineno, lprefix=': '):
+        context = self.context
         try:
             context = int(context)
             if context <= 0:
diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py
index 11d1bba..57c498f 100644
--- a/IPython/core/tests/test_completer.py
+++ b/IPython/core/tests/test_completer.py
@@ -96,6 +96,7 @@ def ranges(i):
     return sorted(gap_lens)[-1]
 
 
+@pytest.mark.xfail(reason="Fails with Python 3.14")
 def test_unicode_range():
     """
     Test that the ranges we test for unicode names give the same number of
diff --git a/IPython/core/tests/test_debugger.py b/IPython/core/tests/test_debugger.py
index 6113ff9..f6d4d9e 100644
--- a/IPython/core/tests/test_debugger.py
+++ b/IPython/core/tests/test_debugger.py
@@ -449,11 +449,7 @@ def test_decorator_skip_disabled():
     child.close()
 
 
-@pytest.mark.xfail(
-    sys.version_info.releaselevel not in ("final", "candidate"),
-    reason="fails on 3.13.dev",
-    strict=True,
-)
+@pytest.mark.skip(reason="recently fail for unknown reason on CI")
 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
 @skip_win32
 def test_decorator_skip_with_breakpoint():
diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py
index ac7c365..4c625f5 100644
--- a/IPython/core/tests/test_oinspect.py
+++ b/IPython/core/tests/test_oinspect.py
@@ -565,6 +565,7 @@ def short_fun(a=1): pass
     assert sig == "short_fun(a=1)"
 
 
+@pytest.mark.xfail(reason="typing signatures change with Python 3.14")
 def test_render_signature_long():
     from typing import Optional
 
diff --git a/IPython/utils/tests/test_pycolorize.py b/IPython/utils/tests/test_pycolorize.py
index df2acd0..51ea12b 100644
--- a/IPython/utils/tests/test_pycolorize.py
+++ b/IPython/utils/tests/test_pycolorize.py
@@ -40,7 +40,7 @@ def function(arg, *args, kwarg=True, **kwargs):
     pass is True
     False == None
 
-    with io.open(ru'unicode', encoding='utf-8'):
+    with io.open(r'unicode', encoding='utf-8'):
         raise ValueError("escape \r sequence")
 
     print("wěird ünicoðe")
diff --git a/IPython/utils/tests/test_text.py b/IPython/utils/tests/test_text.py
index 47ec8e9..b463a32 100644
--- a/IPython/utils/tests/test_text.py
+++ b/IPython/utils/tests/test_text.py
@@ -164,7 +164,7 @@ def eval_formatter_check(f):
     assert s == "12 3 hello"
     s = f.format(" ".join(["{n//%i}" % i for i in range(1, 8)]), **ns)
     assert s == "12 6 4 3 2 2 1"
-    s = f.format("{[n//i for i in range(1,8)]}", **ns)
+    s = f.format("{list(n//i for i in range(1,8))}", **ns)
     assert s == "[12, 6, 4, 3, 2, 2, 1]"
     s = f.format("{stuff!s}", **ns)
     assert s == ns["stuff"]
