Skip to content

Commit b7617c8

Browse files
Merge branch 'main' into allow_initial_keyword_reduce
2 parents 2b57bd0 + c35b33b commit b7617c8

28 files changed

+162
-93
lines changed

Doc/library/turtle.rst

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,9 +2778,6 @@ Changes since Python 3.0
27782778
:func:`Screen.numinput <numinput>`. These pop up input dialogs and return
27792779
strings and numbers respectively.
27802780

2781-
- Two example scripts :file:`tdemo_nim.py` and :file:`tdemo_round_dance.py`
2782-
have been added to the :file:`Lib/turtledemo` directory.
2783-
27842781

27852782
.. doctest::
27862783
:skipif: _tkinter is None

InternalDocs/garbage_collector.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Starting in version 3.13, CPython contains two GC implementations:
5656
performing a collection for thread safety.
5757

5858
Both implementations use the same basic algorithms, but operate on different
59-
data structures. The the section on
59+
data structures. See the section on
6060
[Differences between GC implementations](#Differences-between-GC-implementations)
6161
for the details.
6262

Lib/annotationlib.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Format(enum.IntEnum):
4545
"__globals__",
4646
"__owner__",
4747
"__cell__",
48+
"__stringifier_dict__",
4849
)
4950

5051

@@ -268,7 +269,16 @@ class _Stringifier:
268269
# instance of the other in place.
269270
__slots__ = _SLOTS
270271

271-
def __init__(self, node, globals=None, owner=None, is_class=False, cell=None):
272+
def __init__(
273+
self,
274+
node,
275+
globals=None,
276+
owner=None,
277+
is_class=False,
278+
cell=None,
279+
*,
280+
stringifier_dict,
281+
):
272282
# Either an AST node or a simple str (for the common case where a ForwardRef
273283
# represent a single name).
274284
assert isinstance(node, (ast.AST, str))
@@ -283,6 +293,7 @@ def __init__(self, node, globals=None, owner=None, is_class=False, cell=None):
283293
self.__globals__ = globals
284294
self.__cell__ = cell
285295
self.__owner__ = owner
296+
self.__stringifier_dict__ = stringifier_dict
286297

287298
def __convert_to_ast(self, other):
288299
if isinstance(other, _Stringifier):
@@ -317,9 +328,15 @@ def __get_ast(self):
317328
return node
318329

319330
def __make_new(self, node):
320-
return _Stringifier(
321-
node, self.__globals__, self.__owner__, self.__forward_is_class__
331+
stringifier = _Stringifier(
332+
node,
333+
self.__globals__,
334+
self.__owner__,
335+
self.__forward_is_class__,
336+
stringifier_dict=self.__stringifier_dict__,
322337
)
338+
self.__stringifier_dict__.stringifiers.append(stringifier)
339+
return stringifier
323340

324341
# Must implement this since we set __eq__. We hash by identity so that
325342
# stringifiers in dict keys are kept separate.
@@ -462,6 +479,7 @@ def __missing__(self, key):
462479
globals=self.globals,
463480
owner=self.owner,
464481
is_class=self.is_class,
482+
stringifier_dict=self,
465483
)
466484
self.stringifiers.append(fwdref)
467485
return fwdref
@@ -516,7 +534,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
516534
name = freevars[i]
517535
else:
518536
name = "__cell__"
519-
fwdref = _Stringifier(name)
537+
fwdref = _Stringifier(name, stringifier_dict=globals)
520538
new_closure.append(types.CellType(fwdref))
521539
closure = tuple(new_closure)
522540
else:
@@ -573,6 +591,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
573591
owner=owner,
574592
globals=annotate.__globals__,
575593
is_class=is_class,
594+
stringifier_dict=globals,
576595
)
577596
globals.stringifiers.append(fwdref)
578597
new_closure.append(types.CellType(fwdref))
@@ -591,6 +610,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
591610
result = func(Format.VALUE)
592611
for obj in globals.stringifiers:
593612
obj.__class__ = ForwardRef
613+
obj.__stringifier_dict__ = None # not needed for ForwardRef
594614
if isinstance(obj.__ast_node__, str):
595615
obj.__arg__ = obj.__ast_node__
596616
obj.__ast_node__ = None

Lib/pdb.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def find_first_executable_line(code):
118118
return code.co_firstlineno
119119

120120
def find_function(funcname, filename):
121-
cre = re.compile(r'def\s+%s\s*[(]' % re.escape(funcname))
121+
cre = re.compile(r'def\s+%s(\s*\[.+\])?\s*[(]' % re.escape(funcname))
122122
try:
123123
fp = tokenize.open(filename)
124124
except OSError:
@@ -138,9 +138,12 @@ def find_function(funcname, filename):
138138

139139
if funcdef:
140140
try:
141-
funccode = compile(funcdef, filename, 'exec').co_consts[0]
141+
code = compile(funcdef, filename, 'exec')
142142
except SyntaxError:
143143
continue
144+
# We should always be able to find the code object here
145+
funccode = next(c for c in code.co_consts if
146+
isinstance(c, CodeType) and c.co_name == funcname)
144147
lineno_offset = find_first_executable_line(funccode)
145148
return funcname, filename, funcstart + lineno_offset - 1
146149
return None

Lib/test/test_annotationlib.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,42 @@ def f(x: int, y: doesntexist):
8080
fwdref.evaluate()
8181
self.assertEqual(fwdref.evaluate(globals={"doesntexist": 1}), 1)
8282

83+
def test_nonexistent_attribute(self):
84+
def f(
85+
x: some.module,
86+
y: some[module],
87+
z: some(module),
88+
alpha: some | obj,
89+
beta: +some,
90+
gamma: some < obj,
91+
):
92+
pass
93+
94+
anno = annotationlib.get_annotations(f, format=Format.FORWARDREF)
95+
x_anno = anno["x"]
96+
self.assertIsInstance(x_anno, ForwardRef)
97+
self.assertEqual(x_anno, ForwardRef("some.module"))
98+
99+
y_anno = anno["y"]
100+
self.assertIsInstance(y_anno, ForwardRef)
101+
self.assertEqual(y_anno, ForwardRef("some[module]"))
102+
103+
z_anno = anno["z"]
104+
self.assertIsInstance(z_anno, ForwardRef)
105+
self.assertEqual(z_anno, ForwardRef("some(module)"))
106+
107+
alpha_anno = anno["alpha"]
108+
self.assertIsInstance(alpha_anno, ForwardRef)
109+
self.assertEqual(alpha_anno, ForwardRef("some | obj"))
110+
111+
beta_anno = anno["beta"]
112+
self.assertIsInstance(beta_anno, ForwardRef)
113+
self.assertEqual(beta_anno, ForwardRef("+some"))
114+
115+
gamma_anno = anno["gamma"]
116+
self.assertIsInstance(gamma_anno, ForwardRef)
117+
self.assertEqual(gamma_anno, ForwardRef("some < obj"))
118+
83119

84120
class TestSourceFormat(unittest.TestCase):
85121
def test_closure(self):
@@ -91,6 +127,16 @@ def inner(arg: x):
91127
anno = annotationlib.get_annotations(inner, format=Format.STRING)
92128
self.assertEqual(anno, {"arg": "x"})
93129

130+
def test_closure_undefined(self):
131+
if False:
132+
x = 0
133+
134+
def inner(arg: x):
135+
pass
136+
137+
anno = annotationlib.get_annotations(inner, format=Format.STRING)
138+
self.assertEqual(anno, {"arg": "x"})
139+
94140
def test_function(self):
95141
def f(x: int, y: doesntexist):
96142
pass

Lib/test/test_ctypes/test_generated_structs.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ class Packed3(Structure):
135135

136136
@register()
137137
class Packed4(Structure):
138+
def _maybe_skip():
139+
# `_pack_` enables MSVC-style packing, but keeps platform-specific
140+
# alignments.
141+
# The C code we generate for GCC/clang currently uses
142+
# `__attribute__((ms_struct))`, which activates MSVC layout *and*
143+
# alignments, that is, sizeof(basic type) == alignment(basic type).
144+
# On a Pentium, int64 is 32-bit aligned, so the two won't match.
145+
# The expected behavior is instead tested in
146+
# StructureTestCase.test_packed, over in test_structures.py.
147+
if sizeof(c_int64) != alignment(c_int64):
148+
raise unittest.SkipTest('cannot test on this platform')
149+
138150
_fields_ = [('a', c_int8), ('b', c_int64)]
139151
_pack_ = 8
140152

@@ -436,6 +448,8 @@ def test_generated_data(self):
436448
"""
437449
for name, cls in TESTCASES.items():
438450
with self.subTest(name=name):
451+
if _maybe_skip := getattr(cls, '_maybe_skip', None):
452+
_maybe_skip()
439453
expected = iter(_ctypes_test.get_generated_test_data(name))
440454
expected_name = next(expected)
441455
if expected_name is None:

Lib/test/test_pdb.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,42 @@ def test_pdb_breakpoint_commands():
363363
4
364364
"""
365365

366+
def test_pdb_breakpoint_on_annotated_function_def():
367+
"""Test breakpoints on function definitions with annotation.
368+
369+
>>> def foo[T]():
370+
... return 0
371+
372+
>>> def bar() -> int:
373+
... return 0
374+
375+
>>> def foobar[T]() -> int:
376+
... return 0
377+
378+
>>> reset_Breakpoint()
379+
380+
>>> def test_function():
381+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
382+
... pass
383+
384+
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
385+
... 'break foo',
386+
... 'break bar',
387+
... 'break foobar',
388+
... 'continue',
389+
... ]):
390+
... test_function()
391+
> <doctest test.test_pdb.test_pdb_breakpoint_on_annotated_function_def[4]>(2)test_function()
392+
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
393+
(Pdb) break foo
394+
Breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_on_annotated_function_def[0]>:2
395+
(Pdb) break bar
396+
Breakpoint 2 at <doctest test.test_pdb.test_pdb_breakpoint_on_annotated_function_def[1]>:2
397+
(Pdb) break foobar
398+
Breakpoint 3 at <doctest test.test_pdb.test_pdb_breakpoint_on_annotated_function_def[2]>:2
399+
(Pdb) continue
400+
"""
401+
366402
def test_pdb_commands():
367403
"""Test the commands command of pdb.
368404

Lib/turtledemo/bytedesign.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
""" turtle-example-suite:
2-
3-
tdemo_bytedesign.py
1+
"""turtledemo/bytedesign.py
42
53
An example adapted from the example-suite
64
of PythonCard's turtle graphics.

Lib/turtledemo/chaos.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
# File: tdemo_chaos.py
2-
# Author: Gregor Lingl
3-
# Date: 2009-06-24
4-
5-
# A demonstration of chaos
1+
"""turtledemo/chaos.py
62
3+
A demonstration of chaos.
4+
"""
75
from turtle import *
86

97
N = 80

Lib/turtledemo/clock.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
""" turtle-example-suite:
2-
3-
turtledemo/clock.py
1+
"""turtledemo/clock.py
42
53
Enhanced clock-program, showing date
6-
and time
7-
------------------------------------
8-
Press STOP to exit the program!
9-
------------------------------------
4+
and time.
105
"""
116
from turtle import *
127
from datetime import datetime

0 commit comments

Comments
 (0)