Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,14 @@ jobs:
- os: ubuntu-latest
python-version: "3.11"
deps: test
# Tests latest development Python version
# Tests latest released Python version
- os: ubuntu-latest
python-version: "3.13"
deps: test
# Tests latest development Python version
- os: ubuntu-latest
python-version: "3.14-dev"
deps: test
# Installing optional dependencies stuff takes ages on PyPy
# - os: ubuntu-latest
# python-version: "pypy-3.11"
Expand Down
22 changes: 21 additions & 1 deletion IPython/core/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,26 @@ def set_trace(self, frame=None):
self.initial_frame = frame
return super().set_trace(frame)

def get_stack(self, *args, **kwargs):
stack, pos = super().get_stack(*args, **kwargs)
if len(stack) >= 0 and self._is_internal_frame(stack[0][0]):
stack.pop(0)
pos -= 1
return stack, pos

def _is_internal_frame(self, frame):
"""Determine if this frame should be skipped as internal"""
filename = frame.f_code.co_filename

# Skip bdb.py runcall and internal operations
if filename.endswith("bdb.py"):
func_name = frame.f_code.co_name
# Skip internal bdb operations but allow breakpoint hits
if func_name in ("runcall", "run", "runeval"):
return True

return False

def _hidden_predicate(self, frame):
"""
Given a frame return whether it it should be hidden or not by IPython.
Expand Down Expand Up @@ -754,7 +774,7 @@ def print_list_lines(self, filename: str, first: int, last: int) -> None:
bp,
(Token.LinenoEm, num),
(Token, " "),
# TODO: invsetigate Toke.Line here
# TODO: investigate Token.Line here
(Token, colored_line),
]
)
Expand Down
2 changes: 1 addition & 1 deletion IPython/extensions/deduperreload/deduperreload.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def _gather_children(
result.inplace_merge(
cls._gather_children(handler.body, parent_node)
)
elif not isinstance(ast_elt, (ast.Ellipsis, ast.Pass)):
elif not isinstance(ast_elt, (ast.Constant, ast.Pass)):
if cls.is_constexpr_assign(ast_elt, parent_node):
assert isinstance(ast_elt, (ast.Assign, ast.AnnAssign))
targets = (
Expand Down
6 changes: 5 additions & 1 deletion IPython/utils/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,10 @@ class EvalFormatter(Formatter):
standard string formatting), so if slicing is required, you must explicitly
create a slice.

Note that on Python 3.14+ this version interprets `[]` as indexing operator
so you need to use generators instead of list comprehensions, for example:
`list(i for i in range(10))`.

This is to be used in templating cases, such as the parallel batch
script templates, where simple arithmetic on arguments is useful.

Expand All @@ -455,7 +459,7 @@ class EvalFormatter(Formatter):
"""

def get_field(self, name: str, args: Any, kwargs: Any) -> Tuple[Any, str]:
v = eval(name, kwargs)
v = eval(name, kwargs, kwargs)
return v, name

#XXX: As of Python 3.4, the format string parsing no longer splits on a colon
Expand Down
2 changes: 1 addition & 1 deletion tests/test_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def test_unicode_range():
assert len_exp == len_test, message

# fail if new unicode symbols have been added.
assert len_exp <= 143668, message
assert len_exp <= 148853, message


@contextmanager
Expand Down
11 changes: 5 additions & 6 deletions tests/test_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,11 +485,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():
Expand Down Expand Up @@ -535,7 +531,10 @@ def test_decorator_skip_with_breakpoint():

# From 3.13, set_trace()/breakpoint() stop on the line where they're
# called, instead of the next line.
if sys.version_info >= (3, 13):
if sys.version_info >= (3, 14):
child.expect_exact(" 46 ipdb.set_trace()")
extra_step = [("step", "--> 47 bar(3, 4)")]
elif sys.version_info >= (3, 13):
child.expect_exact("--> 46 ipdb.set_trace()")
extra_step = [("step", "--> 47 bar(3, 4)")]
else:
Expand Down
2 changes: 2 additions & 0 deletions tests/test_oinspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,5 +600,7 @@ def long_function(
let_us_make_sure_this_is_looong: Optional[str] = None,
) -> bool\
"""
if sys.version_info >= (3, 14):
expected = expected.replace("Optional[str]", "str | None")

assert sig == expected
2 changes: 1 addition & 1 deletion tests/test_pycolorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def function(arg, *args, kwarg=True, **kwargs):
pass is True
False == None

with io.open(ru'unicode', encoding='utf-8'):
with io.open(rf'unicode {1}', encoding='utf-8'):
raise ValueError("escape \r sequence")

print("wěird ünicoðe")
Expand Down
12 changes: 11 additions & 1 deletion tests/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# -----------------------------------------------------------------------------

import os
import sys
import math
import random

Expand All @@ -27,13 +28,19 @@
# -----------------------------------------------------------------------------


def eval_formatter_list_comprehension_check(f):
ns = dict(n=12)
s = f.format("{[n//i for i in range(1,8)]}", **ns)
assert s == "[12, 6, 4, 3, 2, 2, 1]"


def eval_formatter_check(f):
ns = dict(n=12, pi=math.pi, stuff="hello there", os=os, u="café", b="café")
s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
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"]
Expand Down Expand Up @@ -78,12 +85,15 @@ def test_eval_formatter():
f = text.EvalFormatter()
eval_formatter_check(f)
eval_formatter_no_slicing_check(f)
if sys.version_info < (3, 14):
eval_formatter_list_comprehension_check(f)


def test_full_eval_formatter():
f = text.FullEvalFormatter()
eval_formatter_check(f)
eval_formatter_slicing_check(f)
eval_formatter_list_comprehension_check(f)


def test_dollar_formatter():
Expand Down
Loading