Skip to content

Commit 6c71103

Browse files
committed
Merge remote-tracking branch 'origin/main' into gh-158195-unpin-type-lock
2 parents f31ced0 + 2346981 commit 6c71103

19 files changed

Lines changed: 234 additions & 60 deletions

‎Lib/_pyrepl/_module_completer.py‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ def get_completions(
8383
if not result:
8484
return None
8585
try:
86-
return self.complete(*result, include_values=include_values)
86+
names, values, action = self.complete(
87+
*result, include_values=include_values
88+
)
89+
names = [self._remove_separated_words(line, c) for c in names]
90+
return names, values, action
8791
except Exception:
8892
# Some unexpected error occurred, make it look like
8993
# no completions are available
@@ -336,6 +340,26 @@ def _do_import() -> str | None:
336340

337341
return (prompt, _do_import)
338342

343+
def _remove_separated_words(self, line: str, completion: str) -> str:
344+
"""Remove completion parts imputed as separate words.
345+
346+
Needed because the completer insert any completion provided
347+
by replacing the stem (eg. word) currently imputed, if any.
348+
349+
Examples:
350+
- 'import foo.', 'foo.bar' -> 'foo.bar'
351+
- 'import foo .', 'foo.bar' -> '.bar'
352+
- 'from foo import ', 'bar' -> 'bar'
353+
- 'import x.x .x.', 'x.x.x.x' -> '.x.x'
354+
"""
355+
last_word = line.split(" ")[-1]
356+
if not last_word:
357+
return completion
358+
index = completion.rfind(last_word)
359+
if index > 0:
360+
return completion[index:]
361+
return completion
362+
339363

340364
class ImportParser:
341365
"""

‎Lib/bdb.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,13 @@ def set_trace(self, frame=None):
601601
602602
If frame is not specified, debugging starts from caller's frame.
603603
"""
604+
605+
if self.enterframe is not None:
606+
# If self.enterframe is not None, it means we are already in
607+
# dispatched functions. Tracing is disabled when calling a
608+
# trace function, so we just skip this set_trace() call.
609+
return
610+
604611
self.stop_trace()
605612
if frame is None:
606613
frame = sys._getframe().f_back

‎Lib/test/test_capi/test_tuple.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,10 @@ def test__tuple_resize(self):
327327
self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX)
328328
self.assertRaises(SystemError, resize, a, -1)
329329
self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN)
330+
a = ([1], [2], [3])
331+
self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX)
332+
self.assertRaises(SystemError, resize, a, -1)
333+
self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN)
330334
# refcount > 1
331335
a = (1, 2, 3)
332336
self.assertRaises(SystemError, resize, a, 3, False)

‎Lib/test/test_interpreters/test_channels.py‎

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# Raise SkipTest if subinterpreters not supported.
99
_channels = import_helper.import_module('_interpchannels')
1010
from concurrent import interpreters
11-
from test.support import channels
11+
from test.support import channels, force_not_colorized
1212
from .utils import _run_output, TestBase
1313

1414

@@ -34,6 +34,39 @@ def test_highlevel_reloaded(self):
3434
importlib.reload(channels)
3535
"""));
3636

37+
@force_not_colorized
38+
def test_channel_id_types(self):
39+
# See https://github.com/python/cpython/issues/143376.
40+
code = """\
41+
import _interpchannels
42+
import re
43+
from concurrent import interpreters
44+
45+
class End:
46+
__slots__ = ()
47+
def __new__(cls, chan=None):
48+
return object.__new__(cls)
49+
@property
50+
def _id(self):
51+
return object()
52+
53+
class Send(End): pass
54+
class Recv(End): pass
55+
56+
_interpchannels._register_end_types(Send, Recv)
57+
chan = _interpchannels._channel_id(_interpchannels.create(), _resolve=True)
58+
interp = interpreters.create()
59+
try:
60+
interp.prepare_main(chan=Send(chan))
61+
finally:
62+
interp.close()
63+
"""
64+
65+
out, err = self.assert_python_failure("-c", code)
66+
self.assertEqual(out, '')
67+
errmsg = "TypeError: '_id' attribute must be an _interpchannels.ChannelID object, not object"
68+
self.assertIn(errmsg, err)
69+
3770

3871
class TestChannels(TestBase):
3972

‎Lib/test/test_pdb.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4979,6 +4979,18 @@ def foo():
49794979
stdout, _ = self._run_script(script, commands)
49804980
self.assertIn("42", stdout)
49814981

4982+
def test_nested_set_trace(self):
4983+
# Calling breakpoint() in pdb prompt should just be ignored.
4984+
script = "breakpoint()"
4985+
commands = """
4986+
breakpoint()
4987+
p 40 + 2
4988+
c
4989+
"""
4990+
stdout, stderr = self._run_script(script, commands)
4991+
self.assertIn('42', stdout)
4992+
self.assertEqual(stderr, '')
4993+
49824994
def test_readline_not_imported(self):
49834995
"""GH-138860
49844996
Directly or indirectly importing readline might deadlock a subprocess

‎Lib/test/test_pyrepl/test_pyrepl.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,12 @@ def test_completions(self):
12381238
("from importlib import res\t\n", "from importlib import resources"),
12391239
("from importlib.res\t import a\t\n", "from importlib.resources import abc"),
12401240
("from __phello__ import s\t\n", "from __phello__ import spam"), # frozen module
1241+
("import importlib .res\t\n", "import importlib .resources"),
1242+
("import importlib. res\t\n", "import importlib. resources"),
1243+
("import importlib . res\t\n", "import importlib . resources"),
1244+
("import importlib .metadata.\t\n", "import importlib .metadata.diagnose"),
1245+
("import importlib .metadata .\t\n", "import importlib .metadata .diagnose"),
1246+
("from importlib .resources .a\t\n", "from importlib .resources .abc"),
12411247
)
12421248
for code, expected in cases:
12431249
with self.subTest(code=code):
@@ -1629,8 +1635,13 @@ def test_parse(self):
16291635
('import a.b.c, foo.bar, ', (None, '')),
16301636
('from foo', ('foo', None)),
16311637
('from a.', ('a.', None)),
1638+
('from a .', ('a.', None)),
1639+
('from a .', ('a.', None)),
1640+
('from a .', ('a.', None)),
16321641
('from a.b', ('a.b', None)),
16331642
('from a.b.', ('a.b.', None)),
1643+
('from a. b.', ('a.b.', None)),
1644+
('from a . b .', ('a.b.', None)),
16341645
('from a.b.c', ('a.b.c', None)),
16351646
('from foo import ', ('foo', '')),
16361647
('from foo import a', ('foo', 'a')),

‎Lib/test/test_traceback.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5109,6 +5109,32 @@ def func():
51095109
actual = self.get_suggestion(func)
51105110
self.assertIn("forget to import '_io'", actual)
51115111

5112+
def test_name_error_with_bad_getattr(self):
5113+
class A:
5114+
def __getattr__(self, x):
5115+
spam
5116+
5117+
actual = self.get_suggestion(A(), "eggs")
5118+
self.assertIn("name 'spam' is not defined", actual)
5119+
5120+
def test_name_error_with_bad_getattribute(self):
5121+
5122+
class A:
5123+
def __getattribute__(self, x):
5124+
spam
5125+
5126+
actual = self.get_suggestion(A(), "eggs")
5127+
self.assertIn("name 'spam' is not defined", actual)
5128+
5129+
def test_name_error_with_bad_property(self):
5130+
class A:
5131+
@property
5132+
def eggs(self):
5133+
eggs
5134+
5135+
actual = self.get_suggestion(A(), "eggs")
5136+
self.assertIn("name 'eggs' is not defined", actual)
5137+
51125138

51135139

51145140
class PurePythonSuggestionFormattingTests(

‎Lib/traceback.py‎

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,31 +1954,34 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
19541954
return None
19551955
else:
19561956
assert isinstance(exc_value, NameError)
1957-
# find most recent frame
1958-
if tb is None:
1957+
try:
1958+
# find most recent frame
1959+
if tb is None:
1960+
return None
1961+
while tb.tb_next is not None:
1962+
tb = tb.tb_next
1963+
frame = tb.tb_frame
1964+
d = (
1965+
list(frame.f_locals)
1966+
+ list(frame.f_globals)
1967+
+ list(frame.f_builtins)
1968+
)
1969+
d = [x for x in d if isinstance(x, str)]
1970+
if not_normalized and wrong_name in d:
1971+
return wrong_name
1972+
1973+
# Check first if we are in a method and the instance
1974+
# has the wrong name as attribute
1975+
if 'self' in frame.f_locals:
1976+
self = frame.f_locals['self']
1977+
try:
1978+
has_wrong_name = hasattr(self, wrong_name)
1979+
except Exception:
1980+
has_wrong_name = False
1981+
if has_wrong_name:
1982+
return f"self.{wrong_name}"
1983+
except Exception:
19591984
return None
1960-
while tb.tb_next is not None:
1961-
tb = tb.tb_next
1962-
frame = tb.tb_frame
1963-
d = (
1964-
list(frame.f_locals)
1965-
+ list(frame.f_globals)
1966-
+ list(frame.f_builtins)
1967-
)
1968-
d = [x for x in d if isinstance(x, str)]
1969-
if not_normalized and wrong_name in d:
1970-
return wrong_name
1971-
1972-
# Check first if we are in a method and the instance
1973-
# has the wrong name as attribute
1974-
if 'self' in frame.f_locals:
1975-
self = frame.f_locals['self']
1976-
try:
1977-
has_wrong_name = hasattr(self, wrong_name)
1978-
except Exception:
1979-
has_wrong_name = False
1980-
if has_wrong_name:
1981-
return f"self.{wrong_name}"
19821985

19831986
if not_normalized and wrong_name in d:
19841987
return wrong_name
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash in :c:func:`_PyTuple_Resize` when resizing a non-empty tuple to a
2+
negative or too large size. It now raises :exc:`SystemError` or
3+
:exc:`MemoryError` respectively.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :term:`REPL` completions inserted incorrectly when there was spaces in
2+
import statements.

0 commit comments

Comments
 (0)