10000 Merge branch '3.13' into backport-73ab83b-3.13 · python/cpython@c98cdda · GitHub
[go: up one dir, main page]

Skip to content

Commit c98cdda

Browse files
committed
Merge branch '3.13' into backport-73ab83b-3.13
2 parents f509295 + cd39da7 commit c98cdda

File tree

15 files changed

+174
-16
lines changed

15 files changed

+174
-16
lines changed

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ struct _Py_global_strings {
710710
STRUCT_FOR_ID(sort)
711711
STRUCT_FOR_ID(source)
712712
STRUCT_FOR_ID(source_traceback)
713+
STRUCT_FOR_ID(spam)
713714
STRUCT_FOR_ID(src)
714715
STRUCT_FOR_ID(src_dir_fd)
715716
STRUCT_FOR_ID(stacklevel)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/_pyrepl/_minimal_curses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class error(Exception):
1717
pass
1818

1919

20-
def _find_clib():
20+
def _find_clib() -> str:
2121
trylibs = ["ncursesw", "ncurses", "curses"]
2222

2323
for lib in trylibs:

Lib/_pyrepl/input.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def empty(self) -> bool:
6060

6161

6262
class KeymapTranslator(InputTranslator):
63-
def __init__(self, keymap, verbose=0, invalid_cls=None, character_cls=None):
63+
def __init__(self, keymap, verbose=False, invalid_cls=None, character_cls=None):
6464
self.verbose = verbose
6565
from .keymap import compile_keymap, parse_keys
6666

@@ -110,5 +110,5 @@ def get(self):
110110
else:
111111
return None
112112

113-
def empty(self):
113+
def empty(self) -> bool:
114114
return not self.results

Lib/_pyrepl/pager.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,14 @@ def tty_pager(text: str, title: str = '') -> None:
7676
fd = sys.stdin.fileno()
7777
old = termios.tcgetattr(fd)
7878
tty.setcbreak(fd)
79-
getchar = lambda: sys.stdin.read(1)
8079
has_tty = True
80+
81+
def getchar() -> str:
82+
return sys.stdin.read(1)
83+
8184
except (ImportError, AttributeError, io.UnsupportedOperation):
82-
getchar = lambda: sys.stdin.readline()[:-1][:1]
85+
def getchar() -> str:
86+
return sys.stdin.readline()[:-1][:1]
8387

8488
try:
8589
try:

Lib/_pyrepl/readline.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
from .types import Callback, Completer, KeySpec, CommandName
5050

5151

52+
MoreLinesCallable = Callable[[str], bool]
53+
54+
5255
__all__ = [
5356
"add_history",
5457
"clear_history",
@@ -95,7 +98,7 @@ class ReadlineAlikeReader(historical_reader.HistoricalReader, CompletingReader):
9598

9699
# Instance fields
97100
config: ReadlineConfig
98-
more_lines: Callable[[str], bool] | None = None
101+
more_lines: MoreLinesCallable | None = None
99102

100103
def __post_init__(self) -> None:
101104
super().__post_init__()
@@ -288,7 +291,7 @@ def input(self, prompt: object = "") -> str:
288291
reader.ps1 = str(prompt)
289292
return reader.readline(startup_hook=self.startup_hook)
290293

291-
def multiline_input(self, more_lines, ps1, ps2):
294+
def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> tuple[str, bool]:
292295
"""Read an input on possibly multiple lines, asking for more
293296
lines as long as 'more_lines(unicodetext)' returns an object whose
294297
boolean value is true.

Lib/_pyrepl/unix_console.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,13 @@
4040
from .utils import wlen
4141

4242

43+
TYPE_CHECKING = False
44+
4345
# types
44-
if False:
45-
from typing import IO
46+
if TYPE_CHECKING:
47+
from typing import IO, Literal, overload
48+
else:
49+
overload = lambda func: None
4650

4751

4852
class InvalidTerminal(RuntimeError):
@@ -157,7 +161,13 @@ def __init__(
157161
curses.setupterm(term or None, self.output_fd)
158162
self.term = term
159163

160-
def _my_getstr(cap, optional=0):
164+
@overload
165+
def _my_getstr(cap: str, optional: Literal[False] = False) -> bytes: ...
166+
167+
@overload
168+
def _my_getstr(cap: str, optional: bool) -> bytes | None: ...
169+
170+
def _my_getstr(cap: str, optional: bool = False) -> bytes | None:
161171
r = curses.tigetstr(cap)
162172
if not optional and r is None:
163173
raise InvalidTerminal(
@@ -672,18 +682,18 @@ def __move_y_cuu_cud(self, y):
672682
elif dy < 0:
673683
self.__write_code(self._cuu, -dy)
674684

675-
def __move_x_hpa(self, x):
685+
def __move_x_hpa(self, x: int) -> None:
676686
if x != self.__posxy[0]:
677687
self.__write_code(self._hpa, x)
678688

679-
def __move_x_cub1_cuf1(self, x):
689+
def __move_x_cub1_cuf1(self, x: int) -> None:
680690
dx = x - self.__posxy[0]
681691
if dx > 0:
682692
self.__write_code(self._cuf1 * dx)
683693
elif dx < 0:
684694
self.__write_code(self._cub1 * (-dx))
685695

686-
def __move_x_cub_cuf(self, x):
696+
def __move_x_cub_cuf(self, x: int) -> None:
687697
dx = x - self.__posxy[0]
688698
if dx > 0:
689699
self.__write_code(self._cuf, dx)

Lib/test/test_capi/test_getargs.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
import sys
55
from test import support
66
from test.support import import_helper
7+
from test.support import script_helper
78
from test.support import warnings_helper
89
# Skip this test if the _testcapi module isn't available.
910
_testcapi = import_helper.import_module('_testcapi')
1011
from _testcapi import getargs_keywords, getargs_keyword_only
1112

13+
try:
14+
import _testinternalcapi
15+
except ImportError:
16+
_testinternalcapi = NULL
17+
1218
# > How about the following counterproposal. This also changes some of
1319
# > the other format codes to be a little more regular.
1420
# >
@@ -1346,6 +1352,33 @@ def test_nested_tuple(self):
13461352
"argument 1 must be sequence of length 1, not 0"):
13471353
parse(((),), {}, '(' + f + ')', ['a'])
13481354

1355+
@unittest.skipIf(_testinternalcapi is None, 'needs _testinternalcapi')
1356+
def test_gh_119213(self):
1357+
rc, out, err = script_helper.assert_python_ok("-c", """if True:
1358+
from test import support
1359+
script = '''if True:
1360+
import _testinternalcapi
1361+
_testinternalcapi.gh_119213_getargs(spam='eggs')
1362+
'''
1363+
config = dict(
1364+
allow_fork=False,
1365+
allow_exec=False,
1366+
allow_threads=True,
1367+
allow_daemon_threads=False,
1368+
use_main_obmalloc=False,
1369+
gil=2,
1370+
check_multi_interp_extensions=True,
1371+
)
1372+
rc = support.run_in_subinterp_with_config(script, **config)
1373+
assert rc == 0
1374+
1375+
# The crash is different if the interpreter was not destroyed first.
1376+
#interpid = _testinternalcapi.create_interpreter()
1377+
#rc = _testinternalcapi.exec_interpreter(interpid, script)
1378+
#assert rc == 0
1379+
""")
1380+
self.assertEqual(rc, 0)
1381+
13491382

13501383
if __name__ == "__main__":
13511384
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Non-builtin modules built with argument clinic were crashing if used in a
2+
subinterpreter before the main interpreter. The objects that were causing
3+
the problem by leaking between interpreters carelessly have been fixed.

Modules/_testinternalcapi.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,25 @@ has_inline_values(PyObject *self, PyObject *obj)
20062006
Py_RETURN_FALSE;
20072007
}
20082008

2009+
2010+
/*[clinic input]
2011+
gh_119213_getargs
2012+
2013+
spam: object = None
2014+
2015+
Test _PyArg_Parser.kwtuple
2016+
[clinic start generated code]*/
2017+
2018+
static PyObject *
2019+
gh_119213_getargs_impl(PyObject *module, PyObject *spam)
2020+
/*[clinic end generated code: output=d8d9c95d5b446802 input=65ef47511da80fc2]*/
2021+
{
2022+
// It must never have been called in the main interprer
2023+
assert(!_Py_IsMainInterpreter(PyInterpreterState_Get()));
2024+
return Py_NewRef(spam);
2025+
}
2026+
2027+
20092028
static PyMethodDef module_functions[] = {
20102029
{"get_configs", get_configs, METH_NOARGS},
20112030
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
@@ -2096,6 +2115,7 @@ static PyMethodDef module_functions[] = {
20962115
#ifdef _Py_TIER2
20972116
{"uop_symbols_test", _Py_uop_symbols_test, METH_NOARGS},
20982117
#endif
2118+
GH_119213_GETARGS_METHODDEF
20992119
{NULL, NULL} /* sentinel */
21002120
};
21012121

Modules/clinic/_testinternalcapi.c.h

Lines changed: 61 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/getargs.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "pycore_dict.h" // _PyDict_HasOnlyStringKeys()
88
#include "pycore_modsupport.h" // export _PyArg_NoKeywords()
99
#include "pycore_pylifecycle.h" // _PyArg_Fini
10+
#include "pycore_pystate.h" // _Py_IsMainInterpreter()
1011
#include "pycore_tuple.h" // _PyTuple_ITEMS()
1112
#include "pycore_pyerrors.h" // _Py_CalculateSuggestions()
1213

@@ -1947,7 +1948,23 @@ _parser_init(void *arg)
19471948
int owned;
19481949
PyObject *kwtuple = parser->kwtuple;
19491950
if (kwtuple == NULL) {
1951+
/* We may temporarily switch to the main interpreter to avoid
1952+
* creating a tuple that could outlive its owning interpreter. */
1953+
PyThreadState *save_tstate = NULL;
1954+
PyThreadState *temp_tstate = NULL;
1955+
if (!_Py_IsMainInterpreter(PyInterpreterState_Get())) {
1956+
temp_tstate = PyThreadState_New(_PyInterpreterState_Main());
1957+
if (temp_tstate == NULL) {
1958+
return -1;
1959+
}
1960+
save_tstate = PyThreadState_Swap(temp_tstate);
1961+
}
19501962
kwtuple = new_kwtuple(keywords, len, pos);
1963+
if (temp_tstate != NULL) {
1964+
PyThreadState_Clear(temp_tstate);
1965+
(void)PyThreadState_Swap(save_tstate);
1966+
PyThreadState_Delete(temp_tstate);
1967+
}
19511968
if (kwtuple == NULL) {
19521969
return -1;
19531970
}
@@ -1969,8 +1986,8 @@ _parser_init(void *arg)
19691986
parser->next = _Py_atomic_load_ptr(&_PyRuntime.getargs.static_parsers);
19701987
do {
19711988
// compare-exchange updates parser->next on failure
1972-
} while (_Py_atomic_compare_exchange_ptr(&_PyRuntime.getargs.static_parsers,
1973-
&parser->next, parser));
1989+
} while (!_Py_atomic_compare_exchange_ptr(&_PyRuntime.getargs.static_parsers,
1990+
&parser->next, parser));
19741991
return 0;
19751992
}
19761993

Tools/clinic/libclinic/parse_args.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ def declare_parser(
5151
#endif
5252
"""
5353
else:
54+
# XXX Why do we not statically allocate the tuple
55+
# for non-builtin modules?
5456
declarations = """
5557
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
5658

0 commit comments

Comments
 (0)
0