Skip to content

Commit dad595d

Browse files
committed
Merge branch 'main' into pr/92078
2 parents 75553a2 + 2762525 commit dad595d

36 files changed

+341
-187
lines changed

Doc/c-api/arg.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,19 @@ small to receive the value.
274274
Convert a Python integer to a C :c:expr:`unsigned long` without
275275
overflow checking.
276276

277+
.. versionchanged:: next
278+
Use :meth:`~object.__index__` if available.
279+
277280
``L`` (:class:`int`) [long long]
278281
Convert a Python integer to a C :c:expr:`long long`.
279282

280283
``K`` (:class:`int`) [unsigned long long]
281284
Convert a Python integer to a C :c:expr:`unsigned long long`
282285
without overflow checking.
283286

287+
.. versionchanged:: next
288+
Use :meth:`~object.__index__` if available.
289+
284290
``n`` (:class:`int`) [:c:type:`Py_ssize_t`]
285291
Convert a Python integer to a C :c:type:`Py_ssize_t`.
286292

Doc/library/socket.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,8 @@ Constants
476476
network interface instead of its name.
477477

478478
.. versionchanged:: 3.14
479-
Added missing ``IP_RECVERR``, ``IPV6_RECVERR``, ``IP_RECVTTL``, and
480-
``IP_RECVORIGDSTADDR`` on Linux.
479+
Added missing ``IP_FREEBIND``, ``IP_RECVERR``, ``IPV6_RECVERR``,
480+
``IP_RECVTTL``, and ``IP_RECVORIGDSTADDR`` on Linux.
481481

482482
.. versionchanged:: 3.14
483483
Added support for ``TCP_QUICKACK`` on Windows platforms when available.

Doc/whatsnew/3.14.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,11 @@ New features
20772077
Adding ``?`` after any format unit makes ``None`` be accepted as a value.
20782078
(Contributed by Serhiy Storchaka in :gh:`112068`.)
20792079

2080+
* The ``k`` and ``K`` formats in :c:func:`PyArg_ParseTuple` and
2081+
similar functions now use :meth:`~object.__index__` if available,
2082+
like all other integer formats.
2083+
(Contributed by Serhiy Storchaka in :gh:`112068`.)
2084+
20802085
* Add macros :c:func:`Py_PACK_VERSION` and :c:func:`Py_PACK_FULL_VERSION` for
20812086
bit-packing Python version numbers.
20822087
(Contributed by Petr Viktorin in :gh:`128629`.)

Lib/_pyrepl/readline.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
# "set_pre_input_hook",
9191
"set_startup_hook",
9292
"write_history_file",
93+
"append_history_file",
9394
# ---- multiline extensions ----
9495
"multiline_input",
9596
]
@@ -453,6 +454,7 @@ def read_history_file(self, filename: str = gethistoryfile()) -> None:
453454
del buffer[:]
454455
if line:
455456
history.append(line)
457+
self.set_history_length(self.get_current_history_length())
456458

457459
def write_history_file(self, filename: str = gethistoryfile()) -> None:
458460
maxlength = self.saved_history_length
@@ -464,6 +466,19 @@ def write_history_file(self, filename: str = gethistoryfile()) -> None:
464466
entry = entry.replace("\n", "\r\n") # multiline history support
465467
f.write(entry + "\n")
466468

469+
def append_history_file(self, filename: str = gethistoryfile()) -> None:
470+
reader = self.get_reader()
471+
saved_length = self.get_history_length()
472+
length = self.get_current_history_length() - saved_length
473+
history = reader.get_trimmed_history(length)
474+
f = open(os.path.expanduser(filename), "a",
475+
encoding="utf-8", newline="\n")
476+
with f:
477+
for entry in history:
478+
entry = entry.replace("\n", "\r\n") # multiline history support
479+
f.write(entry + "\n")
480+
self.set_history_length(saved_length + length)
481+
467482
def clear_history(self) -> None:
468483
del self.get_reader().history[:]
469484

@@ -533,6 +548,7 @@ def insert_text(self, text: str) -> None:
533548
get_current_history_length = _wrapper.get_current_history_length
534549
read_history_file = _wrapper.read_history_file
535550
write_history_file = _wrapper.write_history_file
551+
append_history_file = _wrapper.append_history_file
536552
clear_history = _wrapper.clear_history
537553
get_history_item = _wrapper.get_history_item
538554
remove_history_item = _wrapper.remove_history_item

Lib/_pyrepl/simple_interact.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030
import os
3131
import sys
3232
import code
33+
import warnings
3334

34-
from .readline import _get_reader, multiline_input
35+
from .readline import _get_reader, multiline_input, append_history_file
3536

3637

3738
_error: tuple[type[Exception], ...] | type[Exception]
@@ -144,6 +145,10 @@ def maybe_run_command(statement: str) -> bool:
144145
input_name = f"<python-input-{input_n}>"
145146
more = console.push(_strip_final_indent(statement), filename=input_name, _symbol="single") # type: ignore[call-arg]
146147
assert not more
148+
try:
149+
append_history_file()
150+
except (FileNotFoundError, PermissionError, OSError) as e:
151+
warnings.warn(f"failed to open the history file for writing: {e}")
147152
input_n += 1
148153
except KeyboardInterrupt:
149154
r = _get_reader()

Lib/pdb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1834,7 +1834,7 @@ def do_quit(self, arg):
18341834
reply = 'y'
18351835
self.message('')
18361836
if reply == 'y' or reply == '':
1837-
sys.exit(0)
1837+
sys.exit(1)
18381838
elif reply.lower() == 'n':
18391839
return
18401840

Lib/test/clinic.test.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,7 +1410,7 @@ test_unsigned_long_converter(PyObject *module, PyObject *const *args, Py_ssize_t
14101410
if (nargs < 3) {
14111411
goto skip_optional;
14121412
}
1413-
if (!PyLong_Check(args[2])) {
1413+
if (!PyIndex_Check(args[2])) {
14141414
_PyArg_BadArgument("test_unsigned_long_converter", "argument 3", "int", args[2]);
14151415
goto exit;
14161416
}
@@ -1425,7 +1425,7 @@ test_unsigned_long_converter(PyObject *module, PyObject *const *args, Py_ssize_t
14251425
static PyObject *
14261426
test_unsigned_long_converter_impl(PyObject *module, unsigned long a,
14271427
unsigned long b, unsigned long c)
1428-
/*[clinic end generated code: output=540bb0ba2894e1fe input=f450d94cae1ef73b]*/
1428+
/*[clinic end generated code: output=d74eed227d77a31b input=f450d94cae1ef73b]*/
14291429

14301430

14311431
/*[clinic input]
@@ -1525,7 +1525,7 @@ test_unsigned_long_long_converter(PyObject *module, PyObject *const *args, Py_ss
15251525
if (nargs < 3) {
15261526
goto skip_optional;
15271527
}
1528-
if (!PyLong_Check(args[2])) {
1528+
if (!PyIndex_Check(args[2])) {
15291529
_PyArg_BadArgument("test_unsigned_long_long_converter", "argument 3", "int", args[2]);
15301530
goto exit;
15311531
}
@@ -1542,7 +1542,7 @@ test_unsigned_long_long_converter_impl(PyObject *module,
15421542
unsigned long long a,
15431543
unsigned long long b,
15441544
unsigned long long c)
1545-
/*[clinic end generated code: output=3d69994f618b46bb input=a15115dc41866ff4]*/
1545+
/*[clinic end generated code: output=5ca4e4dfb3db644b input=a15115dc41866ff4]*/
15461546

15471547

15481548
/*[clinic input]

Lib/test/test_asyncio/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from asyncio import base_events
2929
from asyncio import events
3030
from asyncio import format_helpers
31-
from asyncio import futures
3231
from asyncio import tasks
3332
from asyncio.log import logger
3433
from test import support
@@ -104,7 +103,7 @@ def run_until(loop, pred, timeout=support.SHORT_TIMEOUT):
104103
loop.run_until_complete(tasks.sleep(delay))
105104
delay = max(delay * 2, 1.0)
106105
else:
107-
raise futures.TimeoutError()
106+
raise TimeoutError()
108107

109108

110109
def run_once(loop):

Lib/test/test_capi/test_getargs.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,12 +267,12 @@ def test_I(self):
267267
def test_k(self):
268268
from _testcapi import getargs_k
269269
# k returns 'unsigned long', no range checking
270-
# it does not accept float, or instances with __int__
271270
self.assertRaises(TypeError, getargs_k, 3.14)
272-
self.assertRaises(TypeError, getargs_k, Index())
271+
self.assertEqual(99, getargs_k(Index()))
273272
self.assertEqual(0, getargs_k(IndexIntSubclass()))
274273
self.assertRaises(TypeError, getargs_k, BadIndex())
275-
self.assertRaises(TypeError, getargs_k, BadIndex2())
274+
with self.assertWarns(DeprecationWarning):
275+
self.assertEqual(1, getargs_k(BadIndex2()))
276276
self.assertEqual(0, getargs_k(BadIndex3()))
277277
self.assertRaises(TypeError, getargs_k, Int())
278278
self.assertEqual(0, getargs_k(IntSubclass()))
@@ -419,10 +419,11 @@ def test_K(self):
419419
from _testcapi import getargs_K
420420
# K return 'unsigned long long', no range checking
421421
self.assertRaises(TypeError, getargs_K, 3.14)
422-
self.assertRaises(TypeError, getargs_K, Index())
422+
self.assertEqual(99, getargs_K(Index()))
423423
self.assertEqual(0, getargs_K(IndexIntSubclass()))
424424
self.assertRaises(TypeError, getargs_K, BadIndex())
425-
self.assertRaises(TypeError, getargs_K, BadIndex2())
425+
with self.assertWarns(DeprecationWarning):
426+
self.assertEqual(1, getargs_K(BadIndex2()))
426427
self.assertEqual(0, getargs_K(BadIndex3()))
427428
self.assertRaises(TypeError, getargs_K, Int())
428429
self.assertEqual(0, getargs_K(IntSubclass()))
@@ -432,6 +433,7 @@ def test_K(self):
432433

433434
self.assertEqual(ULLONG_MAX, getargs_K(ULLONG_MAX))
434435
self.assertEqual(0, getargs_K(0))
436+
self.assertEqual(ULLONG_MAX, getargs_K(ULLONG_MAX))
435437
self.assertEqual(0, getargs_K(ULLONG_MAX+1))
436438

437439
self.assertEqual(42, getargs_K(42))

Lib/test/test_capi/test_opt.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,23 @@ def testfunc(n):
19231923
self.assertNotIn("_GUARD_TOS_INT", uops)
19241924
self.assertIn("_CALL_LEN", uops)
19251925

1926+
def test_binary_op_subscr_tuple_int(self):
1927+
def testfunc(n):
1928+
x = 0
1929+
for _ in range(n):
1930+
y = (1, 2)
1931+
if y[0] == 1: # _COMPARE_OP_INT + _GUARD_IS_TRUE_POP are removed
1932+
x += 1
1933+
return x
1934+
1935+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
1936+
self.assertEqual(res, TIER2_THRESHOLD)
1937+
self.assertIsNotNone(ex)
1938+
uops = get_opnames(ex)
1939+
self.assertIn("_BINARY_OP_SUBSCR_TUPLE_INT", uops)
1940+
self.assertNotIn("_COMPARE_OP_INT", uops)
1941+
self.assertNotIn("_GUARD_IS_TRUE_POP", uops)
1942+
19261943

19271944
def global_identity(x):
19281945
return x

0 commit comments

Comments
 (0)