Skip to content

Commit 45f295d

Browse files
Merge branch 'python:main' into main
2 parents c5c3f86 + e237b25 commit 45f295d

27 files changed

+265
-81
lines changed

Doc/library/functools.rst

+6-2
Original file line numberDiff line numberDiff line change
@@ -646,8 +646,9 @@ The :mod:`functools` module defines the following functions:
646646
attributes of the wrapper function are updated with the corresponding attributes
647647
from the original function. The default values for these arguments are the
648648
module level constants ``WRAPPER_ASSIGNMENTS`` (which assigns to the wrapper
649-
function's ``__module__``, ``__name__``, ``__qualname__``, ``__annotations__``
650-
and ``__doc__``, the documentation string) and ``WRAPPER_UPDATES`` (which
649+
function's ``__module__``, ``__name__``, ``__qualname__``, ``__annotations__``,
650+
``__type_params__``, and ``__doc__``, the documentation string)
651+
and ``WRAPPER_UPDATES`` (which
651652
updates the wrapper function's ``__dict__``, i.e. the instance dictionary).
652653

653654
To allow access to the original function for introspection and other purposes
@@ -677,6 +678,9 @@ The :mod:`functools` module defines the following functions:
677678
function, even if that function defined a ``__wrapped__`` attribute.
678679
(see :issue:`17482`)
679680

681+
.. versionchanged:: 3.12
682+
The ``__type_params__`` attribute is now copied by default.
683+
680684

681685
.. decorator:: wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
682686

Doc/library/itertools.rst

+5-5
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ loops that truncate the stream.
380380
saved.append(element)
381381
while saved:
382382
for element in saved:
383-
yield element
383+
yield element
384384

385385
Note, this member of the toolkit may require significant auxiliary storage
386386
(depending on the length of the iterable).
@@ -615,10 +615,10 @@ loops that truncate the stream.
615615
This function is roughly equivalent to the following code, except that the
616616
actual implementation does not build up intermediate results in memory::
617617

618-
def product(*args, repeat=1):
618+
def product(*iterables, repeat=1):
619619
# product('ABCD', 'xy') → Ax Ay Bx By Cx Cy Dx Dy
620620
# product(range(2), repeat=3) → 000 001 010 011 100 101 110 111
621-
pools = [tuple(pool) for pool in args] * repeat
621+
pools = [tuple(pool) for pool in iterables] * repeat
622622
result = [[]]
623623
for pool in pools:
624624
result = [x+[y] for x in result for y in pool]
@@ -735,9 +735,9 @@ loops that truncate the stream.
735735
iterables are of uneven length, missing values are filled-in with *fillvalue*.
736736
Iteration continues until the longest iterable is exhausted. Roughly equivalent to::
737737

738-
def zip_longest(*args, fillvalue=None):
738+
def zip_longest(*iterables, fillvalue=None):
739739
# zip_longest('ABCD', 'xy', fillvalue='-') → Ax By C- D-
740-
iterators = [iter(it) for it in args]
740+
iterators = [iter(it) for it in iterables]
741741
num_active = len(iterators)
742742
if not num_active:
743743
return

Doc/library/shutil.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ Directory and files operations
338338
before removing the junction.
339339

340340
.. versionchanged:: 3.11
341-
The *dir_fd* parameter.
341+
Added the *dir_fd* parameter.
342342

343343
.. versionchanged:: 3.12
344344
Added the *onexc* parameter, deprecated *onerror*.

Doc/tools/extensions/pyspecific.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
ISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s'
3434
GH_ISSUE_URI = 'https://github.com/python/cpython/issues/%s'
3535
# Used in conf.py and updated here by python/release-tools/run_release.py
36-
SOURCE_URI = 'https://github.com/python/cpython/tree/3.13/%s'
36+
SOURCE_URI = 'https://github.com/python/cpython/tree/main/%s'
3737

3838
# monkey-patch reST parser to disable alphabetic and roman enumerated lists
3939
from docutils.parsers.rst.states import Body

Lib/bdb.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ def dispatch_return(self, frame, arg):
165165
# The user issued a 'next' or 'until' command.
166166
if self.stopframe is frame and self.stoplineno != -1:
167167
self._set_stopinfo(None, None)
168+
# The previous frame might not have f_trace set, unless we are
169+
# issuing a command that does not expect to stop, we should set
170+
# f_trace
171+
if self.stoplineno != -1:
172+
self._set_caller_tracefunc(frame)
168173
return self.trace_dispatch
169174

170175
def dispatch_exception(self, frame, arg):
@@ -320,15 +325,14 @@ def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False):
320325
self.stoplineno = stoplineno
321326
self._set_trace_opcodes(opcode)
322327

323-
def _set_caller_tracefunc(self):
328+
def _set_caller_tracefunc(self, current_frame):
324329
# Issue #13183: pdb skips frames after hitting a breakpoint and running
325330
# step commands.
326331
# Restore the trace function in the caller (that may not have been set
327332
# for performance reasons) when returning from the current frame.
328-
if self.frame_returning:
329-
caller_frame = self.frame_returning.f_back
330-
if caller_frame and not caller_frame.f_trace:
331-
caller_frame.f_trace = self.trace_dispatch
333+
caller_frame = current_frame.f_back
334+
if caller_frame and not caller_frame.f_trace:
335+
caller_frame.f_trace = self.trace_dispatch
332336

333337
# Derived classes and clients can call the following methods
334338
# to affect the stepping state.
@@ -343,12 +347,10 @@ def set_until(self, frame, lineno=None):
343347

344348
def set_step(self):
345349
"""Stop after one line of code."""
346-
self._set_caller_tracefunc()
347350
self._set_stopinfo(None, None)
348351

349352
def set_stepinstr(self):
350353
"""Stop before the next instruction."""
351-
self._set_caller_tracefunc()
352354
self._set_stopinfo(None, None, opcode=True)
353355

354356
def set_next(self, frame):

Lib/collections/__init__.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ def __getitem__(self, key):
10161016
return self.__missing__(key) # support subclasses that define __missing__
10171017

10181018
def get(self, key, default=None):
1019-
return self[key] if key in self else default
1019+
return self[key] if key in self else default # needs to make use of __contains__
10201020

10211021
def __len__(self):
10221022
return len(set().union(*self.maps)) # reuses stored hash values if possible
@@ -1028,7 +1028,10 @@ def __iter__(self):
10281028
return iter(d)
10291029

10301030
def __contains__(self, key):
1031-
return any(key in m for m in self.maps)
1031+
for mapping in self.maps:
1032+
if key in mapping:
1033+
return True
1034+
return False
10321035

10331036
def __bool__(self):
10341037
return any(self.maps)

Lib/inspect.py

+16-12
Original file line numberDiff line numberDiff line change
@@ -3106,6 +3106,8 @@ def _bind(self, args, kwargs, *, partial=False):
31063106
parameters_ex = ()
31073107
arg_vals = iter(args)
31083108

3109+
pos_only_param_in_kwargs = []
3110+
31093111
while True:
31103112
# Let's iterate through the positional arguments and corresponding
31113113
# parameters
@@ -3126,10 +3128,10 @@ def _bind(self, args, kwargs, *, partial=False):
31263128
break
31273129
elif param.name in kwargs:
31283130
if param.kind == _POSITIONAL_ONLY:
3129-
msg = '{arg!r} parameter is positional only, ' \
3130-
'but was passed as a keyword'
3131-
msg = msg.format(arg=param.name)
3132-
raise TypeError(msg) from None
3131+
# Raise a TypeError once we are sure there is no
3132+
# **kwargs param later.
3133+
pos_only_param_in_kwargs.append(param)
3134+
continue
31333135
parameters_ex = (param,)
31343136
break
31353137
elif (param.kind == _VAR_KEYWORD or
@@ -3211,20 +3213,22 @@ def _bind(self, args, kwargs, *, partial=False):
32113213
format(arg=param_name)) from None
32123214

32133215
else:
3214-
if param.kind == _POSITIONAL_ONLY:
3215-
# This should never happen in case of a properly built
3216-
# Signature object (but let's have this check here
3217-
# to ensure correct behaviour just in case)
3218-
raise TypeError('{arg!r} parameter is positional only, '
3219-
'but was passed as a keyword'. \
3220-
format(arg=param.name))
3221-
32223216
arguments[param_name] = arg_val
32233217

32243218
if kwargs:
32253219
if kwargs_param is not None:
32263220
# Process our '**kwargs'-like parameter
32273221
arguments[kwargs_param.name] = kwargs
3222+
elif pos_only_param_in_kwargs:
3223+
raise TypeError(
3224+
'got some positional-only arguments passed as '
3225+
'keyword arguments: {arg!r}'.format(
3226+
arg=', '.join(
3227+
param.name
3228+
for param in pos_only_param_in_kwargs
3229+
),
3230+
),
3231+
)
32283232
else:
32293233
raise TypeError(
32303234
'got an unexpected keyword argument {arg!r}'.format(

Lib/subprocess.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ def __init__(self, args, bufsize=-1, executable=None,
842842
raise TypeError("bufsize must be an integer")
843843

844844
if stdout is STDOUT:
845-
raise ValueError("STDOUT can only be used for stderr")
845+
raise ValueError("STDOUT can only be used for stderr")
846846

847847
if pipesize is None:
848848
pipesize = -1 # Restore default

Lib/test/datetimetester.py

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from test import support
2424
from test.support import is_resource_enabled, ALWAYS_EQ, LARGEST, SMALLEST
25+
from test.support import warnings_helper
2526

2627
import datetime as datetime_module
2728
from datetime import MINYEAR, MAXYEAR
@@ -2797,6 +2798,7 @@ def test_strptime_single_digit(self):
27972798
newdate = strptime(string, format)
27982799
self.assertEqual(newdate, target, msg=reason)
27992800

2801+
@warnings_helper.ignore_warnings(category=DeprecationWarning)
28002802
def test_strptime_leap_year(self):
28012803
# GH-70647: warns if parsing a format with a day and no year.
28022804
with self.assertRaises(ValueError):

Lib/test/test_builtin.py

+18
Original file line numberDiff line numberDiff line change
@@ -2138,6 +2138,24 @@ def test_bool_notimplemented(self):
21382138
with self.assertRaisesRegex(TypeError, msg):
21392139
not NotImplemented
21402140

2141+
def test_singleton_attribute_access(self):
2142+
for singleton in (NotImplemented, Ellipsis):
2143+
with self.subTest(singleton):
2144+
self.assertIs(type(singleton), singleton.__class__)
2145+
self.assertIs(type(singleton).__class__, type)
2146+
2147+
# Missing instance attributes:
2148+
with self.assertRaises(AttributeError):
2149+
singleton.prop = 1
2150+
with self.assertRaises(AttributeError):
2151+
singleton.prop
2152+
2153+
# Missing class attributes:
2154+
with self.assertRaises(TypeError):
2155+
type(singleton).prop = 1
2156+
with self.assertRaises(AttributeError):
2157+
type(singleton).prop
2158+
21412159

21422160
class TestBreakpoint(unittest.TestCase):
21432161
def setUp(self):

Lib/test/test_inspect/test_inspect.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -5089,15 +5089,30 @@ def test(a_po, b_po, c_po=3, /, foo=42, *, bar=50, **kwargs):
50895089
self.assertEqual(self.call(test, 1, 2, foo=4, bar=5),
50905090
(1, 2, 3, 4, 5, {}))
50915091

5092-
with self.assertRaisesRegex(TypeError, "but was passed as a keyword"):
5093-
self.call(test, 1, 2, foo=4, bar=5, c_po=10)
5092+
self.assertEqual(self.call(test, 1, 2, foo=4, bar=5, c_po=10),
5093+
(1, 2, 3, 4, 5, {'c_po': 10}))
50945094

5095-
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
5096-
self.call(test, 1, 2, c_po=4)
5095+
self.assertEqual(self.call(test, 1, 2, 30, c_po=31, foo=4, bar=5),
5096+
(1, 2, 30, 4, 5, {'c_po': 31}))
50975097

5098-
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
5098+
self.assertEqual(self.call(test, 1, 2, 30, foo=4, bar=5, c_po=31),
5099+
(1, 2, 30, 4, 5, {'c_po': 31}))
5100+
5101+
self.assertEqual(self.call(test, 1, 2, c_po=4),
5102+
(1, 2, 3, 42, 50, {'c_po': 4}))
5103+
5104+
with self.assertRaisesRegex(TypeError, "missing 2 required positional arguments"):
50995105
self.call(test, a_po=1, b_po=2)
51005106

5107+
def without_var_kwargs(c_po=3, d_po=4, /):
5108+
return c_po, d_po
5109+
5110+
with self.assertRaisesRegex(
5111+
TypeError,
5112+
"positional-only arguments passed as keyword arguments: 'c_po, d_po'",
5113+
):
5114+
self.call(without_var_kwargs, c_po=33, d_po=44)
5115+
51015116
def test_signature_bind_with_self_arg(self):
51025117
# Issue #17071: one of the parameters is named "self
51035118
def test(a, self, b):

Lib/test/test_pdb.py

+52
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,58 @@ def test_post_mortem():
14531453
"""
14541454

14551455

1456+
def test_pdb_return_to_different_file():
1457+
"""When pdb returns to a different file, it should not skip if f_trace is
1458+
not already set
1459+
1460+
>>> import pprint
1461+
1462+
>>> class A:
1463+
... def __repr__(self):
1464+
... return 'A'
1465+
1466+
>>> def test_function():
1467+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
1468+
... pprint.pprint(A())
1469+
1470+
>>> reset_Breakpoint()
1471+
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
1472+
... 'b A.__repr__',
1473+
... 'continue',
1474+
... 'return',
1475+
... 'next',
1476+
... 'return',
1477+
... 'return',
1478+
... 'continue',
1479+
... ]):
1480+
... test_function()
1481+
> <doctest test.test_pdb.test_pdb_return_to_different_file[2]>(2)test_function()
1482+
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
1483+
(Pdb) b A.__repr__
1484+
Breakpoint 1 at <doctest test.test_pdb.test_pdb_return_to_different_file[1]>:3
1485+
(Pdb) continue
1486+
> <doctest test.test_pdb.test_pdb_return_to_different_file[1]>(3)__repr__()
1487+
-> return 'A'
1488+
(Pdb) return
1489+
--Return--
1490+
> <doctest test.test_pdb.test_pdb_return_to_different_file[1]>(3)__repr__()->'A'
1491+
-> return 'A'
1492+
(Pdb) next
1493+
> ...pprint.py..._safe_repr()
1494+
-> return rep,...
1495+
(Pdb) return
1496+
--Return--
1497+
> ...pprint.py..._safe_repr()->('A'...)
1498+
-> return rep,...
1499+
(Pdb) return
1500+
--Return--
1501+
> ...pprint.py...format()->('A'...)
1502+
-> return...
1503+
(Pdb) continue
1504+
A
1505+
"""
1506+
1507+
14561508
def test_pdb_skip_modules():
14571509
"""This illustrates the simple case of module skipping.
14581510

0 commit comments

Comments
 (0)