From 5e9e50612eb27aef8f74a0ccc234e5cfae50c4d7 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Fri, 4 Oct 2024 02:00:32 +0200 Subject: [PATCH 001/247] gh-124613: Deactivate perf support in tests if the jit is set (#124794) gh-124613: Deactivate the JIT during perf tests Signed-off-by: Pablo Galindo --- Lib/test/test_perf_profiler.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 672851425ffb53..b55d441759eb69 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -23,15 +23,6 @@ raise unittest.SkipTest("test crash randomly on ASAN/MSAN/UBSAN build") -def is_jit_build(): - cflags = (sysconfig.get_config_var("PY_CORE_CFLAGS") or '') - return "_Py_JIT" in cflags - - -if is_jit_build(): - raise unittest.SkipTest("Perf support is not available in JIT builds") - - def supports_trampoline_profiling(): perf_trampoline = sysconfig.get_config_var("PY_HAVE_PERF_TRAMPOLINE") if not perf_trampoline: @@ -71,11 +62,13 @@ def baz(): """ with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) + env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, "-Xperf", script], text=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, + env=env, ) as process: stdout, stderr = process.communicate() @@ -139,11 +132,13 @@ def baz(): """ with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) + env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, "-Xperf", script], text=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, + env=env, ) as process: stdout, stderr = process.communicate() @@ -188,11 +183,13 @@ def baz(): """ with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) + env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, script], text=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, + env=env, ) as process: stdout, stderr = process.communicate() @@ -269,8 +266,9 @@ def perf_command_works(): "-c", 'print("hello")', ) + env = {**os.environ, "PYTHON_JIT": "0"} stdout = subprocess.check_output( - cmd, cwd=script_dir, text=True, stderr=subprocess.STDOUT + cmd, cwd=script_dir, text=True, stderr=subprocess.STDOUT, env=env ) except (subprocess.SubprocessError, OSError): return False @@ -282,11 +280,10 @@ def perf_command_works(): def run_perf(cwd, *args, use_jit=False, **env_vars): + env = os.environ.copy() if env_vars: - env = os.environ.copy() env.update(env_vars) - else: - env = None + env["PYTHON_JIT"] = "0" output_file = cwd + "/perf_output.perf" if not use_jit: base_cmd = ("perf", "record", "-g", "--call-graph=fp", "-o", output_file, "--") @@ -455,11 +452,13 @@ def compile_trampolines_for_all_functions(): with temp_dir() as script_dir: script = make_script(script_dir, "perftest", code) + env = {**os.environ, "PYTHON_JIT": "0"} with subprocess.Popen( [sys.executable, "-Xperf", script], universal_newlines=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, + env=env, ) as process: stdout, stderr = process.communicate() From f66d785861d3a210f1b6b14ebd129728b24f95bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:58:34 +0200 Subject: [PATCH 002/247] gh-123961: Convert `curses.window` static type into a heap type (#124934) --- ...-10-03-14-06-08.gh-issue-123961.uwJQTY.rst | 3 + Modules/_cursesmodule.c | 181 +++++++++++------- Modules/clinic/_cursesmodule.c.h | 10 +- 3 files changed, 120 insertions(+), 74 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst diff --git a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst new file mode 100644 index 00000000000000..40c26e15a2de92 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst @@ -0,0 +1,3 @@ +Convert the :ref:`curses.window ` static type exposed +by the :c:macro:`!PyCursesWindow_Type` macro in ``Include/py_curses.h`` to a +:ref:`heap type `. Patch by Bénédikt Tran. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index f13731f6f3660c..61b65675375547 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -105,8 +105,9 @@ static const char PyCursesVersion[] = "2.2"; #endif #include "Python.h" -#include "pycore_long.h" // _PyLong_GetZero() -#include "pycore_structseq.h" // _PyStructSequence_NewType() +#include "pycore_capsule.h" // _PyCapsule_SetTraverse() +#include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_structseq.h" // _PyStructSequence_NewType() #ifdef __hpux #define STRICT_SYSV_CURSES @@ -173,6 +174,12 @@ get_cursesmodule_state(PyObject *Py_UNUSED(module)) return &curses_global_state; } +static inline _cursesmodule_state * +get_cursesmodule_state_by_cls(PyTypeObject *Py_UNUSED(cls)) +{ + return &curses_global_state; +} + static inline _cursesmodule_state * get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win)) { @@ -181,9 +188,9 @@ get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win)) /*[clinic input] module _curses -class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" +class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=43265c372c2887d6]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/ /* Tells whether setupterm() has been called to initialise terminfo. */ static int curses_setupterm_called = FALSE; @@ -630,10 +637,6 @@ class component_converter(CConverter): The Window Object ******************************************************************************/ -/* Definition of the window type */ - -PyTypeObject PyCursesWindow_Type; - /* Function prototype macros for Window object X - function name @@ -743,10 +746,9 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns") /* Allocation and deallocation of Window Objects */ static PyObject * -PyCursesWindow_New(WINDOW *win, const char *encoding) +PyCursesWindow_New(_cursesmodule_state *state, + WINDOW *win, const char *encoding) { - PyCursesWindowObject *wo; - if (encoding == NULL) { #if defined(MS_WINDOWS) char *buffer[100]; @@ -758,15 +760,20 @@ PyCursesWindow_New(WINDOW *win, const char *encoding) } #elif defined(CODESET) const char *codeset = nl_langinfo(CODESET); - if (codeset != NULL && codeset[0] != 0) + if (codeset != NULL && codeset[0] != 0) { encoding = codeset; + } #endif - if (encoding == NULL) + if (encoding == NULL) { encoding = "utf-8"; + } } - wo = PyObject_New(PyCursesWindowObject, &PyCursesWindow_Type); - if (wo == NULL) return NULL; + PyCursesWindowObject *wo = PyObject_GC_New(PyCursesWindowObject, + state->window_type); + if (wo == NULL) { + return NULL; + } wo->win = win; wo->encoding = _PyMem_Strdup(encoding); if (wo->encoding == NULL) { @@ -774,12 +781,16 @@ PyCursesWindow_New(WINDOW *win, const char *encoding) PyErr_NoMemory(); return NULL; } + PyObject_GC_Track((PyObject *)wo); return (PyObject *)wo; } static void -PyCursesWindow_Dealloc(PyCursesWindowObject *wo) +PyCursesWindow_dealloc(PyObject *self) { + PyTypeObject *window_type = Py_TYPE(self); + PyObject_GC_UnTrack(self); + PyCursesWindowObject *wo = (PyCursesWindowObject *)self; if (wo->win != stdscr && wo->win != NULL) { // silently ignore errors in delwin(3) (void)delwin(wo->win); @@ -787,7 +798,15 @@ PyCursesWindow_Dealloc(PyCursesWindowObject *wo) if (wo->encoding != NULL) { PyMem_Free(wo->encoding); } - PyObject_Free(wo); + window_type->tp_free(self); + Py_DECREF(window_type); +} + +static int +PyCursesWindow_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; } /* Addch, Addstr, Addnstr */ @@ -1391,7 +1410,8 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, return NULL; } - return (PyObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + return PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -2140,7 +2160,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) /*[clinic input] _curses.window.overlay - destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type") + destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type") [ sminrow: int @@ -2169,7 +2189,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, PyCursesWindowObject *destwin, int group_right_1, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol) -/*[clinic end generated code: output=82bb2c4cb443ca58 input=7edd23ad22cc1984]*/ +/*[clinic end generated code: output=82bb2c4cb443ca58 input=6e4b32a7c627a356]*/ { int rtn; @@ -2187,7 +2207,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, /*[clinic input] _curses.window.overwrite - destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type") + destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type") [ sminrow: int @@ -2217,7 +2237,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, int group_right_1, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol) -/*[clinic end generated code: output=12ae007d1681be28 input=ea5de1b35cd948e0]*/ +/*[clinic end generated code: output=12ae007d1681be28 input=d83dd8b24ff2bcc9]*/ { int rtn; @@ -2426,7 +2446,8 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, return NULL; } - return (PyObject *)PyCursesWindow_New(win, self->encoding); + _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + return PyCursesWindow_New(state, win, self->encoding); } /*[clinic input] @@ -2564,9 +2585,11 @@ PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *P return 0; } +#define clinic_state() (get_cursesmodule_state_by_cls(Py_TYPE(self))) #include "clinic/_cursesmodule.c.h" +#undef clinic_state -static PyMethodDef PyCursesWindow_Methods[] = { +static PyMethodDef PyCursesWindow_methods[] = { _CURSES_WINDOW_ADDCH_METHODDEF _CURSES_WINDOW_ADDNSTR_METHODDEF _CURSES_WINDOW_ADDSTR_METHODDEF @@ -2660,42 +2683,27 @@ static PyGetSetDef PyCursesWindow_getsets[] = { {NULL, NULL, NULL, NULL } /* sentinel */ }; -/* -------------------------------------------------------*/ +static PyType_Slot PyCursesWindow_Type_slots[] = { + {Py_tp_methods, PyCursesWindow_methods}, + {Py_tp_getset, PyCursesWindow_getsets}, + {Py_tp_dealloc, PyCursesWindow_dealloc}, + {Py_tp_traverse, PyCursesWindow_traverse}, + {0, NULL} +}; -PyTypeObject PyCursesWindow_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_curses.window", /*tp_name*/ - sizeof(PyCursesWindowObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)PyCursesWindow_Dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - (getattrfunc)0, /*tp_getattr*/ - (setattrfunc)0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - PyCursesWindow_Methods, /*tp_methods*/ - 0, /* tp_members */ - PyCursesWindow_getsets, /* tp_getset */ +static PyType_Spec PyCursesWindow_Type_spec = { + .name = "_curses.window", + .basicsize = sizeof(PyCursesWindowObject), + .flags = Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_HEAPTYPE + | Py_TPFLAGS_HAVE_GC, + .slots = PyCursesWindow_Type_slots }; +/* -------------------------------------------------------*/ + /* Function Body Macros - They are ugly but very, very useful. ;-) X - function name @@ -3177,7 +3185,8 @@ _curses_getwin(PyObject *module, PyObject *file) PyErr_SetString(state->error, catchall_NULL); goto error; } - res = PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + res = PyCursesWindow_New(state, win, NULL); error: fclose(fp); @@ -3349,7 +3358,8 @@ _curses_initscr_impl(PyObject *module) if (curses_initscr_called) { wrefresh(stdscr); - return (PyObject *)PyCursesWindow_New(stdscr, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + return PyCursesWindow_New(state, stdscr, NULL); } win = initscr(); @@ -3452,12 +3462,13 @@ _curses_initscr_impl(PyObject *module) SetDictInt("COLS", COLS); #undef SetDictInt - PyCursesWindowObject *winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + PyObject *winobj = PyCursesWindow_New(state, win, NULL); if (winobj == NULL) { return NULL; } - curses_screen_encoding = winobj->encoding; - return (PyObject *)winobj; + curses_screen_encoding = ((PyCursesWindowObject *)winobj)->encoding; + return winobj; } /*[clinic input] @@ -3829,7 +3840,8 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) return NULL; } - return (PyObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + return PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -3869,7 +3881,8 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, return NULL; } - return (PyObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + return PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -4893,11 +4906,40 @@ curses_capi_capsule_destructor(PyObject *op) curses_capi_free(capi); } +static int +curses_capi_capsule_traverse(PyObject *op, visitproc visit, void *arg) +{ + void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME); + assert(capi_ptr != NULL); + Py_VISIT(capi_ptr[0]); // visit curses window type + return 0; +} + +static int +curses_capi_capsule_clear(PyObject *op) +{ + void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME); + assert(capi_ptr != NULL); + Py_CLEAR(capi_ptr[0]); // clear curses window type + return 0; +} + static PyObject * curses_capi_capsule_new(void *capi) { - return PyCapsule_New(capi, PyCurses_CAPSULE_NAME, - curses_capi_capsule_destructor); + PyObject *capsule = PyCapsule_New(capi, PyCurses_CAPSULE_NAME, + curses_capi_capsule_destructor); + if (capsule == NULL) { + return NULL; + } + if (_PyCapsule_SetTraverse(capsule, + curses_capi_capsule_traverse, + curses_capi_capsule_clear) < 0) + { + Py_DECREF(capsule); + return NULL; + } + return capsule; } /* Module initialization */ @@ -4907,13 +4949,14 @@ cursesmodule_exec(PyObject *module) { _cursesmodule_state *state = get_cursesmodule_state(module); /* Initialize object type */ - if (PyType_Ready(&PyCursesWindow_Type) < 0) { + state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &PyCursesWindow_Type_spec, NULL); + if (state->window_type == NULL) { return -1; } - if (PyModule_AddType(module, &PyCursesWindow_Type) < 0) { + if (PyModule_AddType(module, state->window_type) < 0) { return -1; } - state->window_type = &PyCursesWindow_Type; /* Add some symbolic constants to the module */ PyObject *module_dict = PyModule_GetDict(module); diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 0b52308f10243e..8399c5620f125b 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1389,12 +1389,12 @@ _curses_window_overlay(PyCursesWindowObject *self, PyObject *args) switch (PyTuple_GET_SIZE(args)) { case 1: - if (!PyArg_ParseTuple(args, "O!:overlay", &PyCursesWindow_Type, &destwin)) { + if (!PyArg_ParseTuple(args, "O!:overlay", clinic_state()->window_type, &destwin)) { goto exit; } break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", &PyCursesWindow_Type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { + if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { goto exit; } group_right_1 = 1; @@ -1448,12 +1448,12 @@ _curses_window_overwrite(PyCursesWindowObject *self, PyObject *args) switch (PyTuple_GET_SIZE(args)) { case 1: - if (!PyArg_ParseTuple(args, "O!:overwrite", &PyCursesWindow_Type, &destwin)) { + if (!PyArg_ParseTuple(args, "O!:overwrite", clinic_state()->window_type, &destwin)) { goto exit; } break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", &PyCursesWindow_Type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { + if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { goto exit; } group_right_1 = 1; @@ -4378,4 +4378,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF #define _CURSES_USE_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=8745c1562b537fb4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cd1273354b08948f input=a9049054013a1b77]*/ From 6c7d5c6415fc22d35c7b8410533eb1831d46ba72 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 4 Oct 2024 11:59:08 +0200 Subject: [PATCH 003/247] gh-111178: Fix function signatures in Python-ast.c (#124942) --- Parser/asdl_c.py | 18 +++++++++++------- Python/Python-ast.c | 18 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index fac9a7740a1fe6..ab5fd229cc46ea 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -843,8 +843,9 @@ def visitModule(self, mod): } AST_object; static void -ast_dealloc(AST_object *self) +ast_dealloc(PyObject *op) { + AST_object *self = (AST_object*)op; /* bpo-31095: UnTrack is needed before calling any callbacks */ PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); @@ -856,16 +857,18 @@ def visitModule(self, mod): } static int -ast_traverse(AST_object *self, visitproc visit, void *arg) +ast_traverse(PyObject *op, visitproc visit, void *arg) { + AST_object *self = (AST_object*)op; Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } static int -ast_clear(AST_object *self) +ast_clear(PyObject *op) { + AST_object *self = (AST_object*)op; Py_CLEAR(self->dict); return 0; } @@ -1651,9 +1654,9 @@ def visitModule(self, mod): } static PyObject * -ast_repr(AST_object *self) +ast_repr(PyObject *self) { - return ast_repr_max_depth(self, 3); + return ast_repr_max_depth((AST_object*)self, 3); } static PyType_Slot AST_type_slots[] = { @@ -1847,8 +1850,9 @@ def visitModule(self, mod): self.file.write(textwrap.dedent(''' static int - init_types(struct ast_state *state) + init_types(void *arg) { + struct ast_state *state = arg; if (init_identifiers(state) < 0) { return -1; } @@ -2296,7 +2300,7 @@ def generate_module_def(mod, metadata, f, internal_h): }; // Forward declaration - static int init_types(struct ast_state *state); + static int init_types(void *arg); static struct ast_state* get_ast_state(void) diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 860447ef9ed702..4a58c0973d1118 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -19,7 +19,7 @@ struct validator { }; // Forward declaration -static int init_types(struct ast_state *state); +static int init_types(void *arg); static struct ast_state* get_ast_state(void) @@ -5044,8 +5044,9 @@ typedef struct { } AST_object; static void -ast_dealloc(AST_object *self) +ast_dealloc(PyObject *op) { + AST_object *self = (AST_object*)op; /* bpo-31095: UnTrack is needed before calling any callbacks */ PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); @@ -5057,16 +5058,18 @@ ast_dealloc(AST_object *self) } static int -ast_traverse(AST_object *self, visitproc visit, void *arg) +ast_traverse(PyObject *op, visitproc visit, void *arg) { + AST_object *self = (AST_object*)op; Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } static int -ast_clear(AST_object *self) +ast_clear(PyObject *op) { + AST_object *self = (AST_object*)op; Py_CLEAR(self->dict); return 0; } @@ -5852,9 +5855,9 @@ ast_repr_max_depth(AST_object *self, int depth) } static PyObject * -ast_repr(AST_object *self) +ast_repr(PyObject *self) { - return ast_repr_max_depth(self, 3); + return ast_repr_max_depth((AST_object*)self, 3); } static PyType_Slot AST_type_slots[] = { @@ -6047,8 +6050,9 @@ static int add_ast_fields(struct ast_state *state) static int -init_types(struct ast_state *state) +init_types(void *arg) { + struct ast_state *state = arg; if (init_identifiers(state) < 0) { return -1; } From aace0dca8bdcde8cd8ba85fbaf04a50fa920be7d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 4 Oct 2024 11:59:51 +0200 Subject: [PATCH 004/247] gh-111178: Fix function signatures in bytearrayobject.c (#124940) --- Objects/bytearrayobject.c | 121 +++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 48 deletions(-) diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index a80e4670665a22..fd2a85a3fe0a61 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -42,15 +42,16 @@ _getbytevalue(PyObject* arg, int *value) } static int -bytearray_getbuffer(PyByteArrayObject *obj, Py_buffer *view, int flags) +bytearray_getbuffer(PyObject *self, Py_buffer *view, int flags) { - void *ptr; + PyByteArrayObject *obj = _PyByteArray_CAST(self); if (view == NULL) { PyErr_SetString(PyExc_BufferError, "bytearray_getbuffer: view==NULL argument is obsolete"); return -1; } - ptr = (void *) PyByteArray_AS_STRING(obj); + + void *ptr = (void *) PyByteArray_AS_STRING(obj); /* cannot fail if view != NULL and readonly == 0 */ (void)PyBuffer_FillInfo(view, (PyObject*)obj, ptr, Py_SIZE(obj), 0, flags); obj->ob_exports++; @@ -58,8 +59,9 @@ bytearray_getbuffer(PyByteArrayObject *obj, Py_buffer *view, int flags) } static void -bytearray_releasebuffer(PyByteArrayObject *obj, Py_buffer *view) +bytearray_releasebuffer(PyObject *self, Py_buffer *view) { + PyByteArrayObject *obj = _PyByteArray_CAST(self); obj->ob_exports--; assert(obj->ob_exports >= 0); } @@ -286,46 +288,53 @@ PyByteArray_Concat(PyObject *a, PyObject *b) /* Functions stuffed into the type object */ static Py_ssize_t -bytearray_length(PyByteArrayObject *self) +bytearray_length(PyObject *op) { + PyByteArrayObject *self = _PyByteArray_CAST(op); return Py_SIZE(self); } static PyObject * -bytearray_iconcat(PyByteArrayObject *self, PyObject *other) +bytearray_iconcat(PyObject *op, PyObject *other) { - Py_ssize_t size; - Py_buffer vo; + PyByteArrayObject *self = _PyByteArray_CAST(op); + Py_buffer vo; if (PyObject_GetBuffer(other, &vo, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(other)->tp_name, Py_TYPE(self)->tp_name); return NULL; } - size = Py_SIZE(self); + Py_ssize_t size = Py_SIZE(self); if (size > PY_SSIZE_T_MAX - vo.len) { PyBuffer_Release(&vo); return PyErr_NoMemory(); } + if (PyByteArray_Resize((PyObject *)self, size + vo.len) < 0) { PyBuffer_Release(&vo); return NULL; } + memcpy(PyByteArray_AS_STRING(self) + size, vo.buf, vo.len); PyBuffer_Release(&vo); return Py_NewRef(self); } static PyObject * -bytearray_repeat(PyByteArrayObject *self, Py_ssize_t count) +bytearray_repeat(PyObject *op, Py_ssize_t count) { - if (count < 0) + PyByteArrayObject *self = _PyByteArray_CAST(op); + if (count < 0) { count = 0; + } const Py_ssize_t mysize = Py_SIZE(self); - if (count > 0 && mysize > PY_SSIZE_T_MAX / count) + if (count > 0 && mysize > PY_SSIZE_T_MAX / count) { return PyErr_NoMemory(); + } Py_ssize_t size = mysize * count; + PyByteArrayObject* result = (PyByteArrayObject *)PyByteArray_FromStringAndSize(NULL, size); const char* buf = PyByteArray_AS_STRING(self); if (result != NULL && size != 0) { @@ -335,20 +344,24 @@ bytearray_repeat(PyByteArrayObject *self, Py_ssize_t count) } static PyObject * -bytearray_irepeat(PyByteArrayObject *self, Py_ssize_t count) +bytearray_irepeat(PyObject *op, Py_ssize_t count) { - if (count < 0) + PyByteArrayObject *self = _PyByteArray_CAST(op); + if (count < 0) { count = 0; + } else if (count == 1) { return Py_NewRef(self); } const Py_ssize_t mysize = Py_SIZE(self); - if (count > 0 && mysize > PY_SSIZE_T_MAX / count) + if (count > 0 && mysize > PY_SSIZE_T_MAX / count) { return PyErr_NoMemory(); + } const Py_ssize_t size = mysize * count; - if (PyByteArray_Resize((PyObject *)self, size) < 0) + if (PyByteArray_Resize((PyObject *)self, size) < 0) { return NULL; + } char* buf = PyByteArray_AS_STRING(self); _PyBytes_Repeat(buf, size, buf, mysize); @@ -357,8 +370,9 @@ bytearray_irepeat(PyByteArrayObject *self, Py_ssize_t count) } static PyObject * -bytearray_getitem(PyByteArrayObject *self, Py_ssize_t i) +bytearray_getitem(PyObject *op, Py_ssize_t i) { + PyByteArrayObject *self = _PyByteArray_CAST(op); if (i < 0 || i >= Py_SIZE(self)) { PyErr_SetString(PyExc_IndexError, "bytearray index out of range"); return NULL; @@ -367,8 +381,9 @@ bytearray_getitem(PyByteArrayObject *self, Py_ssize_t i) } static PyObject * -bytearray_subscript(PyByteArrayObject *self, PyObject *index) +bytearray_subscript(PyObject *op, PyObject *index) { + PyByteArrayObject *self = _PyByteArray_CAST(op); if (_PyIndex_Check(index)) { Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError); @@ -559,12 +574,13 @@ bytearray_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi, } static int -bytearray_setitem(PyByteArrayObject *self, Py_ssize_t i, PyObject *value) +bytearray_setitem(PyObject *op, Py_ssize_t i, PyObject *value) { - int ival = -1; + PyByteArrayObject *self = _PyByteArray_CAST(op); // GH-91153: We need to do this *before* the size check, in case value has a // nasty __index__ method that changes the size of the bytearray: + int ival = -1; if (value && !_getbytevalue(value, &ival)) { return -1; } @@ -588,11 +604,11 @@ bytearray_setitem(PyByteArrayObject *self, Py_ssize_t i, PyObject *value) } static int -bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values) +bytearray_ass_subscript(PyObject *op, PyObject *index, PyObject *values) { - Py_ssize_t start, stop, step, slicelen, needed; - char *buf, *bytes; - buf = PyByteArray_AS_STRING(self); + PyByteArrayObject *self = _PyByteArray_CAST(op); + Py_ssize_t start, stop, step, slicelen; + char *buf = PyByteArray_AS_STRING(self); if (_PyIndex_Check(index)) { Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError); @@ -645,6 +661,8 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu return -1; } + char *bytes; + Py_ssize_t needed; if (values == NULL) { bytes = NULL; needed = 0; @@ -661,7 +679,7 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu values = PyByteArray_FromObject(values); if (values == NULL) return -1; - err = bytearray_ass_subscript(self, index, values); + err = bytearray_ass_subscript((PyObject*)self, index, values); Py_DECREF(values); return err; } @@ -670,10 +688,14 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu bytes = PyByteArray_AS_STRING(values); needed = Py_SIZE(values); } + /* Make sure b[5:2] = ... inserts before 5, not before 2. */ if ((step < 0 && start < stop) || (step > 0 && start > stop)) + { stop = start; + } + if (step == 1) { return bytearray_setslice_linear(self, start, stop, bytes, needed); } @@ -785,7 +807,7 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, if (encoded == NULL) return -1; assert(PyBytes_Check(encoded)); - new = bytearray_iconcat(self, encoded); + new = bytearray_iconcat((PyObject*)self, encoded); Py_DECREF(encoded); if (new == NULL) return -1; @@ -926,8 +948,9 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, /* Mostly copied from string_repr, but without the "smart quote" functionality. */ static PyObject * -bytearray_repr(PyByteArrayObject *self) +bytearray_repr(PyObject *op) { + PyByteArrayObject *self = _PyByteArray_CAST(op); const char *className = _PyType_Name(Py_TYPE(self)); const char *quote_prefix = "(b"; const char *quote_postfix = ")"; @@ -1021,7 +1044,7 @@ bytearray_str(PyObject *op) return NULL; } } - return bytearray_repr((PyByteArrayObject*)op); + return bytearray_repr(op); } static PyObject * @@ -1080,8 +1103,9 @@ bytearray_richcompare(PyObject *self, PyObject *other, int op) } static void -bytearray_dealloc(PyByteArrayObject *self) +bytearray_dealloc(PyObject *op) { + PyByteArrayObject *self = _PyByteArray_CAST(op); if (self->ob_exports > 0) { PyErr_SetString(PyExc_SystemError, "deallocated bytearray object has exported buffers"); @@ -1244,7 +1268,9 @@ bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub, static int bytearray_contains(PyObject *self, PyObject *arg) { - return _Py_bytes_contains(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), arg); + return _Py_bytes_contains(PyByteArray_AS_STRING(self), + PyByteArray_GET_SIZE(self), + arg); } /*[clinic input] @@ -2262,31 +2288,30 @@ bytearray_sizeof_impl(PyByteArrayObject *self) } static PySequenceMethods bytearray_as_sequence = { - (lenfunc)bytearray_length, /* sq_length */ - (binaryfunc)PyByteArray_Concat, /* sq_concat */ - (ssizeargfunc)bytearray_repeat, /* sq_repeat */ - (ssizeargfunc)bytearray_getitem, /* sq_item */ + bytearray_length, /* sq_length */ + PyByteArray_Concat, /* sq_concat */ + bytearray_repeat, /* sq_repeat */ + bytearray_getitem, /* sq_item */ 0, /* sq_slice */ - (ssizeobjargproc)bytearray_setitem, /* sq_ass_item */ + bytearray_setitem, /* sq_ass_item */ 0, /* sq_ass_slice */ - (objobjproc)bytearray_contains, /* sq_contains */ - (binaryfunc)bytearray_iconcat, /* sq_inplace_concat */ - (ssizeargfunc)bytearray_irepeat, /* sq_inplace_repeat */ + bytearray_contains, /* sq_contains */ + bytearray_iconcat, /* sq_inplace_concat */ + bytearray_irepeat, /* sq_inplace_repeat */ }; static PyMappingMethods bytearray_as_mapping = { - (lenfunc)bytearray_length, - (binaryfunc)bytearray_subscript, - (objobjargproc)bytearray_ass_subscript, + bytearray_length, + bytearray_subscript, + bytearray_ass_subscript, }; static PyBufferProcs bytearray_as_buffer = { - (getbufferproc)bytearray_getbuffer, - (releasebufferproc)bytearray_releasebuffer, + bytearray_getbuffer, + bytearray_releasebuffer, }; -static PyMethodDef -bytearray_methods[] = { +static PyMethodDef bytearray_methods[] = { {"__alloc__", (PyCFunction)bytearray_alloc, METH_NOARGS, alloc_doc}, BYTEARRAY_REDUCE_METHODDEF BYTEARRAY_REDUCE_EX_METHODDEF @@ -2391,12 +2416,12 @@ PyTypeObject PyByteArray_Type = { "bytearray", sizeof(PyByteArrayObject), 0, - (destructor)bytearray_dealloc, /* tp_dealloc */ + bytearray_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)bytearray_repr, /* tp_repr */ + bytearray_repr, /* tp_repr */ &bytearray_as_number, /* tp_as_number */ &bytearray_as_sequence, /* tp_as_sequence */ &bytearray_as_mapping, /* tp_as_mapping */ @@ -2411,7 +2436,7 @@ PyTypeObject PyByteArray_Type = { bytearray_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - (richcmpfunc)bytearray_richcompare, /* tp_richcompare */ + bytearray_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ bytearray_iter, /* tp_iter */ 0, /* tp_iternext */ From 2c2ad4f76f8ec197c31145d3f33bc40b790d4aea Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 4 Oct 2024 12:00:00 +0200 Subject: [PATCH 005/247] gh-111178: Fix function signatures in classobject.c (#124943) --- Objects/classobject.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/Objects/classobject.c b/Objects/classobject.c index 69a7d5f046e30d..775894ad5a7166 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -10,6 +10,7 @@ #include "clinic/classobject.c.h" +#define _PyMethodObject_CAST(op) _Py_CAST(PyMethodObject*, (op)) #define TP_DESCR_GET(t) ((t)->tp_descr_get) /*[clinic input] @@ -166,13 +167,14 @@ static PyMemberDef method_memberlist[] = { should only be used for the class, not for instances */ static PyObject * -method_get_doc(PyMethodObject *im, void *context) +method_get_doc(PyObject *self, void *context) { + PyMethodObject *im = _PyMethodObject_CAST(self); return PyObject_GetAttr(im->im_func, &_Py_ID(__doc__)); } static PyGetSetDef method_getset[] = { - {"__doc__", (getter)method_get_doc, NULL, NULL}, + {"__doc__", method_get_doc, NULL, NULL}, {0} }; @@ -235,8 +237,9 @@ method_new_impl(PyTypeObject *type, PyObject *function, PyObject *instance) } static void -method_dealloc(PyMethodObject *im) +method_dealloc(PyObject *self) { + PyMethodObject *im = _PyMethodObject_CAST(self); _PyObject_GC_UNTRACK(im); if (im->im_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)im); @@ -274,8 +277,9 @@ method_richcompare(PyObject *self, PyObject *other, int op) } static PyObject * -method_repr(PyMethodObject *a) +method_repr(PyObject *op) { + PyMethodObject *a = _PyMethodObject_CAST(op); PyObject *self = a->im_self; PyObject *func = a->im_func; PyObject *funcname, *result; @@ -301,22 +305,26 @@ method_repr(PyMethodObject *a) } static Py_hash_t -method_hash(PyMethodObject *a) +method_hash(PyObject *self) { - Py_hash_t x, y; - x = PyObject_GenericHash(a->im_self); - y = PyObject_Hash(a->im_func); - if (y == -1) + PyMethodObject *a = _PyMethodObject_CAST(self); + Py_hash_t x = PyObject_GenericHash(a->im_self); + Py_hash_t y = PyObject_Hash(a->im_func); + if (y == -1) { return -1; + } + x = x ^ y; - if (x == -1) + if (x == -1) { x = -2; + } return x; } static int -method_traverse(PyMethodObject *im, visitproc visit, void *arg) +method_traverse(PyObject *self, visitproc visit, void *arg) { + PyMethodObject *im = _PyMethodObject_CAST(self); Py_VISIT(im->im_func); Py_VISIT(im->im_self); return 0; @@ -333,17 +341,17 @@ PyTypeObject PyMethod_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "method", .tp_basicsize = sizeof(PyMethodObject), - .tp_dealloc = (destructor)method_dealloc, + .tp_dealloc = method_dealloc, .tp_vectorcall_offset = offsetof(PyMethodObject, vectorcall), - .tp_repr = (reprfunc)method_repr, - .tp_hash = (hashfunc)method_hash, + .tp_repr = method_repr, + .tp_hash = method_hash, .tp_call = PyVectorcall_Call, .tp_getattro = method_getattro, .tp_setattro = PyObject_GenericSetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_VECTORCALL, .tp_doc = method_new__doc__, - .tp_traverse = (traverseproc)method_traverse, + .tp_traverse = method_traverse, .tp_richcompare = method_richcompare, .tp_weaklistoffset = offsetof(PyMethodObject, im_weakreflist), .tp_methods = method_methods, @@ -399,7 +407,7 @@ instancemethod_get_doc(PyObject *self, void *context) } static PyGetSetDef instancemethod_getset[] = { - {"__doc__", (getter)instancemethod_get_doc, NULL, NULL}, + {"__doc__", instancemethod_get_doc, NULL, NULL}, {0} }; @@ -537,7 +545,7 @@ PyTypeObject PyInstanceMethod_Type = { .tp_name = "instancemethod", .tp_basicsize = sizeof(PyInstanceMethodObject), .tp_dealloc = instancemethod_dealloc, - .tp_repr = (reprfunc)instancemethod_repr, + .tp_repr = instancemethod_repr, .tp_call = instancemethod_call, .tp_getattro = instancemethod_getattro, .tp_setattro = PyObject_GenericSetAttr, From ac9648243dc0f5cb34c93621e507a98cf90550ea Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 4 Oct 2024 12:21:03 +0200 Subject: [PATCH 006/247] gh-109975: Suggest ``pynntp`` instead of ``nntplib`` (#124830) The ``nntplib`` library has been deleted from PyPI by its author. --- Doc/whatsnew/3.13.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 261c3b003ccf66..e629fc122f1397 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -1559,7 +1559,7 @@ and are now removed: * :mod:`!msilib` * :mod:`!nis` * :mod:`!nntplib`: - Use the :pypi:`nntplib` library from PyPI instead. + Use the :pypi:`pynntp` library from PyPI instead. * :mod:`!ossaudiodev`: For audio playback, use the :pypi:`pygame` library from PyPI instead. * :mod:`!pipes`: From ddccd546a00fa7c2e4140cae25284b902292ad3b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 4 Oct 2024 12:50:01 +0200 Subject: [PATCH 007/247] gh-111178: Fix function signatures in _threadmodule.c (#124964) --- Modules/_threadmodule.c | 119 +++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 49 deletions(-) diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index b3ed8e7bc56b9e..153fe85597749d 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -599,8 +599,9 @@ PyThreadHandleObject_traverse(PyThreadHandleObject *self, visitproc visit, } static void -PyThreadHandleObject_dealloc(PyThreadHandleObject *self) +PyThreadHandleObject_dealloc(PyObject *op) { + PyThreadHandleObject *self = (PyThreadHandleObject*)op; PyObject_GC_UnTrack(self); PyTypeObject *tp = Py_TYPE(self); ThreadHandle_decref(self->handle); @@ -609,23 +610,26 @@ PyThreadHandleObject_dealloc(PyThreadHandleObject *self) } static PyObject * -PyThreadHandleObject_repr(PyThreadHandleObject *self) +PyThreadHandleObject_repr(PyObject *op) { + PyThreadHandleObject *self = (PyThreadHandleObject*)op; PyThread_ident_t ident = ThreadHandle_ident(self->handle); return PyUnicode_FromFormat("<%s object: ident=%" PY_FORMAT_THREAD_IDENT_T ">", Py_TYPE(self)->tp_name, ident); } static PyObject * -PyThreadHandleObject_get_ident(PyThreadHandleObject *self, - PyObject *Py_UNUSED(ignored)) +PyThreadHandleObject_get_ident(PyObject *op, void *Py_UNUSED(ignored)) { + PyThreadHandleObject *self = (PyThreadHandleObject*)op; return PyLong_FromUnsignedLongLong(ThreadHandle_ident(self->handle)); } static PyObject * -PyThreadHandleObject_join(PyThreadHandleObject *self, PyObject *args) +PyThreadHandleObject_join(PyObject *op, PyObject *args) { + PyThreadHandleObject *self = (PyThreadHandleObject*)op; + PyObject *timeout_obj = NULL; if (!PyArg_ParseTuple(args, "|O:join", &timeout_obj)) { return NULL; @@ -646,9 +650,9 @@ PyThreadHandleObject_join(PyThreadHandleObject *self, PyObject *args) } static PyObject * -PyThreadHandleObject_is_done(PyThreadHandleObject *self, - PyObject *Py_UNUSED(ignored)) +PyThreadHandleObject_is_done(PyObject *op, PyObject *Py_UNUSED(ignored)) { + PyThreadHandleObject *self = (PyThreadHandleObject*)op; if (_PyEvent_IsSet(&self->handle->thread_is_exiting)) { Py_RETURN_TRUE; } @@ -658,9 +662,9 @@ PyThreadHandleObject_is_done(PyThreadHandleObject *self, } static PyObject * -PyThreadHandleObject_set_done(PyThreadHandleObject *self, - PyObject *Py_UNUSED(ignored)) +PyThreadHandleObject_set_done(PyObject *op, PyObject *Py_UNUSED(ignored)) { + PyThreadHandleObject *self = (PyThreadHandleObject*)op; if (ThreadHandle_set_done(self->handle) < 0) { return NULL; } @@ -668,20 +672,20 @@ PyThreadHandleObject_set_done(PyThreadHandleObject *self, } static PyGetSetDef ThreadHandle_getsetlist[] = { - {"ident", (getter)PyThreadHandleObject_get_ident, NULL, NULL}, + {"ident", PyThreadHandleObject_get_ident, NULL, NULL}, {0}, }; static PyMethodDef ThreadHandle_methods[] = { - {"join", (PyCFunction)PyThreadHandleObject_join, METH_VARARGS, NULL}, - {"_set_done", (PyCFunction)PyThreadHandleObject_set_done, METH_NOARGS, NULL}, - {"is_done", (PyCFunction)PyThreadHandleObject_is_done, METH_NOARGS, NULL}, + {"join", PyThreadHandleObject_join, METH_VARARGS, NULL}, + {"_set_done", PyThreadHandleObject_set_done, METH_NOARGS, NULL}, + {"is_done", PyThreadHandleObject_is_done, METH_NOARGS, NULL}, {0, 0} }; static PyType_Slot ThreadHandle_Type_slots[] = { - {Py_tp_dealloc, (destructor)PyThreadHandleObject_dealloc}, - {Py_tp_repr, (reprfunc)PyThreadHandleObject_repr}, + {Py_tp_dealloc, PyThreadHandleObject_dealloc}, + {Py_tp_repr, PyThreadHandleObject_repr}, {Py_tp_getset, ThreadHandle_getsetlist}, {Py_tp_traverse, PyThreadHandleObject_traverse}, {Py_tp_methods, ThreadHandle_methods}, @@ -707,15 +711,16 @@ typedef struct { } lockobject; static int -lock_traverse(lockobject *self, visitproc visit, void *arg) +lock_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); return 0; } static void -lock_dealloc(lockobject *self) +lock_dealloc(PyObject *op) { + lockobject *self = (lockobject*)op; PyObject_GC_UnTrack(self); if (self->in_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *) self); @@ -784,11 +789,14 @@ lock_acquire_parse_args(PyObject *args, PyObject *kwds, } static PyObject * -lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds) +lock_PyThread_acquire_lock(PyObject *op, PyObject *args, PyObject *kwds) { + lockobject *self = (lockobject*)op; + PyTime_t timeout; - if (lock_acquire_parse_args(args, kwds, &timeout) < 0) + if (lock_acquire_parse_args(args, kwds, &timeout) < 0) { return NULL; + } PyLockStatus r = acquire_timed(self->lock_lock, timeout); if (r == PY_LOCK_INTR) { @@ -824,8 +832,9 @@ PyDoc_STRVAR(enter_doc, Lock the lock."); static PyObject * -lock_PyThread_release_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) +lock_PyThread_release_lock(PyObject *op, PyObject *Py_UNUSED(ignored)) { + lockobject *self = (lockobject*)op; /* Sanity check: the lock must be locked */ if (!self->locked) { PyErr_SetString(ThreadError, "release unlocked lock"); @@ -858,8 +867,9 @@ PyDoc_STRVAR(lock_exit_doc, Release the lock."); static PyObject * -lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) +lock_locked_lock(PyObject *op, PyObject *Py_UNUSED(ignored)) { + lockobject *self = (lockobject*)op; return PyBool_FromLong((long)self->locked); } @@ -876,16 +886,18 @@ PyDoc_STRVAR(locked_lock_doc, An obsolete synonym of locked()."); static PyObject * -lock_repr(lockobject *self) +lock_repr(PyObject *op) { + lockobject *self = (lockobject*)op; return PyUnicode_FromFormat("<%s %s object at %p>", self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self); } #ifdef HAVE_FORK static PyObject * -lock__at_fork_reinit(lockobject *self, PyObject *Py_UNUSED(args)) +lock__at_fork_reinit(PyObject *op, PyObject *Py_UNUSED(args)) { + lockobject *self = (lockobject*)op; if (_PyThread_at_fork_reinit(&self->lock_lock) < 0) { PyErr_SetString(ThreadError, "failed to reinitialize lock at fork"); return NULL; @@ -924,20 +936,20 @@ static PyMethodDef lock_methods[] = { METH_VARARGS | METH_KEYWORDS, acquire_lock_doc}, {"acquire", _PyCFunction_CAST(lock_PyThread_acquire_lock), METH_VARARGS | METH_KEYWORDS, acquire_doc}, - {"release_lock", (PyCFunction)lock_PyThread_release_lock, + {"release_lock", lock_PyThread_release_lock, METH_NOARGS, release_lock_doc}, - {"release", (PyCFunction)lock_PyThread_release_lock, + {"release", lock_PyThread_release_lock, METH_NOARGS, release_doc}, - {"locked_lock", (PyCFunction)lock_locked_lock, + {"locked_lock", lock_locked_lock, METH_NOARGS, locked_lock_doc}, - {"locked", (PyCFunction)lock_locked_lock, + {"locked", lock_locked_lock, METH_NOARGS, locked_doc}, {"__enter__", _PyCFunction_CAST(lock_PyThread_acquire_lock), METH_VARARGS | METH_KEYWORDS, enter_doc}, - {"__exit__", (PyCFunction)lock_PyThread_release_lock, + {"__exit__", lock_PyThread_release_lock, METH_VARARGS, lock_exit_doc}, #ifdef HAVE_FORK - {"_at_fork_reinit", (PyCFunction)lock__at_fork_reinit, + {"_at_fork_reinit", lock__at_fork_reinit, METH_NOARGS, NULL}, #endif {NULL, NULL} /* sentinel */ @@ -964,8 +976,8 @@ static PyMemberDef lock_type_members[] = { }; static PyType_Slot lock_type_slots[] = { - {Py_tp_dealloc, (destructor)lock_dealloc}, - {Py_tp_repr, (reprfunc)lock_repr}, + {Py_tp_dealloc, lock_dealloc}, + {Py_tp_repr, lock_repr}, {Py_tp_doc, (void *)lock_doc}, {Py_tp_methods, lock_methods}, {Py_tp_traverse, lock_traverse}, @@ -1001,8 +1013,9 @@ rlock_traverse(rlockobject *self, visitproc visit, void *arg) static void -rlock_dealloc(rlockobject *self) +rlock_dealloc(PyObject *op) { + rlockobject *self = (rlockobject*)op; PyObject_GC_UnTrack(self); if (self->in_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -1029,8 +1042,9 @@ rlock_is_owned_by(rlockobject *self, PyThread_ident_t tid) } static PyObject * -rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds) +rlock_acquire(PyObject *op, PyObject *args, PyObject *kwds) { + rlockobject *self = (rlockobject*)op; PyTime_t timeout; PyThread_ident_t tid; PyLockStatus r = PY_LOCK_ACQUIRED; @@ -1086,8 +1100,9 @@ PyDoc_STRVAR(rlock_enter_doc, Lock the lock."); static PyObject * -rlock_release(rlockobject *self, PyObject *Py_UNUSED(ignored)) +rlock_release(PyObject *op, PyObject *Py_UNUSED(ignored)) { + rlockobject *self = (rlockobject*)op; PyThread_ident_t tid = PyThread_get_thread_ident_ex(); if (!rlock_is_owned_by(self, tid)) { @@ -1122,8 +1137,9 @@ PyDoc_STRVAR(rlock_exit_doc, Release the lock."); static PyObject * -rlock_acquire_restore(rlockobject *self, PyObject *args) +rlock_acquire_restore(PyObject *op, PyObject *args) { + rlockobject *self = (rlockobject*)op; PyThread_ident_t owner; unsigned long count; int r = 1; @@ -1154,8 +1170,9 @@ PyDoc_STRVAR(rlock_acquire_restore_doc, For internal use by `threading.Condition`."); static PyObject * -rlock_release_save(rlockobject *self, PyObject *Py_UNUSED(ignored)) +rlock_release_save(PyObject *op, PyObject *Py_UNUSED(ignored)) { + rlockobject *self = (rlockobject*)op; PyThread_ident_t owner; unsigned long count; @@ -1180,8 +1197,9 @@ PyDoc_STRVAR(rlock_release_save_doc, For internal use by `threading.Condition`."); static PyObject * -rlock_recursion_count(rlockobject *self, PyObject *Py_UNUSED(ignored)) +rlock_recursion_count(PyObject *op, PyObject *Py_UNUSED(ignored)) { + rlockobject *self = (rlockobject*)op; PyThread_ident_t tid = PyThread_get_thread_ident_ex(); PyThread_ident_t owner = _Py_atomic_load_ullong_relaxed(&self->rlock_owner); @@ -1195,8 +1213,9 @@ PyDoc_STRVAR(rlock_recursion_count_doc, For internal use by reentrancy checks."); static PyObject * -rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored)) +rlock_is_owned(PyObject *op, PyObject *Py_UNUSED(ignored)) { + rlockobject *self = (rlockobject*)op; PyThread_ident_t tid = PyThread_get_thread_ident_ex(); if (rlock_is_owned_by(self, tid)) { @@ -1232,8 +1251,9 @@ rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static PyObject * -rlock_repr(rlockobject *self) +rlock_repr(PyObject *op) { + rlockobject *self = (rlockobject*)op; PyThread_ident_t owner = _Py_atomic_load_ullong_relaxed(&self->rlock_owner); return PyUnicode_FromFormat( @@ -1264,19 +1284,19 @@ rlock__at_fork_reinit(rlockobject *self, PyObject *Py_UNUSED(args)) static PyMethodDef rlock_methods[] = { {"acquire", _PyCFunction_CAST(rlock_acquire), METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, - {"release", (PyCFunction)rlock_release, + {"release", rlock_release, METH_NOARGS, rlock_release_doc}, - {"_is_owned", (PyCFunction)rlock_is_owned, + {"_is_owned", rlock_is_owned, METH_NOARGS, rlock_is_owned_doc}, - {"_acquire_restore", (PyCFunction)rlock_acquire_restore, + {"_acquire_restore", rlock_acquire_restore, METH_VARARGS, rlock_acquire_restore_doc}, - {"_release_save", (PyCFunction)rlock_release_save, + {"_release_save", rlock_release_save, METH_NOARGS, rlock_release_save_doc}, - {"_recursion_count", (PyCFunction)rlock_recursion_count, + {"_recursion_count", rlock_recursion_count, METH_NOARGS, rlock_recursion_count_doc}, {"__enter__", _PyCFunction_CAST(rlock_acquire), METH_VARARGS | METH_KEYWORDS, rlock_enter_doc}, - {"__exit__", (PyCFunction)rlock_release, + {"__exit__", rlock_release, METH_VARARGS, rlock_exit_doc}, #ifdef HAVE_FORK {"_at_fork_reinit", (PyCFunction)rlock__at_fork_reinit, @@ -1292,8 +1312,8 @@ static PyMemberDef rlock_type_members[] = { }; static PyType_Slot rlock_type_slots[] = { - {Py_tp_dealloc, (destructor)rlock_dealloc}, - {Py_tp_repr, (reprfunc)rlock_repr}, + {Py_tp_dealloc, rlock_dealloc}, + {Py_tp_repr, rlock_repr}, {Py_tp_methods, rlock_methods}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, rlock_new}, @@ -1392,8 +1412,9 @@ typedef struct { } localdummyobject; static void -localdummy_dealloc(localdummyobject *self) +localdummy_dealloc(PyObject *op) { + localdummyobject *self = (localdummyobject*)op; if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); PyTypeObject *tp = Py_TYPE(self); @@ -1407,7 +1428,7 @@ static PyMemberDef local_dummy_type_members[] = { }; static PyType_Slot local_dummy_type_slots[] = { - {Py_tp_dealloc, (destructor)localdummy_dealloc}, + {Py_tp_dealloc, localdummy_dealloc}, {Py_tp_doc, "Thread-local dummy"}, {Py_tp_members, local_dummy_type_members}, {0, 0} From 480354dc236af9ae9d47b2520aa85fb7293c7b68 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Fri, 4 Oct 2024 13:15:08 +0200 Subject: [PATCH 008/247] gh-118658: Modify cert generation script to extract cert3.pem (GH-124598) --- Lib/test/certdata/cert3.pem | 2 +- Lib/test/certdata/make_ssl_certs.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/certdata/cert3.pem b/Lib/test/certdata/cert3.pem index 034bc43ff1974e..4ab0f5ff133e3f 100644 --- a/Lib/test/certdata/cert3.pem +++ b/Lib/test/certdata/cert3.pem @@ -31,4 +31,4 @@ zqmtEM65ceSP8lo8Zbrcy+AEkCulFaZ92tyjtbe8oN4wTmTLFw06oFLSZzuiOgDV OaphdVKf/pvA6KBpr6izox0KQFIE5z3AAJZfKzMGDDD20xhy7jjQZNMAhjfsT+k4 SeYB/6KafNxq08uoulj7w4Z4R/EGpkXnU96ZHYHmvGN0RnxwI1cpYHCazG8AjsK/ anN9brBi5twTGrn+D8LRBqF5Yn+2MKkD0EdXJdtIENHP+32sPQ== ------END CERTIFICATE----- \ No newline at end of file +-----END CERTIFICATE----- diff --git a/Lib/test/certdata/make_ssl_certs.py b/Lib/test/certdata/make_ssl_certs.py index 5e626baf550c5b..48f980124e1198 100644 --- a/Lib/test/certdata/make_ssl_certs.py +++ b/Lib/test/certdata/make_ssl_certs.py @@ -266,6 +266,8 @@ def write_cert_reference(path): f.write(key) f.write(cert) + check_call(['openssl', 'x509', '-outform', 'pem', '-in', 'keycert3.pem', '-out', 'cert3.pem']) + cert, key = make_cert_key(cmdlineargs, 'fakehostname', sign=True) with open('keycert4.pem', 'w') as f: f.write(key) From bd393aedb84a7d84d11a996bcbbf57cad90af7db Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Fri, 4 Oct 2024 13:33:54 +0200 Subject: [PATCH 009/247] Fix console prompt syntax in What's New in Python 3.8 (#124968) --- Doc/whatsnew/3.8.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index d0e60bc280a217..fc9f49e65af847 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -428,9 +428,9 @@ Other Language Changes normal assignment syntax:: >>> def parse(family): - lastname, *members = family.split() - return lastname.upper(), *members - + ... lastname, *members = family.split() + ... return lastname.upper(), *members + ... >>> parse('simpsons homer marge bart lisa maggie') ('SIMPSONS', 'homer', 'marge', 'bart', 'lisa', 'maggie') From 994051e086b9ce624a3b16750d6f692bc4a3b07b Mon Sep 17 00:00:00 2001 From: isaacjones99 <82098317+isaacjones99@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:23:02 +0100 Subject: [PATCH 010/247] gh-124962: Convert leftover rst to markup in `InternalDocs/compiler.md` (#124971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- InternalDocs/compiler.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/InternalDocs/compiler.md b/InternalDocs/compiler.md index ba31e16c3bbeaa..f27e73b274511f 100644 --- a/InternalDocs/compiler.md +++ b/InternalDocs/compiler.md @@ -324,14 +324,14 @@ basic block. As an example, consider the following code snippet: -.. code-block:: Python - - if x < 10: - f1() - f2() - else: - g() - end() +```python +if x < 10: + f1() + f2() +else: + g() +end() +``` The ``x < 10`` guard is represented by its own basic block that compares ``x`` with ``10`` and then ends in a conditional jump based on From f474391b26aa9208b44ca879f8635409d322f738 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 4 Oct 2024 17:37:38 +0100 Subject: [PATCH 011/247] gh-124871: fix 'visited' tracking in compiler's reachability analysis (#124952) --- Lib/test/test_compile.py | 13 +++++++++++++ .../2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst | 2 ++ Python/flowgraph.c | 5 +++-- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e9ee72cf234fdc..e6dc7a53189e12 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -479,6 +479,19 @@ def test_dead_code_with_except_handler_compiles(self): x = 2 """), '', 'exec') + def test_try_except_in_while_with_chained_condition_compiles(self): + # see gh-124871 + compile(textwrap.dedent(""" + name_1, name_2, name_3 = 1, 2, 3 + while name_3 <= name_2 > name_1: + try: + raise + except: + pass + finally: + pass + """), '', 'exec') + def test_compile_invalid_namedexpr(self): # gh-109351 m = ast.Module( diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst b/Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst new file mode 100644 index 00000000000000..185cb3048fadf5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst @@ -0,0 +1,2 @@ +Fix compiler bug (in some versions of 3.13) where an assertion fails during reachability +analysis. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 69d7e0a872aa48..388862912d6826 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1001,13 +1001,14 @@ remove_unreachable(basicblock *entryblock) { basicblock **sp = stack; entryblock->b_predecessors = 1; *sp++ = entryblock; + entryblock->b_visited = 1; while (sp > stack) { basicblock *b = *(--sp); - b->b_visited = 1; if (b->b_next && BB_HAS_FALLTHROUGH(b)) { if (!b->b_next->b_visited) { assert(b->b_next->b_predecessors == 0); *sp++ = b->b_next; + b->b_next->b_visited = 1; } b->b_next->b_predecessors++; } @@ -1017,8 +1018,8 @@ remove_unreachable(basicblock *entryblock) { if (is_jump(instr) || is_block_push(instr)) { target = instr->i_target; if (!target->b_visited) { - assert(target->b_predecessors == 0 || target == b->b_next); *sp++ = target; + target->b_visited = 1; } target->b_predecessors++; } From 8bcf118dcb2cab88acc8a6dffb7968b1854802b4 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 5 Oct 2024 00:48:12 +0100 Subject: [PATCH 012/247] gh-119786: move a few more details on exception handling from devguide to InternalDocs (#124989) --- InternalDocs/exception_handling.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/InternalDocs/exception_handling.md b/InternalDocs/exception_handling.md index ec09e0769929fa..2e306c7046e237 100644 --- a/InternalDocs/exception_handling.md +++ b/InternalDocs/exception_handling.md @@ -75,7 +75,8 @@ table. If it finds a handler, control flow transfers to it. Otherwise, the exception bubbles up to the caller, and the caller's frame is checked for a handler covering the `CALL` instruction. This repeats until a handler is found or the topmost frame is reached. -If no handler is found, the program terminates. During unwinding, +If no handler is found, then the interpreter function +(``_PyEval_EvalFrameDefault()``) returns NULL. During unwinding, the traceback is constructed as each frame is added to it by ``PyTraceBack_Here()``, which is in [Python/traceback.c](https://github.com/python/cpython/blob/main/Python/traceback.c). @@ -182,3 +183,12 @@ The interpreter's function to lookup the table by instruction offset is The Python function ``_parse_exception_table()`` in [Lib/dis.py](https://github.com/python/cpython/blob/main/Lib/dis.py) returns the exception table content as a list of namedtuple instances. + +Exception Chaining Implementation +--------------------------------- + +[Exception chaining](https://docs.python.org/dev/tutorial/errors.html#exception-chaining) +refers to setting the ``__context__`` and ``__cause__`` fields of an exception as it is +being raised. The ``__context__`` field is set by ``_PyErr_SetObject()`` in +:cpy-file:`Python/errors.c` (which is ultimately called by all ``PyErr_Set*()`` functions). +The ``__cause__`` field (explicit chaining) is set by the ``RAISE_VARARGS`` bytecode. From 6efd95c4650ec7c2fb5522b352c74a9d44370fe0 Mon Sep 17 00:00:00 2001 From: morotti Date: Sat, 5 Oct 2024 00:51:22 +0100 Subject: [PATCH 013/247] gh-117151: increase default buffer size of shutil.copyfileobj() to 256k. (GH-119783) * gh-117151: increase default buffer size of shutil.copyfileobj() to 256k. it was set to 16k in the 1990s. it was raised to 64k in 2019. the discussion at the time mentioned another 5% improvement by raising to 128k and settled for a very conservative setting. it's 2024 now, I think it should be revisited to match modern hardware. I am measuring 0-15% performance improvement when raising to 256k on various types of disk. there is no downside as far as I can tell. this function is only intended for sequential copy of full files (or file like objects). it's the typical use case that benefits from larger operations. for reference, I came across this function while trying to profile pip that is using it to copy files when installing python packages. * add news --------- Co-authored-by: rmorotti --- Lib/shutil.py | 2 +- .../Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst diff --git a/Lib/shutil.py b/Lib/shutil.py index dab3ca5ee91245..dd3e0e0c5da54b 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -44,7 +44,7 @@ else: _winapi = None -COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024 +COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 256 * 1024 # This should never be removed, see rationale in: # https://bugs.python.org/issue43743#msg393429 _USE_CP_SENDFILE = (hasattr(os, "sendfile") diff --git a/Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst b/Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst new file mode 100644 index 00000000000000..a7d6251f1e071f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst @@ -0,0 +1,3 @@ +The default buffer size used by :func:`shutil.copyfileobj` has been +increased from 64k to 256k on non-Windows platforms. It was already larger +on Windows. From 2d8b6a4e9d9a74e3c5270eec62716710ac197063 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 5 Oct 2024 01:00:19 +0100 Subject: [PATCH 014/247] gh-119786: Replace a Sphinx role with a link to `Python/errors.c` (#124990) --- InternalDocs/exception_handling.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InternalDocs/exception_handling.md b/InternalDocs/exception_handling.md index 2e306c7046e237..64a346b55b8413 100644 --- a/InternalDocs/exception_handling.md +++ b/InternalDocs/exception_handling.md @@ -190,5 +190,6 @@ Exception Chaining Implementation [Exception chaining](https://docs.python.org/dev/tutorial/errors.html#exception-chaining) refers to setting the ``__context__`` and ``__cause__`` fields of an exception as it is being raised. The ``__context__`` field is set by ``_PyErr_SetObject()`` in -:cpy-file:`Python/errors.c` (which is ultimately called by all ``PyErr_Set*()`` functions). +[Python/errors.c](https://github.com/python/cpython/blob/main/Python/errors.c) +(which is ultimately called by all ``PyErr_Set*()`` functions). The ``__cause__`` field (explicit chaining) is set by the ``RAISE_VARARGS`` bytecode. From adfe7657a3f1ce5d8384694ed27a40376a18fa6c Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Fri, 4 Oct 2024 18:32:57 -0700 Subject: [PATCH 015/247] gh-124552 : Improve the accuracy of possible breakpoint check in bdb (#124553) --- Lib/bdb.py | 27 ++++++++++++-- Lib/test/test_pdb.py | 37 +++++++++++++++++++ ...-09-25-22-06-52.gh-issue-124552.1nQKNM.rst | 1 + 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst diff --git a/Lib/bdb.py b/Lib/bdb.py index d7543017940d4f..666f9714eb9b7a 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -3,6 +3,7 @@ import fnmatch import sys import os +import weakref from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR __all__ = ["BdbQuit", "Bdb", "Breakpoint"] @@ -36,6 +37,7 @@ def __init__(self, skip=None): self.frame_returning = None self.trace_opcodes = False self.enterframe = None + self.code_linenos = weakref.WeakKeyDictionary() self._load_breaks() @@ -155,6 +157,9 @@ def dispatch_return(self, frame, arg): if self.stop_here(frame) or frame == self.returnframe: # Ignore return events in generator except when stepping. if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS: + # It's possible to trigger a StopIteration exception in + # the caller so we must set the trace function in the caller + self._set_caller_tracefunc(frame) return self.trace_dispatch try: self.frame_returning = frame @@ -273,9 +278,25 @@ def do_clear(self, arg): raise NotImplementedError("subclass of bdb must implement do_clear()") def break_anywhere(self, frame): - """Return True if there is any breakpoint for frame's filename. + """Return True if there is any breakpoint in that frame """ - return self.canonic(frame.f_code.co_filename) in self.breaks + filename = self.canonic(frame.f_code.co_filename) + if filename not in self.breaks: + return False + for lineno in self.breaks[filename]: + if self._lineno_in_frame(lineno, frame): + return True + return False + + def _lineno_in_frame(self, lineno, frame): + """Return True if the line number is in the frame's code object. + """ + code = frame.f_code + if lineno < code.co_firstlineno: + return False + if code not in self.code_linenos: + self.code_linenos[code] = set(lineno for _, _, lineno in code.co_lines()) + return lineno in self.code_linenos[code] # Derived classes should override the user_* methods # to gain control. @@ -360,7 +381,7 @@ def set_next(self, frame): def set_return(self, frame): """Stop when returning from the given frame.""" if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS: - self._set_stopinfo(frame, None, -1) + self._set_stopinfo(frame, frame, -1) else: self._set_stopinfo(frame.f_back, frame) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 4c64a800cb32d2..46eb00261042bc 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -518,6 +518,43 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions(): (Pdb) continue """ +def test_pdb_break_anywhere(): + """Test break_anywhere() method of Pdb. + + >>> def outer(): + ... def inner(): + ... import pdb + ... import sys + ... p = pdb.Pdb(nosigint=True, readrc=False) + ... p.set_trace() + ... frame = sys._getframe() + ... print(p.break_anywhere(frame)) # inner + ... print(p.break_anywhere(frame.f_back)) # outer + ... print(p.break_anywhere(frame.f_back.f_back)) # caller + ... inner() + + >>> def caller(): + ... outer() + + >>> def test_function(): + ... caller() + + >>> reset_Breakpoint() + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'b 3', + ... 'c', + ... ]): + ... test_function() + > (6)inner() + -> p.set_trace() + (Pdb) b 3 + Breakpoint 1 at :3 + (Pdb) c + True + False + False + """ + def test_pdb_pp_repr_exc(): """Test that do_p/do_pp do not swallow exceptions. diff --git a/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst b/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst new file mode 100644 index 00000000000000..39dde4c774ba5d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst @@ -0,0 +1 @@ +Improve the accuracy of :mod:`bdb`'s check for the possibility of breakpoint in a frame. This makes it possible to disable unnecessary events in functions. From a5fc50994a3fae46d0c3d496c4e1d5e00548a1b8 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 5 Oct 2024 11:27:32 +0900 Subject: [PATCH 016/247] gh-112804: Clamping timeout value for _PySemaphore_PlatformWait (gh-124914) * gh-112804: Clamping timeout value for _PySemaphore_PlatformWait * Address code review * nit --- Python/parking_lot.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Python/parking_lot.c b/Python/parking_lot.c index 841b1d71ea16cb..a7e9760e35d87a 100644 --- a/Python/parking_lot.c +++ b/Python/parking_lot.c @@ -102,7 +102,14 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, PyTime_t timeout) millis = INFINITE; } else { - millis = (DWORD) (timeout / 1000000); + PyTime_t div = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_TIMEOUT); + // Prevent overflow with clamping the result + if ((PyTime_t)PY_DWORD_MAX < div) { + millis = PY_DWORD_MAX; + } + else { + millis = (DWORD) div; + } } wait = WaitForSingleObjectEx(sema->platform_sem, millis, FALSE); if (wait == WAIT_OBJECT_0) { From 16cd6cc86b3ba20074ae3eefb61aeb24ee1544f7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 5 Oct 2024 09:56:44 +0200 Subject: [PATCH 017/247] gh-111178: Fix function signatures in genobject.c (#124970) * Add "CAST" macros. * Rename parameters/variables "o" to "ag", "ags", "agw" or "agt" in some functions. --- Objects/genobject.c | 477 +++++++++++++++++++++++++------------------- 1 file changed, 271 insertions(+), 206 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c index 41cf8fdcc9dee8..19c2c4e3331a89 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -17,9 +17,20 @@ #include "pystats.h" -static PyObject *gen_close(PyGenObject *, PyObject *); -static PyObject *async_gen_asend_new(PyAsyncGenObject *, PyObject *); -static PyObject *async_gen_athrow_new(PyAsyncGenObject *, PyObject *); +// Forward declarations +static PyObject* gen_close(PyObject *, PyObject *); +static PyObject* async_gen_asend_new(PyAsyncGenObject *, PyObject *); +static PyObject* async_gen_athrow_new(PyAsyncGenObject *, PyObject *); + + +#define _PyGen_CAST(op) \ + _Py_CAST(PyGenObject*, (op)) +#define _PyCoroObject_CAST(op) \ + (assert(PyCoro_CheckExact(op)), \ + _Py_CAST(PyCoroObject*, (op))) +#define _PyAsyncGenObject_CAST(op) \ + _Py_CAST(PyAsyncGenObject*, (op)) + static const char *NON_INIT_CORO_MSG = "can't send non-None value to a " "just-started coroutine"; @@ -42,8 +53,9 @@ PyGen_GetCode(PyGenObject *gen) { } static int -gen_traverse(PyGenObject *gen, visitproc visit, void *arg) +gen_traverse(PyObject *self, visitproc visit, void *arg) { + PyGenObject *gen = _PyGen_CAST(self); Py_VISIT(gen->gi_name); Py_VISIT(gen->gi_qualname); if (gen->gi_frame_state != FRAME_CLEARED) { @@ -107,7 +119,7 @@ _PyGen_Finalize(PyObject *self) _PyErr_WarnUnawaitedCoroutine((PyObject *)gen); } else { - PyObject *res = gen_close(gen, NULL); + PyObject *res = gen_close((PyObject*)gen, NULL); if (res == NULL) { if (PyErr_Occurred()) { PyErr_WriteUnraisable(self); @@ -123,9 +135,9 @@ _PyGen_Finalize(PyObject *self) } static void -gen_dealloc(PyGenObject *gen) +gen_dealloc(PyObject *self) { - PyObject *self = (PyObject *) gen; + PyGenObject *gen = _PyGen_CAST(self); _PyObject_GC_UNTRACK(gen); @@ -262,8 +274,9 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, } static PySendResult -PyGen_am_send(PyGenObject *gen, PyObject *arg, PyObject **result) +PyGen_am_send(PyObject *self, PyObject *arg, PyObject **result) { + PyGenObject *gen = _PyGen_CAST(self); return gen_send_ex2(gen, arg, result, 0, 0); } @@ -292,9 +305,9 @@ PyDoc_STRVAR(send_doc, return next yielded value or raise StopIteration."); static PyObject * -gen_send(PyGenObject *gen, PyObject *arg) +gen_send(PyObject *gen, PyObject *arg) { - return gen_send_ex(gen, arg, 0, 0); + return gen_send_ex((PyGenObject*)gen, arg, 0, 0); } PyDoc_STRVAR(close_doc, @@ -311,7 +324,7 @@ gen_close_iter(PyObject *yf) PyObject *retval = NULL; if (PyGen_CheckExact(yf) || PyCoro_CheckExact(yf)) { - retval = gen_close((PyGenObject *)yf, NULL); + retval = gen_close((PyObject *)yf, NULL); if (retval == NULL) return -1; } @@ -356,11 +369,9 @@ _PyGen_yf(PyGenObject *gen) } static PyObject * -gen_close(PyGenObject *gen, PyObject *args) +gen_close(PyObject *self, PyObject *args) { - PyObject *retval; - int err = 0; - + PyGenObject *gen = _PyGen_CAST(self); if (gen->gi_frame_state == FRAME_CREATED) { gen->gi_frame_state = FRAME_COMPLETED; @@ -369,7 +380,9 @@ gen_close(PyGenObject *gen, PyObject *args) if (FRAME_STATE_FINISHED(gen->gi_frame_state)) { Py_RETURN_NONE; } + PyObject *yf = _PyGen_yf(gen); + int err = 0; if (yf) { PyFrameState state = gen->gi_frame_state; gen->gi_frame_state = FRAME_EXECUTING; @@ -394,7 +407,8 @@ gen_close(PyGenObject *gen, PyObject *args) if (err == 0) { PyErr_SetNone(PyExc_GeneratorExit); } - retval = gen_send_ex(gen, Py_None, 1, 1); + + PyObject *retval = gen_send_ex(gen, Py_None, 1, 1); if (retval) { const char *msg = "generator ignored GeneratorExit"; if (PyCoro_CheckExact(gen)) { @@ -407,10 +421,12 @@ gen_close(PyGenObject *gen, PyObject *args) return NULL; } assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_GeneratorExit)) { PyErr_Clear(); /* ignore this error */ Py_RETURN_NONE; } + /* if the generator returned a value while closing, StopIteration was * raised in gen_send_ex() above; retrieve and return the value here */ if (_PyGen_FetchStopIterationValue(&retval) == 0) { @@ -587,10 +603,12 @@ gen_throw(PyGenObject *gen, PyObject *const *args, Py_ssize_t nargs) static PyObject * -gen_iternext(PyGenObject *gen) +gen_iternext(PyObject *self) { + assert(PyGen_CheckExact(self) || PyCoro_CheckExact(self)); + PyGenObject *gen = _PyGen_CAST(self); + PyObject *result; - assert(PyGen_CheckExact(gen) || PyCoro_CheckExact(gen)); if (gen_send_ex2(gen, NULL, &result, 0, 0) == PYGEN_RETURN) { if (result != Py_None) { _PyGen_SetStopIterationValue(result); @@ -664,21 +682,24 @@ _PyGen_FetchStopIterationValue(PyObject **pvalue) } static PyObject * -gen_repr(PyGenObject *gen) +gen_repr(PyObject *self) { + PyGenObject *gen = _PyGen_CAST(self); return PyUnicode_FromFormat("", gen->gi_qualname, gen); } static PyObject * -gen_get_name(PyGenObject *op, void *Py_UNUSED(ignored)) +gen_get_name(PyObject *self, void *Py_UNUSED(ignored)) { + PyGenObject *op = _PyGen_CAST(self); return Py_NewRef(op->gi_name); } static int -gen_set_name(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored)) +gen_set_name(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyGenObject *op = _PyGen_CAST(self); /* Not legal to del gen.gi_name or to set it to anything * other than a string object. */ if (value == NULL || !PyUnicode_Check(value)) { @@ -691,14 +712,16 @@ gen_set_name(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored)) } static PyObject * -gen_get_qualname(PyGenObject *op, void *Py_UNUSED(ignored)) +gen_get_qualname(PyObject *self, void *Py_UNUSED(ignored)) { + PyGenObject *op = _PyGen_CAST(self); return Py_NewRef(op->gi_qualname); } static int -gen_set_qualname(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored)) +gen_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyGenObject *op = _PyGen_CAST(self); /* Not legal to del gen.__qualname__ or to set it to anything * other than a string object. */ if (value == NULL || !PyUnicode_Check(value)) { @@ -711,18 +734,20 @@ gen_set_qualname(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored)) } static PyObject * -gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored)) +gen_getyieldfrom(PyObject *gen, void *Py_UNUSED(ignored)) { - PyObject *yf = _PyGen_yf(gen); - if (yf == NULL) + PyObject *yf = _PyGen_yf(_PyGen_CAST(gen)); + if (yf == NULL) { Py_RETURN_NONE; + } return yf; } static PyObject * -gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored)) +gen_getrunning(PyObject *self, void *Py_UNUSED(ignored)) { + PyGenObject *gen = _PyGen_CAST(self); if (gen->gi_frame_state == FRAME_EXECUTING) { Py_RETURN_TRUE; } @@ -730,8 +755,9 @@ gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored)) } static PyObject * -gen_getsuspended(PyGenObject *gen, void *Py_UNUSED(ignored)) +gen_getsuspended(PyObject *self, void *Py_UNUSED(ignored)) { + PyGenObject *gen = _PyGen_CAST(self); return PyBool_FromLong(FRAME_STATE_SUSPENDED(gen->gi_frame_state)); } @@ -748,8 +774,9 @@ _gen_getframe(PyGenObject *gen, const char *const name) } static PyObject * -gen_getframe(PyGenObject *gen, void *Py_UNUSED(ignored)) +gen_getframe(PyObject *self, void *Py_UNUSED(ignored)) { + PyGenObject *gen = _PyGen_CAST(self); return _gen_getframe(gen, "gi_frame"); } @@ -763,22 +790,23 @@ _gen_getcode(PyGenObject *gen, const char *const name) } static PyObject * -gen_getcode(PyGenObject *gen, void *Py_UNUSED(ignored)) +gen_getcode(PyObject *self, void *Py_UNUSED(ignored)) { + PyGenObject *gen = _PyGen_CAST(self); return _gen_getcode(gen, "gi_code"); } static PyGetSetDef gen_getsetlist[] = { - {"__name__", (getter)gen_get_name, (setter)gen_set_name, + {"__name__", gen_get_name, gen_set_name, PyDoc_STR("name of the generator")}, - {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, + {"__qualname__", gen_get_qualname, gen_set_qualname, PyDoc_STR("qualified name of the generator")}, - {"gi_yieldfrom", (getter)gen_getyieldfrom, NULL, + {"gi_yieldfrom", gen_getyieldfrom, NULL, PyDoc_STR("object being iterated by yield from, or None")}, - {"gi_running", (getter)gen_getrunning, NULL, NULL}, - {"gi_frame", (getter)gen_getframe, NULL, NULL}, - {"gi_suspended", (getter)gen_getsuspended, NULL, NULL}, - {"gi_code", (getter)gen_getcode, NULL, NULL}, + {"gi_running", gen_getrunning, NULL, NULL}, + {"gi_frame", gen_getframe, NULL, NULL}, + {"gi_suspended", gen_getsuspended, NULL, NULL}, + {"gi_code", gen_getcode, NULL, NULL}, {NULL} /* Sentinel */ }; @@ -800,9 +828,9 @@ PyDoc_STRVAR(sizeof__doc__, "gen.__sizeof__() -> size of gen in memory, in bytes"); static PyMethodDef gen_methods[] = { - {"send",(PyCFunction)gen_send, METH_O, send_doc}, - {"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, throw_doc}, - {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, + {"send", gen_send, METH_O, send_doc}, + {"throw", _PyCFunction_CAST(gen_throw), METH_FASTCALL, throw_doc}, + {"close", gen_close, METH_NOARGS, close_doc}, {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {NULL, NULL} /* Sentinel */ @@ -812,7 +840,7 @@ static PyAsyncMethods gen_as_async = { 0, /* am_await */ 0, /* am_aiter */ 0, /* am_anext */ - (sendfunc)PyGen_am_send, /* am_send */ + PyGen_am_send, /* am_send */ }; @@ -822,12 +850,12 @@ PyTypeObject PyGen_Type = { offsetof(PyGenObject, gi_iframe.localsplus), /* tp_basicsize */ sizeof(PyObject *), /* tp_itemsize */ /* methods */ - (destructor)gen_dealloc, /* tp_dealloc */ + gen_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ &gen_as_async, /* tp_as_async */ - (reprfunc)gen_repr, /* tp_repr */ + gen_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -839,12 +867,12 @@ PyTypeObject PyGen_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - (traverseproc)gen_traverse, /* tp_traverse */ + gen_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof(PyGenObject, gi_weakreflist), /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ - (iternextfunc)gen_iternext, /* tp_iternext */ + gen_iternext, /* tp_iternext */ gen_methods, /* tp_methods */ gen_memberlist, /* tp_members */ gen_getsetlist, /* tp_getset */ @@ -903,17 +931,18 @@ _Py_MakeCoro(PyFunctionObject *func) return make_gen(&PyGen_Type, func); } if (coro_flags == CO_ASYNC_GENERATOR) { - PyAsyncGenObject *o; - o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, func); - if (o == NULL) { + PyAsyncGenObject *ag; + ag = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, func); + if (ag == NULL) { return NULL; } - o->ag_origin_or_finalizer = NULL; - o->ag_closed = 0; - o->ag_hooks_inited = 0; - o->ag_running_async = 0; - return (PyObject*)o; + ag->ag_origin_or_finalizer = NULL; + ag->ag_closed = 0; + ag->ag_hooks_inited = 0; + ag->ag_running_async = 0; + return (PyObject*)ag; } + assert (coro_flags == CO_COROUTINE); PyObject *coro = make_gen(&PyCoro_Type, func); if (!coro) { @@ -995,6 +1024,11 @@ typedef struct { PyCoroObject *cw_coroutine; } PyCoroWrapper; +#define _PyCoroWrapper_CAST(op) \ + (assert(Py_IS_TYPE((op), &_PyCoroWrapper_Type)), \ + _Py_CAST(PyCoroWrapper*, (op))) + + static int gen_is_coroutine(PyObject *o) { @@ -1057,14 +1091,15 @@ _PyCoro_GetAwaitableIter(PyObject *o) } static PyObject * -coro_repr(PyCoroObject *coro) +coro_repr(PyObject *self) { + PyCoroObject *coro = _PyCoroObject_CAST(self); return PyUnicode_FromFormat("", coro->cr_qualname, coro); } static PyObject * -coro_await(PyCoroObject *coro) +coro_await(PyObject *coro) { PyCoroWrapper *cw = PyObject_GC_New(PyCoroWrapper, &_PyCoroWrapper_Type); if (cw == NULL) { @@ -1076,7 +1111,7 @@ coro_await(PyCoroObject *coro) } static PyObject * -coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored)) +coro_get_cr_await(PyObject *coro, void *Py_UNUSED(ignored)) { PyObject *yf = _PyGen_yf((PyGenObject *) coro); if (yf == NULL) @@ -1085,8 +1120,9 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored)) } static PyObject * -cr_getsuspended(PyCoroObject *coro, void *Py_UNUSED(ignored)) +cr_getsuspended(PyObject *self, void *Py_UNUSED(ignored)) { + PyCoroObject *coro = _PyCoroObject_CAST(self); if (FRAME_STATE_SUSPENDED(coro->cr_frame_state)) { Py_RETURN_TRUE; } @@ -1094,8 +1130,9 @@ cr_getsuspended(PyCoroObject *coro, void *Py_UNUSED(ignored)) } static PyObject * -cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored)) +cr_getrunning(PyObject *self, void *Py_UNUSED(ignored)) { + PyCoroObject *coro = _PyCoroObject_CAST(self); if (coro->cr_frame_state == FRAME_EXECUTING) { Py_RETURN_TRUE; } @@ -1103,29 +1140,29 @@ cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored)) } static PyObject * -cr_getframe(PyCoroObject *coro, void *Py_UNUSED(ignored)) +cr_getframe(PyObject *coro, void *Py_UNUSED(ignored)) { - return _gen_getframe((PyGenObject *)coro, "cr_frame"); + return _gen_getframe(_PyGen_CAST(coro), "cr_frame"); } static PyObject * -cr_getcode(PyCoroObject *coro, void *Py_UNUSED(ignored)) +cr_getcode(PyObject *coro, void *Py_UNUSED(ignored)) { - return _gen_getcode((PyGenObject *)coro, "cr_code"); + return _gen_getcode(_PyGen_CAST(coro), "cr_code"); } static PyGetSetDef coro_getsetlist[] = { - {"__name__", (getter)gen_get_name, (setter)gen_set_name, + {"__name__", gen_get_name, gen_set_name, PyDoc_STR("name of the coroutine")}, - {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, + {"__qualname__", gen_get_qualname, gen_set_qualname, PyDoc_STR("qualified name of the coroutine")}, - {"cr_await", (getter)coro_get_cr_await, NULL, + {"cr_await", coro_get_cr_await, NULL, PyDoc_STR("object being awaited on, or None")}, - {"cr_running", (getter)cr_getrunning, NULL, NULL}, - {"cr_frame", (getter)cr_getframe, NULL, NULL}, - {"cr_code", (getter)cr_getcode, NULL, NULL}, - {"cr_suspended", (getter)cr_getsuspended, NULL, NULL}, + {"cr_running", cr_getrunning, NULL, NULL}, + {"cr_frame", cr_getframe, NULL, NULL}, + {"cr_code", cr_getcode, NULL, NULL}, + {"cr_suspended", cr_getsuspended, NULL, NULL}, {NULL} /* Sentinel */ }; @@ -1152,19 +1189,19 @@ PyDoc_STRVAR(coro_close_doc, "close() -> raise GeneratorExit inside coroutine."); static PyMethodDef coro_methods[] = { - {"send",(PyCFunction)gen_send, METH_O, coro_send_doc}, + {"send", gen_send, METH_O, coro_send_doc}, {"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, coro_throw_doc}, - {"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc}, + {"close", gen_close, METH_NOARGS, coro_close_doc}, {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {NULL, NULL} /* Sentinel */ }; static PyAsyncMethods coro_as_async = { - (unaryfunc)coro_await, /* am_await */ + coro_await, /* am_await */ 0, /* am_aiter */ 0, /* am_anext */ - (sendfunc)PyGen_am_send, /* am_send */ + PyGen_am_send, /* am_send */ }; PyTypeObject PyCoro_Type = { @@ -1173,12 +1210,12 @@ PyTypeObject PyCoro_Type = { offsetof(PyCoroObject, cr_iframe.localsplus),/* tp_basicsize */ sizeof(PyObject *), /* tp_itemsize */ /* methods */ - (destructor)gen_dealloc, /* tp_dealloc */ + gen_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ &coro_as_async, /* tp_as_async */ - (reprfunc)coro_repr, /* tp_repr */ + coro_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -1190,7 +1227,7 @@ PyTypeObject PyCoro_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - (traverseproc)gen_traverse, /* tp_traverse */ + gen_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof(PyCoroObject, cr_weakreflist), /* tp_weaklistoffset */ @@ -1220,49 +1257,55 @@ PyTypeObject PyCoro_Type = { }; static void -coro_wrapper_dealloc(PyCoroWrapper *cw) +coro_wrapper_dealloc(PyObject *self) { + PyCoroWrapper *cw = _PyCoroWrapper_CAST(self); _PyObject_GC_UNTRACK((PyObject *)cw); Py_CLEAR(cw->cw_coroutine); PyObject_GC_Del(cw); } static PyObject * -coro_wrapper_iternext(PyCoroWrapper *cw) +coro_wrapper_iternext(PyObject *self) { - return gen_iternext((PyGenObject *)cw->cw_coroutine); + PyCoroWrapper *cw = _PyCoroWrapper_CAST(self); + return gen_iternext((PyObject *)cw->cw_coroutine); } static PyObject * -coro_wrapper_send(PyCoroWrapper *cw, PyObject *arg) +coro_wrapper_send(PyObject *self, PyObject *arg) { - return gen_send((PyGenObject *)cw->cw_coroutine, arg); + PyCoroWrapper *cw = _PyCoroWrapper_CAST(self); + return gen_send((PyObject *)cw->cw_coroutine, arg); } static PyObject * -coro_wrapper_throw(PyCoroWrapper *cw, PyObject *const *args, Py_ssize_t nargs) +coro_wrapper_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { + PyCoroWrapper *cw = _PyCoroWrapper_CAST(self); return gen_throw((PyGenObject *)cw->cw_coroutine, args, nargs); } static PyObject * -coro_wrapper_close(PyCoroWrapper *cw, PyObject *args) +coro_wrapper_close(PyObject *self, PyObject *args) { - return gen_close((PyGenObject *)cw->cw_coroutine, args); + PyCoroWrapper *cw = _PyCoroWrapper_CAST(self); + return gen_close((PyObject *)cw->cw_coroutine, args); } static int -coro_wrapper_traverse(PyCoroWrapper *cw, visitproc visit, void *arg) +coro_wrapper_traverse(PyObject *self, visitproc visit, void *arg) { + PyCoroWrapper *cw = _PyCoroWrapper_CAST(self); Py_VISIT((PyObject *)cw->cw_coroutine); return 0; } static PyMethodDef coro_wrapper_methods[] = { - {"send",(PyCFunction)coro_wrapper_send, METH_O, coro_send_doc}, - {"throw",_PyCFunction_CAST(coro_wrapper_throw), - METH_FASTCALL, coro_throw_doc}, - {"close",(PyCFunction)coro_wrapper_close, METH_NOARGS, coro_close_doc}, + {"send", coro_wrapper_send, METH_O, coro_send_doc}, + {"throw", _PyCFunction_CAST(coro_wrapper_throw), METH_FASTCALL, + coro_throw_doc}, + {"close", coro_wrapper_close, METH_NOARGS, coro_close_doc}, {NULL, NULL} /* Sentinel */ }; @@ -1271,7 +1314,7 @@ PyTypeObject _PyCoroWrapper_Type = { "coroutine_wrapper", sizeof(PyCoroWrapper), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)coro_wrapper_dealloc, /* destructor tp_dealloc */ + coro_wrapper_dealloc, /* destructor tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -1288,12 +1331,12 @@ PyTypeObject _PyCoroWrapper_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ "A wrapper object implementing __await__ for coroutines.", - (traverseproc)coro_wrapper_traverse, /* tp_traverse */ + coro_wrapper_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ - (iternextfunc)coro_wrapper_iternext, /* tp_iternext */ + coro_wrapper_iternext, /* tp_iternext */ coro_wrapper_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ @@ -1387,6 +1430,9 @@ typedef struct PyAsyncGenASend { AwaitableState ags_state; } PyAsyncGenASend; +#define _PyAsyncGenASend_CAST(op) \ + _Py_CAST(PyAsyncGenASend*, (op)) + typedef struct PyAsyncGenAThrow { PyObject_HEAD @@ -1408,19 +1454,24 @@ typedef struct _PyAsyncGenWrappedValue { #define _PyAsyncGenWrappedValue_CheckExact(o) \ Py_IS_TYPE(o, &_PyAsyncGenWrappedValue_Type) +#define _PyAsyncGenWrappedValue_CAST(op) \ + (assert(_PyAsyncGenWrappedValue_CheckExact(op)), \ + _Py_CAST(_PyAsyncGenWrappedValue*, (op))) static int -async_gen_traverse(PyAsyncGenObject *gen, visitproc visit, void *arg) +async_gen_traverse(PyObject *self, visitproc visit, void *arg) { - Py_VISIT(gen->ag_origin_or_finalizer); - return gen_traverse((PyGenObject*)gen, visit, arg); + PyAsyncGenObject *ag = _PyAsyncGenObject_CAST(self); + Py_VISIT(ag->ag_origin_or_finalizer); + return gen_traverse((PyObject*)ag, visit, arg); } static PyObject * -async_gen_repr(PyAsyncGenObject *o) +async_gen_repr(PyObject *self) { + PyAsyncGenObject *o = _PyAsyncGenObject_CAST(self); return PyUnicode_FromFormat("", o->ag_qualname, o); } @@ -1464,12 +1515,13 @@ async_gen_init_hooks(PyAsyncGenObject *o) static PyObject * -async_gen_anext(PyAsyncGenObject *o) +async_gen_anext(PyObject *self) { - if (async_gen_init_hooks(o)) { + PyAsyncGenObject *ag = _PyAsyncGenObject_CAST(self); + if (async_gen_init_hooks(ag)) { return NULL; } - return async_gen_asend_new(o, NULL); + return async_gen_asend_new(ag, NULL); } @@ -1510,20 +1562,21 @@ async_gen_athrow(PyAsyncGenObject *o, PyObject *args) } static PyObject * -ag_getframe(PyAsyncGenObject *ag, void *Py_UNUSED(ignored)) +ag_getframe(PyObject *ag, void *Py_UNUSED(ignored)) { return _gen_getframe((PyGenObject *)ag, "ag_frame"); } static PyObject * -ag_getcode(PyGenObject *gen, void *Py_UNUSED(ignored)) +ag_getcode(PyObject *gen, void *Py_UNUSED(ignored)) { - return _gen_getcode(gen, "ag_code"); + return _gen_getcode((PyGenObject*)gen, "ag_code"); } static PyObject * -ag_getsuspended(PyAsyncGenObject *ag, void *Py_UNUSED(ignored)) +ag_getsuspended(PyObject *self, void *Py_UNUSED(ignored)) { + PyAsyncGenObject *ag = _PyAsyncGenObject_CAST(self); if (FRAME_STATE_SUSPENDED(ag->ag_frame_state)) { Py_RETURN_TRUE; } @@ -1531,15 +1584,15 @@ ag_getsuspended(PyAsyncGenObject *ag, void *Py_UNUSED(ignored)) } static PyGetSetDef async_gen_getsetlist[] = { - {"__name__", (getter)gen_get_name, (setter)gen_set_name, + {"__name__", gen_get_name, gen_set_name, PyDoc_STR("name of the async generator")}, - {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, + {"__qualname__", gen_get_qualname, gen_set_qualname, PyDoc_STR("qualified name of the async generator")}, - {"ag_await", (getter)coro_get_cr_await, NULL, + {"ag_await", coro_get_cr_await, NULL, PyDoc_STR("object being awaited on, or None")}, - {"ag_frame", (getter)ag_getframe, NULL, NULL}, - {"ag_code", (getter)ag_getcode, NULL, NULL}, - {"ag_suspended", (getter)ag_getsuspended, NULL, NULL}, + {"ag_frame", ag_getframe, NULL, NULL}, + {"ag_code", ag_getcode, NULL, NULL}, + {"ag_suspended", ag_getsuspended, NULL, NULL}, {NULL} /* Sentinel */ }; @@ -1577,8 +1630,8 @@ static PyMethodDef async_gen_methods[] = { static PyAsyncMethods async_gen_as_async = { 0, /* am_await */ PyObject_SelfIter, /* am_aiter */ - (unaryfunc)async_gen_anext, /* am_anext */ - (sendfunc)PyGen_am_send, /* am_send */ + async_gen_anext, /* am_anext */ + PyGen_am_send, /* am_send */ }; @@ -1588,12 +1641,12 @@ PyTypeObject PyAsyncGen_Type = { offsetof(PyAsyncGenObject, ag_iframe.localsplus), /* tp_basicsize */ sizeof(PyObject *), /* tp_itemsize */ /* methods */ - (destructor)gen_dealloc, /* tp_dealloc */ + gen_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ &async_gen_as_async, /* tp_as_async */ - (reprfunc)async_gen_repr, /* tp_repr */ + async_gen_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -1605,7 +1658,7 @@ PyTypeObject PyAsyncGen_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - (traverseproc)async_gen_traverse, /* tp_traverse */ + async_gen_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof(PyAsyncGenObject, ag_weakreflist), /* tp_weaklistoffset */ @@ -1638,17 +1691,18 @@ PyTypeObject PyAsyncGen_Type = { PyObject * PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) { - PyAsyncGenObject *o; - o = (PyAsyncGenObject *)gen_new_with_qualname( - &PyAsyncGen_Type, f, name, qualname); - if (o == NULL) { + PyAsyncGenObject *ag; + ag = (PyAsyncGenObject *)gen_new_with_qualname(&PyAsyncGen_Type, f, + name, qualname); + if (ag == NULL) { return NULL; } - o->ag_origin_or_finalizer = NULL; - o->ag_closed = 0; - o->ag_hooks_inited = 0; - o->ag_running_async = 0; - return (PyObject*)o; + + ag->ag_origin_or_finalizer = NULL; + ag->ag_closed = 0; + ag->ag_hooks_inited = 0; + ag->ag_running_async = 0; + return (PyObject*)ag; } static PyObject * @@ -1685,36 +1739,38 @@ async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result) static void -async_gen_asend_dealloc(PyAsyncGenASend *o) +async_gen_asend_dealloc(PyObject *self) { - if (PyObject_CallFinalizerFromDealloc((PyObject *)o)) { + assert(PyAsyncGenASend_CheckExact(self)); + PyAsyncGenASend *ags = _PyAsyncGenASend_CAST(self); + + if (PyObject_CallFinalizerFromDealloc(self)) { return; } - _PyObject_GC_UNTRACK((PyObject *)o); - Py_CLEAR(o->ags_gen); - Py_CLEAR(o->ags_sendval); + _PyObject_GC_UNTRACK(self); + Py_CLEAR(ags->ags_gen); + Py_CLEAR(ags->ags_sendval); - assert(PyAsyncGenASend_CheckExact(o)); - _PyGC_CLEAR_FINALIZED((PyObject *)o); + _PyGC_CLEAR_FINALIZED(self); - _Py_FREELIST_FREE(async_gen_asends, o, PyObject_GC_Del); + _Py_FREELIST_FREE(async_gen_asends, self, PyObject_GC_Del); } static int -async_gen_asend_traverse(PyAsyncGenASend *o, visitproc visit, void *arg) +async_gen_asend_traverse(PyObject *self, visitproc visit, void *arg) { - Py_VISIT(o->ags_gen); - Py_VISIT(o->ags_sendval); + PyAsyncGenASend *ags = _PyAsyncGenASend_CAST(self); + Py_VISIT(ags->ags_gen); + Py_VISIT(ags->ags_sendval); return 0; } static PyObject * -async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg) +async_gen_asend_send(PyObject *self, PyObject *arg) { - PyObject *result; - + PyAsyncGenASend *o = _PyAsyncGenASend_CAST(self); if (o->ags_state == AWAITABLE_STATE_CLOSED) { PyErr_SetString( PyExc_RuntimeError, @@ -1738,7 +1794,7 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg) } o->ags_gen->ag_running_async = 1; - result = gen_send((PyGenObject*)o->ags_gen, arg); + PyObject *result = gen_send((PyObject*)o->ags_gen, arg); result = async_gen_unwrap_value(o->ags_gen, result); if (result == NULL) { @@ -1750,16 +1806,16 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg) static PyObject * -async_gen_asend_iternext(PyAsyncGenASend *o) +async_gen_asend_iternext(PyObject *ags) { - return async_gen_asend_send(o, NULL); + return async_gen_asend_send(ags, NULL); } static PyObject * -async_gen_asend_throw(PyAsyncGenASend *o, PyObject *const *args, Py_ssize_t nargs) +async_gen_asend_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - PyObject *result; + PyAsyncGenASend *o = _PyAsyncGenASend_CAST(self); if (o->ags_state == AWAITABLE_STATE_CLOSED) { PyErr_SetString( @@ -1781,7 +1837,7 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *const *args, Py_ssize_t narg o->ags_gen->ag_running_async = 1; } - result = gen_throw((PyGenObject*)o->ags_gen, args, nargs); + PyObject *result = gen_throw((PyGenObject*)o->ags_gen, args, nargs); result = async_gen_unwrap_value(o->ags_gen, result); if (result == NULL) { @@ -1794,13 +1850,14 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *const *args, Py_ssize_t narg static PyObject * -async_gen_asend_close(PyAsyncGenASend *o, PyObject *args) +async_gen_asend_close(PyObject *self, PyObject *args) { - PyObject *result; + PyAsyncGenASend *o = _PyAsyncGenASend_CAST(self); if (o->ags_state == AWAITABLE_STATE_CLOSED) { Py_RETURN_NONE; } - result = async_gen_asend_throw(o, &PyExc_GeneratorExit, 1); + + PyObject *result = async_gen_asend_throw(self, &PyExc_GeneratorExit, 1); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_StopIteration) || PyErr_ExceptionMatches(PyExc_StopAsyncIteration) || @@ -1810,25 +1867,26 @@ async_gen_asend_close(PyAsyncGenASend *o, PyObject *args) Py_RETURN_NONE; } return result; - } else { - Py_DECREF(result); - PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit"); - return NULL; } + + Py_DECREF(result); + PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit"); + return NULL; } static void -async_gen_asend_finalize(PyAsyncGenASend *o) +async_gen_asend_finalize(PyObject *self) { - if (o->ags_state == AWAITABLE_STATE_INIT) { - _PyErr_WarnUnawaitedAgenMethod(o->ags_gen, &_Py_ID(asend)); + PyAsyncGenASend *ags = _PyAsyncGenASend_CAST(self); + if (ags->ags_state == AWAITABLE_STATE_INIT) { + _PyErr_WarnUnawaitedAgenMethod(ags->ags_gen, &_Py_ID(asend)); } } static PyMethodDef async_gen_asend_methods[] = { - {"send", (PyCFunction)async_gen_asend_send, METH_O, send_doc}, + {"send", async_gen_asend_send, METH_O, send_doc}, {"throw", _PyCFunction_CAST(async_gen_asend_throw), METH_FASTCALL, throw_doc}, - {"close", (PyCFunction)async_gen_asend_close, METH_NOARGS, close_doc}, + {"close", async_gen_asend_close, METH_NOARGS, close_doc}, {NULL, NULL} /* Sentinel */ }; @@ -1847,7 +1905,7 @@ PyTypeObject _PyAsyncGenASend_Type = { sizeof(PyAsyncGenASend), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)async_gen_asend_dealloc, /* tp_dealloc */ + async_gen_asend_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -1864,12 +1922,12 @@ PyTypeObject _PyAsyncGenASend_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - (traverseproc)async_gen_asend_traverse, /* tp_traverse */ + async_gen_asend_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ - (iternextfunc)async_gen_asend_iternext, /* tp_iternext */ + async_gen_asend_iternext, /* tp_iternext */ async_gen_asend_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ @@ -1881,29 +1939,27 @@ PyTypeObject _PyAsyncGenASend_Type = { 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ - .tp_finalize = (destructor)async_gen_asend_finalize, + .tp_finalize = async_gen_asend_finalize, }; static PyObject * async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval) { - PyAsyncGenASend *o = _Py_FREELIST_POP(PyAsyncGenASend, async_gen_asends); - if (o == NULL) { - o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type); - if (o == NULL) { + PyAsyncGenASend *ags = _Py_FREELIST_POP(PyAsyncGenASend, async_gen_asends); + if (ags == NULL) { + ags = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type); + if (ags == NULL) { return NULL; } } - o->ags_gen = (PyAsyncGenObject*)Py_NewRef(gen); - - o->ags_sendval = Py_XNewRef(sendval); + ags->ags_gen = (PyAsyncGenObject*)Py_NewRef(gen); + ags->ags_sendval = Py_XNewRef(sendval); + ags->ags_state = AWAITABLE_STATE_INIT; - o->ags_state = AWAITABLE_STATE_INIT; - - _PyObject_GC_TRACK((PyObject*)o); - return (PyObject*)o; + _PyObject_GC_TRACK((PyObject*)ags); + return (PyObject*)ags; } @@ -1911,19 +1967,20 @@ async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval) static void -async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o) +async_gen_wrapped_val_dealloc(PyObject *self) { - _PyObject_GC_UNTRACK((PyObject *)o); - Py_CLEAR(o->agw_val); - _Py_FREELIST_FREE(async_gens, o, PyObject_GC_Del); + _PyAsyncGenWrappedValue *agw = _PyAsyncGenWrappedValue_CAST(self); + _PyObject_GC_UNTRACK(self); + Py_CLEAR(agw->agw_val); + _Py_FREELIST_FREE(async_gens, self, PyObject_GC_Del); } static int -async_gen_wrapped_val_traverse(_PyAsyncGenWrappedValue *o, - visitproc visit, void *arg) +async_gen_wrapped_val_traverse(PyObject *self, visitproc visit, void *arg) { - Py_VISIT(o->agw_val); + _PyAsyncGenWrappedValue *agw = _PyAsyncGenWrappedValue_CAST(self); + Py_VISIT(agw->agw_val); return 0; } @@ -1934,7 +1991,7 @@ PyTypeObject _PyAsyncGenWrappedValue_Type = { sizeof(_PyAsyncGenWrappedValue), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)async_gen_wrapped_val_dealloc, /* tp_dealloc */ + async_gen_wrapped_val_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -1951,7 +2008,7 @@ PyTypeObject _PyAsyncGenWrappedValue_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - (traverseproc)async_gen_wrapped_val_traverse, /* tp_traverse */ + async_gen_wrapped_val_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ @@ -1993,34 +2050,40 @@ _PyAsyncGenValueWrapperNew(PyThreadState *tstate, PyObject *val) /* ---------- Async Generator AThrow awaitable ------------ */ +#define _PyAsyncGenAThrow_CAST(op) \ + (assert(Py_IS_TYPE((op), &_PyAsyncGenAThrow_Type)), \ + _Py_CAST(PyAsyncGenAThrow*, (op))) static void -async_gen_athrow_dealloc(PyAsyncGenAThrow *o) +async_gen_athrow_dealloc(PyObject *self) { - if (PyObject_CallFinalizerFromDealloc((PyObject *)o)) { + PyAsyncGenAThrow *agt = _PyAsyncGenAThrow_CAST(self); + if (PyObject_CallFinalizerFromDealloc(self)) { return; } - _PyObject_GC_UNTRACK((PyObject *)o); - Py_CLEAR(o->agt_gen); - Py_CLEAR(o->agt_args); - PyObject_GC_Del(o); + _PyObject_GC_UNTRACK(self); + Py_CLEAR(agt->agt_gen); + Py_CLEAR(agt->agt_args); + PyObject_GC_Del(self); } static int -async_gen_athrow_traverse(PyAsyncGenAThrow *o, visitproc visit, void *arg) +async_gen_athrow_traverse(PyObject *self, visitproc visit, void *arg) { - Py_VISIT(o->agt_gen); - Py_VISIT(o->agt_args); + PyAsyncGenAThrow *agt = _PyAsyncGenAThrow_CAST(self); + Py_VISIT(agt->agt_gen); + Py_VISIT(agt->agt_args); return 0; } static PyObject * -async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) +async_gen_athrow_send(PyObject *self, PyObject *arg) { - PyGenObject *gen = (PyGenObject*)o->agt_gen; + PyAsyncGenAThrow *o = _PyAsyncGenAThrow_CAST(self); + PyGenObject *gen = _PyGen_CAST(o->agt_gen); PyObject *retval; if (o->agt_state == AWAITABLE_STATE_CLOSED) { @@ -2103,7 +2166,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) assert(o->agt_state == AWAITABLE_STATE_ITER); - retval = gen_send((PyGenObject *)gen, arg); + retval = gen_send((PyObject *)gen, arg); if (o->agt_args) { return async_gen_unwrap_value(o->agt_gen, retval); } else { @@ -2150,9 +2213,9 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) static PyObject * -async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t nargs) +async_gen_athrow_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - PyObject *retval; + PyAsyncGenAThrow *o = _PyAsyncGenAThrow_CAST(self); if (o->agt_state == AWAITABLE_STATE_CLOSED) { PyErr_SetString( @@ -2181,7 +2244,7 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t na o->agt_gen->ag_running_async = 1; } - retval = gen_throw((PyGenObject*)o->agt_gen, args, nargs); + PyObject *retval = gen_throw((PyGenObject*)o->agt_gen, args, nargs); if (o->agt_args) { retval = async_gen_unwrap_value(o->agt_gen, retval); if (retval == NULL) { @@ -2189,7 +2252,8 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t na o->agt_state = AWAITABLE_STATE_CLOSED; } return retval; - } else { + } + else { /* aclose() mode */ if (retval && _PyAsyncGenWrappedValue_CheckExact(retval)) { o->agt_gen->ag_running_async = 0; @@ -2219,20 +2283,21 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t na static PyObject * -async_gen_athrow_iternext(PyAsyncGenAThrow *o) +async_gen_athrow_iternext(PyObject *agt) { - return async_gen_athrow_send(o, Py_None); + return async_gen_athrow_send(agt, Py_None); } static PyObject * -async_gen_athrow_close(PyAsyncGenAThrow *o, PyObject *args) +async_gen_athrow_close(PyObject *self, PyObject *args) { - PyObject *result; - if (o->agt_state == AWAITABLE_STATE_CLOSED) { + PyAsyncGenAThrow *agt = _PyAsyncGenAThrow_CAST(self); + if (agt->agt_state == AWAITABLE_STATE_CLOSED) { Py_RETURN_NONE; } - result = async_gen_athrow_throw(o, &PyExc_GeneratorExit, 1); + PyObject *result = async_gen_athrow_throw((PyObject*)agt, + &PyExc_GeneratorExit, 1); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_StopIteration) || PyErr_ExceptionMatches(PyExc_StopAsyncIteration) || @@ -2260,10 +2325,10 @@ async_gen_athrow_finalize(PyAsyncGenAThrow *o) } static PyMethodDef async_gen_athrow_methods[] = { - {"send", (PyCFunction)async_gen_athrow_send, METH_O, send_doc}, + {"send", async_gen_athrow_send, METH_O, send_doc}, {"throw", _PyCFunction_CAST(async_gen_athrow_throw), METH_FASTCALL, throw_doc}, - {"close", (PyCFunction)async_gen_athrow_close, METH_NOARGS, close_doc}, + {"close", async_gen_athrow_close, METH_NOARGS, close_doc}, {NULL, NULL} /* Sentinel */ }; @@ -2282,7 +2347,7 @@ PyTypeObject _PyAsyncGenAThrow_Type = { sizeof(PyAsyncGenAThrow), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)async_gen_athrow_dealloc, /* tp_dealloc */ + async_gen_athrow_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -2299,12 +2364,12 @@ PyTypeObject _PyAsyncGenAThrow_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - (traverseproc)async_gen_athrow_traverse, /* tp_traverse */ + async_gen_athrow_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ - (iternextfunc)async_gen_athrow_iternext, /* tp_iternext */ + async_gen_athrow_iternext, /* tp_iternext */ async_gen_athrow_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ From 39c859f6ffd8dee7f48b2181c6cb59cffe8125ff Mon Sep 17 00:00:00 2001 From: Rigel Di Scala Date: Sun, 6 Oct 2024 11:55:56 +0200 Subject: [PATCH 018/247] gh-122951: Simplify the grammar of the assignment rule (#124998) --- Grammar/python.gram | 4 +- Parser/parser.c | 3359 +++++++++++++++++++++---------------------- 2 files changed, 1652 insertions(+), 1711 deletions(-) diff --git a/Grammar/python.gram b/Grammar/python.gram index e9a8c69c4fa27c..b47028460b94f4 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -151,9 +151,9 @@ assignment[stmt_ty]: | a=('(' b=single_target ')' { b } | single_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] { CHECK_VERSION(stmt_ty, 6, "Variable annotations syntax is", _PyAST_AnnAssign(a, b, c, 0, EXTRA)) } - | a[asdl_expr_seq*]=(z=star_targets '=' { z })+ b=(yield_expr | star_expressions) !'=' tc=[TYPE_COMMENT] { + | a[asdl_expr_seq*]=(z=star_targets '=' { z })+ b=annotated_rhs !'=' tc=[TYPE_COMMENT] { _PyAST_Assign(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) } - | a=single_target b=augassign ~ c=(yield_expr | star_expressions) { + | a=single_target b=augassign ~ c=annotated_rhs { _PyAST_AugAssign(a, b->kind, c, EXTRA) } | invalid_assignment diff --git a/Parser/parser.c b/Parser/parser.c index 01ecb7498710a9..9ff58ab7e7bfd5 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -350,99 +350,99 @@ static char *soft_keywords[] = { #define _tmp_11_type 1263 #define _loop1_12_type 1264 #define _tmp_13_type 1265 -#define _tmp_14_type 1266 -#define _loop0_15_type 1267 -#define _gather_16_type 1268 +#define _loop0_14_type 1266 +#define _gather_15_type 1267 +#define _tmp_16_type 1268 #define _tmp_17_type 1269 -#define _tmp_18_type 1270 -#define _loop0_19_type 1271 -#define _loop1_20_type 1272 -#define _loop0_21_type 1273 -#define _gather_22_type 1274 -#define _tmp_23_type 1275 -#define _loop0_24_type 1276 -#define _gather_25_type 1277 -#define _loop1_26_type 1278 +#define _loop0_18_type 1270 +#define _loop1_19_type 1271 +#define _loop0_20_type 1272 +#define _gather_21_type 1273 +#define _tmp_22_type 1274 +#define _loop0_23_type 1275 +#define _gather_24_type 1276 +#define _loop1_25_type 1277 +#define _tmp_26_type 1278 #define _tmp_27_type 1279 -#define _tmp_28_type 1280 +#define _loop0_28_type 1280 #define _loop0_29_type 1281 -#define _loop0_30_type 1282 +#define _loop1_30_type 1282 #define _loop1_31_type 1283 -#define _loop1_32_type 1284 -#define _loop0_33_type 1285 -#define _loop1_34_type 1286 -#define _loop0_35_type 1287 -#define _gather_36_type 1288 -#define _tmp_37_type 1289 +#define _loop0_32_type 1284 +#define _loop1_33_type 1285 +#define _loop0_34_type 1286 +#define _gather_35_type 1287 +#define _tmp_36_type 1288 +#define _loop1_37_type 1289 #define _loop1_38_type 1290 #define _loop1_39_type 1291 -#define _loop1_40_type 1292 -#define _loop0_41_type 1293 -#define _gather_42_type 1294 +#define _loop0_40_type 1292 +#define _gather_41_type 1293 +#define _tmp_42_type 1294 #define _tmp_43_type 1295 -#define _tmp_44_type 1296 -#define _loop0_45_type 1297 -#define _gather_46_type 1298 -#define _loop0_47_type 1299 -#define _gather_48_type 1300 -#define _tmp_49_type 1301 -#define _loop0_50_type 1302 -#define _gather_51_type 1303 -#define _loop0_52_type 1304 -#define _gather_53_type 1305 -#define _loop0_54_type 1306 -#define _gather_55_type 1307 +#define _loop0_44_type 1296 +#define _gather_45_type 1297 +#define _loop0_46_type 1298 +#define _gather_47_type 1299 +#define _tmp_48_type 1300 +#define _loop0_49_type 1301 +#define _gather_50_type 1302 +#define _loop0_51_type 1303 +#define _gather_52_type 1304 +#define _loop0_53_type 1305 +#define _gather_54_type 1306 +#define _loop1_55_type 1307 #define _loop1_56_type 1308 -#define _loop1_57_type 1309 -#define _loop0_58_type 1310 -#define _gather_59_type 1311 +#define _loop0_57_type 1309 +#define _gather_58_type 1310 +#define _loop1_59_type 1311 #define _loop1_60_type 1312 #define _loop1_61_type 1313 -#define _loop1_62_type 1314 -#define _tmp_63_type 1315 -#define _loop0_64_type 1316 -#define _gather_65_type 1317 +#define _tmp_62_type 1314 +#define _loop0_63_type 1315 +#define _gather_64_type 1316 +#define _tmp_65_type 1317 #define _tmp_66_type 1318 #define _tmp_67_type 1319 #define _tmp_68_type 1320 #define _tmp_69_type 1321 #define _tmp_70_type 1322 -#define _tmp_71_type 1323 +#define _loop0_71_type 1323 #define _loop0_72_type 1324 -#define _loop0_73_type 1325 +#define _loop1_73_type 1325 #define _loop1_74_type 1326 -#define _loop1_75_type 1327 -#define _loop0_76_type 1328 -#define _loop1_77_type 1329 +#define _loop0_75_type 1327 +#define _loop1_76_type 1328 +#define _loop0_77_type 1329 #define _loop0_78_type 1330 -#define _loop0_79_type 1331 -#define _loop1_80_type 1332 -#define _tmp_81_type 1333 -#define _loop0_82_type 1334 -#define _gather_83_type 1335 -#define _loop1_84_type 1336 -#define _loop0_85_type 1337 -#define _tmp_86_type 1338 -#define _loop0_87_type 1339 -#define _gather_88_type 1340 -#define _tmp_89_type 1341 -#define _loop0_90_type 1342 -#define _gather_91_type 1343 -#define _loop0_92_type 1344 -#define _gather_93_type 1345 +#define _loop1_79_type 1331 +#define _tmp_80_type 1332 +#define _loop0_81_type 1333 +#define _gather_82_type 1334 +#define _loop1_83_type 1335 +#define _loop0_84_type 1336 +#define _tmp_85_type 1337 +#define _loop0_86_type 1338 +#define _gather_87_type 1339 +#define _tmp_88_type 1340 +#define _loop0_89_type 1341 +#define _gather_90_type 1342 +#define _loop0_91_type 1343 +#define _gather_92_type 1344 +#define _loop0_93_type 1345 #define _loop0_94_type 1346 -#define _loop0_95_type 1347 -#define _gather_96_type 1348 -#define _loop1_97_type 1349 -#define _tmp_98_type 1350 -#define _loop0_99_type 1351 -#define _gather_100_type 1352 -#define _loop0_101_type 1353 -#define _gather_102_type 1354 +#define _gather_95_type 1347 +#define _loop1_96_type 1348 +#define _tmp_97_type 1349 +#define _loop0_98_type 1350 +#define _gather_99_type 1351 +#define _loop0_100_type 1352 +#define _gather_101_type 1353 +#define _tmp_102_type 1354 #define _tmp_103_type 1355 -#define _tmp_104_type 1356 -#define _loop0_105_type 1357 -#define _gather_106_type 1358 +#define _loop0_104_type 1356 +#define _gather_105_type 1357 +#define _tmp_106_type 1358 #define _tmp_107_type 1359 #define _tmp_108_type 1360 #define _tmp_109_type 1361 @@ -451,9 +451,9 @@ static char *soft_keywords[] = { #define _tmp_112_type 1364 #define _tmp_113_type 1365 #define _tmp_114_type 1366 -#define _tmp_115_type 1367 +#define _loop0_115_type 1367 #define _loop0_116_type 1368 -#define _loop0_117_type 1369 +#define _tmp_117_type 1369 #define _tmp_118_type 1370 #define _tmp_119_type 1371 #define _tmp_120_type 1372 @@ -462,21 +462,21 @@ static char *soft_keywords[] = { #define _tmp_123_type 1375 #define _tmp_124_type 1376 #define _tmp_125_type 1377 -#define _tmp_126_type 1378 -#define _loop0_127_type 1379 -#define _gather_128_type 1380 +#define _loop0_126_type 1378 +#define _gather_127_type 1379 +#define _tmp_128_type 1380 #define _tmp_129_type 1381 #define _tmp_130_type 1382 #define _tmp_131_type 1383 -#define _tmp_132_type 1384 -#define _loop0_133_type 1385 -#define _gather_134_type 1386 -#define _loop0_135_type 1387 -#define _gather_136_type 1388 -#define _loop0_137_type 1389 -#define _gather_138_type 1390 -#define _tmp_139_type 1391 -#define _loop0_140_type 1392 +#define _loop0_132_type 1384 +#define _gather_133_type 1385 +#define _loop0_134_type 1386 +#define _gather_135_type 1387 +#define _loop0_136_type 1388 +#define _gather_137_type 1389 +#define _tmp_138_type 1390 +#define _loop0_139_type 1391 +#define _tmp_140_type 1392 #define _tmp_141_type 1393 #define _tmp_142_type 1394 #define _tmp_143_type 1395 @@ -501,12 +501,11 @@ static char *soft_keywords[] = { #define _tmp_162_type 1414 #define _tmp_163_type 1415 #define _tmp_164_type 1416 -#define _tmp_165_type 1417 -#define _loop0_166_type 1418 +#define _loop0_165_type 1417 +#define _tmp_166_type 1418 #define _tmp_167_type 1419 #define _tmp_168_type 1420 #define _tmp_169_type 1421 -#define _tmp_170_type 1422 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -774,99 +773,99 @@ static void *_tmp_10_rule(Parser *p); static void *_tmp_11_rule(Parser *p); static asdl_seq *_loop1_12_rule(Parser *p); static void *_tmp_13_rule(Parser *p); -static void *_tmp_14_rule(Parser *p); -static asdl_seq *_loop0_15_rule(Parser *p); -static asdl_seq *_gather_16_rule(Parser *p); +static asdl_seq *_loop0_14_rule(Parser *p); +static asdl_seq *_gather_15_rule(Parser *p); +static void *_tmp_16_rule(Parser *p); static void *_tmp_17_rule(Parser *p); -static void *_tmp_18_rule(Parser *p); -static asdl_seq *_loop0_19_rule(Parser *p); -static asdl_seq *_loop1_20_rule(Parser *p); -static asdl_seq *_loop0_21_rule(Parser *p); -static asdl_seq *_gather_22_rule(Parser *p); -static void *_tmp_23_rule(Parser *p); -static asdl_seq *_loop0_24_rule(Parser *p); -static asdl_seq *_gather_25_rule(Parser *p); -static asdl_seq *_loop1_26_rule(Parser *p); +static asdl_seq *_loop0_18_rule(Parser *p); +static asdl_seq *_loop1_19_rule(Parser *p); +static asdl_seq *_loop0_20_rule(Parser *p); +static asdl_seq *_gather_21_rule(Parser *p); +static void *_tmp_22_rule(Parser *p); +static asdl_seq *_loop0_23_rule(Parser *p); +static asdl_seq *_gather_24_rule(Parser *p); +static asdl_seq *_loop1_25_rule(Parser *p); +static void *_tmp_26_rule(Parser *p); static void *_tmp_27_rule(Parser *p); -static void *_tmp_28_rule(Parser *p); +static asdl_seq *_loop0_28_rule(Parser *p); static asdl_seq *_loop0_29_rule(Parser *p); -static asdl_seq *_loop0_30_rule(Parser *p); +static asdl_seq *_loop1_30_rule(Parser *p); static asdl_seq *_loop1_31_rule(Parser *p); -static asdl_seq *_loop1_32_rule(Parser *p); -static asdl_seq *_loop0_33_rule(Parser *p); -static asdl_seq *_loop1_34_rule(Parser *p); -static asdl_seq *_loop0_35_rule(Parser *p); -static asdl_seq *_gather_36_rule(Parser *p); -static void *_tmp_37_rule(Parser *p); +static asdl_seq *_loop0_32_rule(Parser *p); +static asdl_seq *_loop1_33_rule(Parser *p); +static asdl_seq *_loop0_34_rule(Parser *p); +static asdl_seq *_gather_35_rule(Parser *p); +static void *_tmp_36_rule(Parser *p); +static asdl_seq *_loop1_37_rule(Parser *p); static asdl_seq *_loop1_38_rule(Parser *p); static asdl_seq *_loop1_39_rule(Parser *p); -static asdl_seq *_loop1_40_rule(Parser *p); -static asdl_seq *_loop0_41_rule(Parser *p); -static asdl_seq *_gather_42_rule(Parser *p); +static asdl_seq *_loop0_40_rule(Parser *p); +static asdl_seq *_gather_41_rule(Parser *p); +static void *_tmp_42_rule(Parser *p); static void *_tmp_43_rule(Parser *p); -static void *_tmp_44_rule(Parser *p); -static asdl_seq *_loop0_45_rule(Parser *p); -static asdl_seq *_gather_46_rule(Parser *p); -static asdl_seq *_loop0_47_rule(Parser *p); -static asdl_seq *_gather_48_rule(Parser *p); -static void *_tmp_49_rule(Parser *p); -static asdl_seq *_loop0_50_rule(Parser *p); -static asdl_seq *_gather_51_rule(Parser *p); -static asdl_seq *_loop0_52_rule(Parser *p); -static asdl_seq *_gather_53_rule(Parser *p); -static asdl_seq *_loop0_54_rule(Parser *p); -static asdl_seq *_gather_55_rule(Parser *p); +static asdl_seq *_loop0_44_rule(Parser *p); +static asdl_seq *_gather_45_rule(Parser *p); +static asdl_seq *_loop0_46_rule(Parser *p); +static asdl_seq *_gather_47_rule(Parser *p); +static void *_tmp_48_rule(Parser *p); +static asdl_seq *_loop0_49_rule(Parser *p); +static asdl_seq *_gather_50_rule(Parser *p); +static asdl_seq *_loop0_51_rule(Parser *p); +static asdl_seq *_gather_52_rule(Parser *p); +static asdl_seq *_loop0_53_rule(Parser *p); +static asdl_seq *_gather_54_rule(Parser *p); +static asdl_seq *_loop1_55_rule(Parser *p); static asdl_seq *_loop1_56_rule(Parser *p); -static asdl_seq *_loop1_57_rule(Parser *p); -static asdl_seq *_loop0_58_rule(Parser *p); -static asdl_seq *_gather_59_rule(Parser *p); +static asdl_seq *_loop0_57_rule(Parser *p); +static asdl_seq *_gather_58_rule(Parser *p); +static asdl_seq *_loop1_59_rule(Parser *p); static asdl_seq *_loop1_60_rule(Parser *p); static asdl_seq *_loop1_61_rule(Parser *p); -static asdl_seq *_loop1_62_rule(Parser *p); -static void *_tmp_63_rule(Parser *p); -static asdl_seq *_loop0_64_rule(Parser *p); -static asdl_seq *_gather_65_rule(Parser *p); +static void *_tmp_62_rule(Parser *p); +static asdl_seq *_loop0_63_rule(Parser *p); +static asdl_seq *_gather_64_rule(Parser *p); +static void *_tmp_65_rule(Parser *p); static void *_tmp_66_rule(Parser *p); static void *_tmp_67_rule(Parser *p); static void *_tmp_68_rule(Parser *p); static void *_tmp_69_rule(Parser *p); static void *_tmp_70_rule(Parser *p); -static void *_tmp_71_rule(Parser *p); +static asdl_seq *_loop0_71_rule(Parser *p); static asdl_seq *_loop0_72_rule(Parser *p); -static asdl_seq *_loop0_73_rule(Parser *p); +static asdl_seq *_loop1_73_rule(Parser *p); static asdl_seq *_loop1_74_rule(Parser *p); -static asdl_seq *_loop1_75_rule(Parser *p); -static asdl_seq *_loop0_76_rule(Parser *p); -static asdl_seq *_loop1_77_rule(Parser *p); +static asdl_seq *_loop0_75_rule(Parser *p); +static asdl_seq *_loop1_76_rule(Parser *p); +static asdl_seq *_loop0_77_rule(Parser *p); static asdl_seq *_loop0_78_rule(Parser *p); -static asdl_seq *_loop0_79_rule(Parser *p); -static asdl_seq *_loop1_80_rule(Parser *p); -static void *_tmp_81_rule(Parser *p); -static asdl_seq *_loop0_82_rule(Parser *p); -static asdl_seq *_gather_83_rule(Parser *p); -static asdl_seq *_loop1_84_rule(Parser *p); -static asdl_seq *_loop0_85_rule(Parser *p); -static void *_tmp_86_rule(Parser *p); -static asdl_seq *_loop0_87_rule(Parser *p); -static asdl_seq *_gather_88_rule(Parser *p); -static void *_tmp_89_rule(Parser *p); -static asdl_seq *_loop0_90_rule(Parser *p); -static asdl_seq *_gather_91_rule(Parser *p); -static asdl_seq *_loop0_92_rule(Parser *p); -static asdl_seq *_gather_93_rule(Parser *p); +static asdl_seq *_loop1_79_rule(Parser *p); +static void *_tmp_80_rule(Parser *p); +static asdl_seq *_loop0_81_rule(Parser *p); +static asdl_seq *_gather_82_rule(Parser *p); +static asdl_seq *_loop1_83_rule(Parser *p); +static asdl_seq *_loop0_84_rule(Parser *p); +static void *_tmp_85_rule(Parser *p); +static asdl_seq *_loop0_86_rule(Parser *p); +static asdl_seq *_gather_87_rule(Parser *p); +static void *_tmp_88_rule(Parser *p); +static asdl_seq *_loop0_89_rule(Parser *p); +static asdl_seq *_gather_90_rule(Parser *p); +static asdl_seq *_loop0_91_rule(Parser *p); +static asdl_seq *_gather_92_rule(Parser *p); +static asdl_seq *_loop0_93_rule(Parser *p); static asdl_seq *_loop0_94_rule(Parser *p); -static asdl_seq *_loop0_95_rule(Parser *p); -static asdl_seq *_gather_96_rule(Parser *p); -static asdl_seq *_loop1_97_rule(Parser *p); -static void *_tmp_98_rule(Parser *p); -static asdl_seq *_loop0_99_rule(Parser *p); -static asdl_seq *_gather_100_rule(Parser *p); -static asdl_seq *_loop0_101_rule(Parser *p); -static asdl_seq *_gather_102_rule(Parser *p); +static asdl_seq *_gather_95_rule(Parser *p); +static asdl_seq *_loop1_96_rule(Parser *p); +static void *_tmp_97_rule(Parser *p); +static asdl_seq *_loop0_98_rule(Parser *p); +static asdl_seq *_gather_99_rule(Parser *p); +static asdl_seq *_loop0_100_rule(Parser *p); +static asdl_seq *_gather_101_rule(Parser *p); +static void *_tmp_102_rule(Parser *p); static void *_tmp_103_rule(Parser *p); -static void *_tmp_104_rule(Parser *p); -static asdl_seq *_loop0_105_rule(Parser *p); -static asdl_seq *_gather_106_rule(Parser *p); +static asdl_seq *_loop0_104_rule(Parser *p); +static asdl_seq *_gather_105_rule(Parser *p); +static void *_tmp_106_rule(Parser *p); static void *_tmp_107_rule(Parser *p); static void *_tmp_108_rule(Parser *p); static void *_tmp_109_rule(Parser *p); @@ -875,9 +874,9 @@ static void *_tmp_111_rule(Parser *p); static void *_tmp_112_rule(Parser *p); static void *_tmp_113_rule(Parser *p); static void *_tmp_114_rule(Parser *p); -static void *_tmp_115_rule(Parser *p); +static asdl_seq *_loop0_115_rule(Parser *p); static asdl_seq *_loop0_116_rule(Parser *p); -static asdl_seq *_loop0_117_rule(Parser *p); +static void *_tmp_117_rule(Parser *p); static void *_tmp_118_rule(Parser *p); static void *_tmp_119_rule(Parser *p); static void *_tmp_120_rule(Parser *p); @@ -886,21 +885,21 @@ static void *_tmp_122_rule(Parser *p); static void *_tmp_123_rule(Parser *p); static void *_tmp_124_rule(Parser *p); static void *_tmp_125_rule(Parser *p); -static void *_tmp_126_rule(Parser *p); -static asdl_seq *_loop0_127_rule(Parser *p); -static asdl_seq *_gather_128_rule(Parser *p); +static asdl_seq *_loop0_126_rule(Parser *p); +static asdl_seq *_gather_127_rule(Parser *p); +static void *_tmp_128_rule(Parser *p); static void *_tmp_129_rule(Parser *p); static void *_tmp_130_rule(Parser *p); static void *_tmp_131_rule(Parser *p); -static void *_tmp_132_rule(Parser *p); -static asdl_seq *_loop0_133_rule(Parser *p); -static asdl_seq *_gather_134_rule(Parser *p); -static asdl_seq *_loop0_135_rule(Parser *p); -static asdl_seq *_gather_136_rule(Parser *p); -static asdl_seq *_loop0_137_rule(Parser *p); -static asdl_seq *_gather_138_rule(Parser *p); -static void *_tmp_139_rule(Parser *p); -static asdl_seq *_loop0_140_rule(Parser *p); +static asdl_seq *_loop0_132_rule(Parser *p); +static asdl_seq *_gather_133_rule(Parser *p); +static asdl_seq *_loop0_134_rule(Parser *p); +static asdl_seq *_gather_135_rule(Parser *p); +static asdl_seq *_loop0_136_rule(Parser *p); +static asdl_seq *_gather_137_rule(Parser *p); +static void *_tmp_138_rule(Parser *p); +static asdl_seq *_loop0_139_rule(Parser *p); +static void *_tmp_140_rule(Parser *p); static void *_tmp_141_rule(Parser *p); static void *_tmp_142_rule(Parser *p); static void *_tmp_143_rule(Parser *p); @@ -925,12 +924,11 @@ static void *_tmp_161_rule(Parser *p); static void *_tmp_162_rule(Parser *p); static void *_tmp_163_rule(Parser *p); static void *_tmp_164_rule(Parser *p); -static void *_tmp_165_rule(Parser *p); -static asdl_seq *_loop0_166_rule(Parser *p); +static asdl_seq *_loop0_165_rule(Parser *p); +static void *_tmp_166_rule(Parser *p); static void *_tmp_167_rule(Parser *p); static void *_tmp_168_rule(Parser *p); static void *_tmp_169_rule(Parser *p); -static void *_tmp_170_rule(Parser *p); // file: statements? $ @@ -2035,8 +2033,8 @@ compound_stmt_rule(Parser *p) // assignment: // | NAME ':' expression ['=' annotated_rhs] // | ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] -// | ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? -// | single_target augassign ~ (yield_expr | star_expressions) +// | ((star_targets '='))+ annotated_rhs !'=' TYPE_COMMENT? +// | single_target augassign ~ annotated_rhs // | invalid_assignment static stmt_ty assignment_rule(Parser *p) @@ -2143,26 +2141,26 @@ assignment_rule(Parser *p) D(fprintf(stderr, "%*c%s assignment[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs]")); } - { // ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? + { // ((star_targets '='))+ annotated_rhs !'=' TYPE_COMMENT? if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT?")); + D(fprintf(stderr, "%*c> assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))+ annotated_rhs !'=' TYPE_COMMENT?")); asdl_expr_seq* a; - void *b; + expr_ty b; void *tc; if ( (a = (asdl_expr_seq*)_loop1_12_rule(p)) // ((star_targets '='))+ && - (b = _tmp_13_rule(p)) // yield_expr | star_expressions + (b = annotated_rhs_rule(p)) // annotated_rhs && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' && (tc = _PyPegen_expect_token(p, TYPE_COMMENT), !p->error_indicator) // TYPE_COMMENT? ) { - D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT?")); + D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((star_targets '='))+ annotated_rhs !'=' TYPE_COMMENT?")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -2182,18 +2180,18 @@ assignment_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s assignment[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT?")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((star_targets '='))+ annotated_rhs !'=' TYPE_COMMENT?")); } - { // single_target augassign ~ (yield_expr | star_expressions) + { // single_target augassign ~ annotated_rhs if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_target augassign ~ (yield_expr | star_expressions)")); + D(fprintf(stderr, "%*c> assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_target augassign ~ annotated_rhs")); int _cut_var = 0; expr_ty a; AugOperator* b; - void *c; + expr_ty c; if ( (a = single_target_rule(p)) // single_target && @@ -2201,10 +2199,10 @@ assignment_rule(Parser *p) && (_cut_var = 1) && - (c = _tmp_13_rule(p)) // yield_expr | star_expressions + (c = annotated_rhs_rule(p)) // annotated_rhs ) { - D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_target augassign ~ (yield_expr | star_expressions)")); + D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_target augassign ~ annotated_rhs")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -2224,7 +2222,7 @@ assignment_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s assignment[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "single_target augassign ~ (yield_expr | star_expressions)")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "single_target augassign ~ annotated_rhs")); if (_cut_var) { p->level--; return NULL; @@ -2756,7 +2754,7 @@ raise_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (b = _tmp_14_rule(p), !p->error_indicator) // ['from' expression] + (b = _tmp_13_rule(p), !p->error_indicator) // ['from' expression] ) { D(fprintf(stderr, "%*c+ raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression ['from' expression]")); @@ -2853,7 +2851,7 @@ global_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 526)) // token='global' && - (a = (asdl_expr_seq*)_gather_16_rule(p)) // ','.NAME+ + (a = (asdl_expr_seq*)_gather_15_rule(p)) // ','.NAME+ ) { D(fprintf(stderr, "%*c+ global_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'global' ','.NAME+")); @@ -2917,7 +2915,7 @@ nonlocal_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 527)) // token='nonlocal' && - (a = (asdl_expr_seq*)_gather_16_rule(p)) // ','.NAME+ + (a = (asdl_expr_seq*)_gather_15_rule(p)) // ','.NAME+ ) { D(fprintf(stderr, "%*c+ nonlocal_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'nonlocal' ','.NAME+")); @@ -2983,7 +2981,7 @@ del_stmt_rule(Parser *p) && (a = del_targets_rule(p)) // del_targets && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_17_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_16_rule, p) ) { D(fprintf(stderr, "%*c+ del_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'del' del_targets &(';' | NEWLINE)")); @@ -3130,7 +3128,7 @@ assert_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (b = _tmp_18_rule(p), !p->error_indicator) // [',' expression] + (b = _tmp_17_rule(p), !p->error_indicator) // [',' expression] ) { D(fprintf(stderr, "%*c+ assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression [',' expression]")); @@ -3339,7 +3337,7 @@ import_from_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 621)) // token='from' && - (a = _loop0_19_rule(p)) // (('.' | '...'))* + (a = _loop0_18_rule(p)) // (('.' | '...'))* && (b = dotted_name_rule(p)) // dotted_name && @@ -3383,7 +3381,7 @@ import_from_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 621)) // token='from' && - (a = _loop1_20_rule(p)) // (('.' | '...'))+ + (a = _loop1_19_rule(p)) // (('.' | '...'))+ && (_keyword_1 = _PyPegen_expect_token(p, 622)) // token='import' && @@ -3578,7 +3576,7 @@ import_from_as_names_rule(Parser *p) D(fprintf(stderr, "%*c> import_from_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+")); asdl_alias_seq* a; if ( - (a = (asdl_alias_seq*)_gather_22_rule(p)) // ','.import_from_as_name+ + (a = (asdl_alias_seq*)_gather_21_rule(p)) // ','.import_from_as_name+ ) { D(fprintf(stderr, "%*c+ import_from_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+")); @@ -3633,7 +3631,7 @@ import_from_as_name_rule(Parser *p) if ( (a = _PyPegen_name_token(p)) // NAME && - (b = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (b = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] ) { D(fprintf(stderr, "%*c+ import_from_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME ['as' NAME]")); @@ -3685,7 +3683,7 @@ dotted_as_names_rule(Parser *p) D(fprintf(stderr, "%*c> dotted_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+")); asdl_alias_seq* a; if ( - (a = (asdl_alias_seq*)_gather_25_rule(p)) // ','.dotted_as_name+ + (a = (asdl_alias_seq*)_gather_24_rule(p)) // ','.dotted_as_name+ ) { D(fprintf(stderr, "%*c+ dotted_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+")); @@ -3740,7 +3738,7 @@ dotted_as_name_rule(Parser *p) if ( (a = dotted_name_rule(p)) // dotted_name && - (b = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (b = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] ) { D(fprintf(stderr, "%*c+ dotted_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name ['as' NAME]")); @@ -3991,7 +3989,7 @@ decorators_rule(Parser *p) D(fprintf(stderr, "%*c> decorators[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_26_rule(p)) // (('@' named_expression NEWLINE))+ + (a = (asdl_expr_seq*)_loop1_25_rule(p)) // (('@' named_expression NEWLINE))+ ) { D(fprintf(stderr, "%*c+ decorators[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+")); @@ -4140,7 +4138,7 @@ class_def_raw_rule(Parser *p) && (t = type_params_rule(p), !p->error_indicator) // type_params? && - (b = _tmp_27_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (b = _tmp_26_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -4313,7 +4311,7 @@ function_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (a = _tmp_28_rule(p), !p->error_indicator) // ['->' expression] + (a = _tmp_27_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -4376,7 +4374,7 @@ function_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (a = _tmp_28_rule(p), !p->error_indicator) // ['->' expression] + (a = _tmp_27_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -4501,9 +4499,9 @@ parameters_rule(Parser *p) if ( (a = slash_no_default_rule(p)) // slash_no_default && - (b = (asdl_arg_seq*)_loop0_29_rule(p)) // param_no_default* + (b = (asdl_arg_seq*)_loop0_28_rule(p)) // param_no_default* && - (c = _loop0_30_rule(p)) // param_with_default* + (c = _loop0_29_rule(p)) // param_with_default* && (d = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4533,7 +4531,7 @@ parameters_rule(Parser *p) if ( (a = slash_with_default_rule(p)) // slash_with_default && - (b = _loop0_30_rule(p)) // param_with_default* + (b = _loop0_29_rule(p)) // param_with_default* && (c = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4561,9 +4559,9 @@ parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_31_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_30_rule(p)) // param_no_default+ && - (b = _loop0_30_rule(p)) // param_with_default* + (b = _loop0_29_rule(p)) // param_with_default* && (c = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4590,7 +4588,7 @@ parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_32_rule(p)) // param_with_default+ + (a = _loop1_31_rule(p)) // param_with_default+ && (b = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4661,7 +4659,7 @@ slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_31_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_30_rule(p)) // param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4690,7 +4688,7 @@ slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_31_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_30_rule(p)) // param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4742,9 +4740,9 @@ slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_29_rule(p)) // param_no_default* + (a = _loop0_28_rule(p)) // param_no_default* && - (b = _loop1_32_rule(p)) // param_with_default+ + (b = _loop1_31_rule(p)) // param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4774,9 +4772,9 @@ slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_29_rule(p)) // param_no_default* + (a = _loop0_28_rule(p)) // param_no_default* && - (b = _loop1_32_rule(p)) // param_with_default+ + (b = _loop1_31_rule(p)) // param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4854,7 +4852,7 @@ star_etc_rule(Parser *p) && (a = param_no_default_rule(p)) // param_no_default && - (b = _loop0_33_rule(p)) // param_maybe_default* + (b = _loop0_32_rule(p)) // param_maybe_default* && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -4887,7 +4885,7 @@ star_etc_rule(Parser *p) && (a = param_no_default_star_annotation_rule(p)) // param_no_default_star_annotation && - (b = _loop0_33_rule(p)) // param_maybe_default* + (b = _loop0_32_rule(p)) // param_maybe_default* && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -4920,7 +4918,7 @@ star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_34_rule(p)) // param_maybe_default+ + (b = _loop1_33_rule(p)) // param_maybe_default+ && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -6348,7 +6346,7 @@ with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = (asdl_withitem_seq*)_gather_36_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_35_rule(p)) // ','.with_item+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -6397,7 +6395,7 @@ with_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 633)) // token='with' && - (a = (asdl_withitem_seq*)_gather_36_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_35_rule(p)) // ','.with_item+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -6450,7 +6448,7 @@ with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = (asdl_withitem_seq*)_gather_36_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_35_rule(p)) // ','.with_item+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -6500,7 +6498,7 @@ with_stmt_rule(Parser *p) && (_keyword_1 = _PyPegen_expect_token(p, 633)) // token='with' && - (a = (asdl_withitem_seq*)_gather_36_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_35_rule(p)) // ','.with_item+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -6588,7 +6586,7 @@ with_item_rule(Parser *p) && (t = star_target_rule(p)) // star_target && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_37_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_36_rule, p) ) { D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')")); @@ -6759,7 +6757,7 @@ try_stmt_rule(Parser *p) && (b = block_rule(p)) // block && - (ex = (asdl_excepthandler_seq*)_loop1_38_rule(p)) // except_block+ + (ex = (asdl_excepthandler_seq*)_loop1_37_rule(p)) // except_block+ && (el = else_block_rule(p), !p->error_indicator) // else_block? && @@ -6807,7 +6805,7 @@ try_stmt_rule(Parser *p) && (b = block_rule(p)) // block && - (ex = (asdl_excepthandler_seq*)_loop1_39_rule(p)) // except_star_block+ + (ex = (asdl_excepthandler_seq*)_loop1_38_rule(p)) // except_star_block+ && (el = else_block_rule(p), !p->error_indicator) // else_block? && @@ -6903,7 +6901,7 @@ except_block_rule(Parser *p) && (e = expression_rule(p)) // expression && - (t = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (t = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7059,7 +7057,7 @@ except_star_block_rule(Parser *p) && (e = expression_rule(p)) // expression && - (t = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (t = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7229,7 +7227,7 @@ match_stmt_rule(Parser *p) && (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' && - (cases = (asdl_match_case_seq*)_loop1_40_rule(p)) // case_block+ + (cases = (asdl_match_case_seq*)_loop1_39_rule(p)) // case_block+ && (dedent_var = _PyPegen_expect_token(p, DEDENT)) // token='DEDENT' ) @@ -7740,7 +7738,7 @@ or_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> or_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); asdl_pattern_seq* patterns; if ( - (patterns = (asdl_pattern_seq*)_gather_42_rule(p)) // '|'.closed_pattern+ + (patterns = (asdl_pattern_seq*)_gather_41_rule(p)) // '|'.closed_pattern+ ) { D(fprintf(stderr, "%*c+ or_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); @@ -7993,7 +7991,7 @@ literal_pattern_rule(Parser *p) if ( (value = signed_number_rule(p)) // signed_number && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_43_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_42_rule, p) ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); @@ -8227,7 +8225,7 @@ literal_expr_rule(Parser *p) if ( (signed_number_var = signed_number_rule(p)) // signed_number && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_43_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_42_rule, p) ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); @@ -8827,7 +8825,7 @@ pattern_capture_target_rule(Parser *p) && (name = _PyPegen_name_token(p)) // NAME && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_44_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_43_rule, p) ) { D(fprintf(stderr, "%*c+ pattern_capture_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); @@ -8942,7 +8940,7 @@ value_pattern_rule(Parser *p) if ( (attr = attr_rule(p)) // attr && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_44_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_43_rule, p) ) { D(fprintf(stderr, "%*c+ value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr !('.' | '(' | '=')")); @@ -9361,7 +9359,7 @@ maybe_sequence_pattern_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * patterns; if ( - (patterns = _gather_46_rule(p)) // ','.maybe_star_pattern+ + (patterns = _gather_45_rule(p)) // ','.maybe_star_pattern+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -9769,13 +9767,13 @@ items_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> items_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); - asdl_seq * _gather_48_var; + asdl_seq * _gather_47_var; if ( - (_gather_48_var = _gather_48_rule(p)) // ','.key_value_pattern+ + (_gather_47_var = _gather_47_rule(p)) // ','.key_value_pattern+ ) { D(fprintf(stderr, "%*c+ items_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); - _res = _gather_48_var; + _res = _gather_47_var; goto done; } p->mark = _mark; @@ -9811,7 +9809,7 @@ key_value_pattern_rule(Parser *p) void *key; pattern_ty pattern; if ( - (key = _tmp_49_rule(p)) // literal_expr | attr + (key = _tmp_48_rule(p)) // literal_expr | attr && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -10139,7 +10137,7 @@ positional_patterns_rule(Parser *p) D(fprintf(stderr, "%*c> positional_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.pattern+")); asdl_pattern_seq* args; if ( - (args = (asdl_pattern_seq*)_gather_51_rule(p)) // ','.pattern+ + (args = (asdl_pattern_seq*)_gather_50_rule(p)) // ','.pattern+ ) { D(fprintf(stderr, "%*c+ positional_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.pattern+")); @@ -10180,13 +10178,13 @@ keyword_patterns_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> keyword_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); - asdl_seq * _gather_53_var; + asdl_seq * _gather_52_var; if ( - (_gather_53_var = _gather_53_rule(p)) // ','.keyword_pattern+ + (_gather_52_var = _gather_52_rule(p)) // ','.keyword_pattern+ ) { D(fprintf(stderr, "%*c+ keyword_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); - _res = _gather_53_var; + _res = _gather_52_var; goto done; } p->mark = _mark; @@ -10412,7 +10410,7 @@ type_param_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_type_param_seq* a; if ( - (a = (asdl_type_param_seq*)_gather_55_rule(p)) // ','.type_param+ + (a = (asdl_type_param_seq*)_gather_54_rule(p)) // ','.type_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -10782,7 +10780,7 @@ expressions_rule(Parser *p) if ( (a = expression_rule(p)) // expression && - (b = _loop1_56_rule(p)) // ((',' expression))+ + (b = _loop1_55_rule(p)) // ((',' expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11170,7 +11168,7 @@ star_expressions_rule(Parser *p) if ( (a = star_expression_rule(p)) // star_expression && - (b = _loop1_57_rule(p)) // ((',' star_expression))+ + (b = _loop1_56_rule(p)) // ((',' star_expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11369,7 +11367,7 @@ star_named_expressions_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_59_rule(p)) // ','.star_named_expression+ + (a = (asdl_expr_seq*)_gather_58_rule(p)) // ','.star_named_expression+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11665,7 +11663,7 @@ disjunction_rule(Parser *p) if ( (a = conjunction_rule(p)) // conjunction && - (b = _loop1_60_rule(p)) // (('or' conjunction))+ + (b = _loop1_59_rule(p)) // (('or' conjunction))+ ) { D(fprintf(stderr, "%*c+ disjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "conjunction (('or' conjunction))+")); @@ -11753,7 +11751,7 @@ conjunction_rule(Parser *p) if ( (a = inversion_rule(p)) // inversion && - (b = _loop1_61_rule(p)) // (('and' inversion))+ + (b = _loop1_60_rule(p)) // (('and' inversion))+ ) { D(fprintf(stderr, "%*c+ conjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "inversion (('and' inversion))+")); @@ -11925,7 +11923,7 @@ comparison_rule(Parser *p) if ( (a = bitwise_or_rule(p)) // bitwise_or && - (b = _loop1_62_rule(p)) // compare_op_bitwise_or_pair+ + (b = _loop1_61_rule(p)) // compare_op_bitwise_or_pair+ ) { D(fprintf(stderr, "%*c+ comparison[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or compare_op_bitwise_or_pair+")); @@ -12259,10 +12257,10 @@ noteq_bitwise_or_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> noteq_bitwise_or[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('!=') bitwise_or")); - void *_tmp_63_var; + void *_tmp_62_var; expr_ty a; if ( - (_tmp_63_var = _tmp_63_rule(p)) // '!=' + (_tmp_62_var = _tmp_62_rule(p)) // '!=' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -14310,7 +14308,7 @@ slices_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_65_rule(p)) // ','.(slice | starred_expression)+ + (a = (asdl_expr_seq*)_gather_64_rule(p)) // ','.(slice | starred_expression)+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -14382,7 +14380,7 @@ slice_rule(Parser *p) && (b = expression_rule(p), !p->error_indicator) // expression? && - (c = _tmp_66_rule(p), !p->error_indicator) // [':' expression?] + (c = _tmp_65_rule(p), !p->error_indicator) // [':' expression?] ) { D(fprintf(stderr, "%*c+ slice[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression? ':' expression? [':' expression?]")); @@ -14595,7 +14593,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); expr_ty strings_var; if ( - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_67_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_66_rule, p) && (strings_var = strings_rule(p)) // strings ) @@ -14633,15 +14631,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - void *_tmp_68_var; + void *_tmp_67_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 7) // token='(' && - (_tmp_68_var = _tmp_68_rule(p)) // tuple | group | genexp + (_tmp_67_var = _tmp_67_rule(p)) // tuple | group | genexp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - _res = _tmp_68_var; + _res = _tmp_67_var; goto done; } p->mark = _mark; @@ -14654,15 +14652,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - void *_tmp_69_var; + void *_tmp_68_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='[' && - (_tmp_69_var = _tmp_69_rule(p)) // list | listcomp + (_tmp_68_var = _tmp_68_rule(p)) // list | listcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - _res = _tmp_69_var; + _res = _tmp_68_var; goto done; } p->mark = _mark; @@ -14675,15 +14673,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - void *_tmp_70_var; + void *_tmp_69_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{' && - (_tmp_70_var = _tmp_70_rule(p)) // dict | set | dictcomp | setcomp + (_tmp_69_var = _tmp_69_rule(p)) // dict | set | dictcomp | setcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - _res = _tmp_70_var; + _res = _tmp_69_var; goto done; } p->mark = _mark; @@ -14754,7 +14752,7 @@ group_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_71_rule(p)) // yield_expr | named_expression + (a = _tmp_70_rule(p)) // yield_expr | named_expression && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -14955,9 +14953,9 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_no_default_rule(p)) // lambda_slash_no_default && - (b = (asdl_arg_seq*)_loop0_72_rule(p)) // lambda_param_no_default* + (b = (asdl_arg_seq*)_loop0_71_rule(p)) // lambda_param_no_default* && - (c = _loop0_73_rule(p)) // lambda_param_with_default* + (c = _loop0_72_rule(p)) // lambda_param_with_default* && (d = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14987,7 +14985,7 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_with_default_rule(p)) // lambda_slash_with_default && - (b = _loop0_73_rule(p)) // lambda_param_with_default* + (b = _loop0_72_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15015,9 +15013,9 @@ lambda_parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_74_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_73_rule(p)) // lambda_param_no_default+ && - (b = _loop0_73_rule(p)) // lambda_param_with_default* + (b = _loop0_72_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15044,7 +15042,7 @@ lambda_parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_75_rule(p)) // lambda_param_with_default+ + (a = _loop1_74_rule(p)) // lambda_param_with_default+ && (b = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15117,7 +15115,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_74_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_73_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15146,7 +15144,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_74_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_73_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15198,9 +15196,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_72_rule(p)) // lambda_param_no_default* + (a = _loop0_71_rule(p)) // lambda_param_no_default* && - (b = _loop1_75_rule(p)) // lambda_param_with_default+ + (b = _loop1_74_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15230,9 +15228,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_72_rule(p)) // lambda_param_no_default* + (a = _loop0_71_rule(p)) // lambda_param_no_default* && - (b = _loop1_75_rule(p)) // lambda_param_with_default+ + (b = _loop1_74_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15309,7 +15307,7 @@ lambda_star_etc_rule(Parser *p) && (a = lambda_param_no_default_rule(p)) // lambda_param_no_default && - (b = _loop0_76_rule(p)) // lambda_param_maybe_default* + (b = _loop0_75_rule(p)) // lambda_param_maybe_default* && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15342,7 +15340,7 @@ lambda_star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_77_rule(p)) // lambda_param_maybe_default+ + (b = _loop1_76_rule(p)) // lambda_param_maybe_default+ && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15982,7 +15980,7 @@ fstring_full_format_spec_rule(Parser *p) if ( (colon = _PyPegen_expect_token(p, 11)) // token=':' && - (spec = _loop0_78_rule(p)) // fstring_format_spec* + (spec = _loop0_77_rule(p)) // fstring_format_spec* ) { D(fprintf(stderr, "%*c+ fstring_full_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' fstring_format_spec*")); @@ -16100,7 +16098,7 @@ fstring_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' && - (b = _loop0_79_rule(p)) // fstring_middle* + (b = _loop0_78_rule(p)) // fstring_middle* && (c = _PyPegen_expect_token(p, FSTRING_END)) // token='FSTRING_END' ) @@ -16201,7 +16199,7 @@ strings_rule(Parser *p) D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_80_rule(p)) // ((fstring | string))+ + (a = (asdl_expr_seq*)_loop1_79_rule(p)) // ((fstring | string))+ ) { D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); @@ -16334,7 +16332,7 @@ tuple_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_81_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] + (a = _tmp_80_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -16549,7 +16547,7 @@ double_starred_kvpairs_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_83_rule(p)) // ','.double_starred_kvpair+ + (a = _gather_82_rule(p)) // ','.double_starred_kvpair+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -16708,7 +16706,7 @@ for_if_clauses_rule(Parser *p) D(fprintf(stderr, "%*c> for_if_clauses[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); asdl_comprehension_seq* a; if ( - (a = (asdl_comprehension_seq*)_loop1_84_rule(p)) // for_if_clause+ + (a = (asdl_comprehension_seq*)_loop1_83_rule(p)) // for_if_clause+ ) { D(fprintf(stderr, "%*c+ for_if_clauses[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); @@ -16773,7 +16771,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_85_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_84_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async' 'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -16816,7 +16814,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_85_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_84_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -17095,7 +17093,7 @@ genexp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_86_rule(p)) // assignment_expression | expression !':=' + (a = _tmp_85_rule(p)) // assignment_expression | expression !':=' && (b = for_if_clauses_rule(p)) // for_if_clauses && @@ -17344,9 +17342,9 @@ args_rule(Parser *p) asdl_expr_seq* a; void *b; if ( - (a = (asdl_expr_seq*)_gather_88_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + (a = (asdl_expr_seq*)_gather_87_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ && - (b = _tmp_89_rule(p), !p->error_indicator) // [',' kwargs] + (b = _tmp_88_rule(p), !p->error_indicator) // [',' kwargs] ) { D(fprintf(stderr, "%*c+ args[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ [',' kwargs]")); @@ -17436,11 +17434,11 @@ kwargs_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _gather_91_rule(p)) // ','.kwarg_or_starred+ + (a = _gather_90_rule(p)) // ','.kwarg_or_starred+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _gather_93_rule(p)) // ','.kwarg_or_double_starred+ + (b = _gather_92_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+")); @@ -17462,13 +17460,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - asdl_seq * _gather_91_var; + asdl_seq * _gather_90_var; if ( - (_gather_91_var = _gather_91_rule(p)) // ','.kwarg_or_starred+ + (_gather_90_var = _gather_90_rule(p)) // ','.kwarg_or_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - _res = _gather_91_var; + _res = _gather_90_var; goto done; } p->mark = _mark; @@ -17481,13 +17479,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - asdl_seq * _gather_93_var; + asdl_seq * _gather_92_var; if ( - (_gather_93_var = _gather_93_rule(p)) // ','.kwarg_or_double_starred+ + (_gather_92_var = _gather_92_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - _res = _gather_93_var; + _res = _gather_92_var; goto done; } p->mark = _mark; @@ -17898,7 +17896,7 @@ star_targets_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop0_94_rule(p)) // ((',' star_target))* + (b = _loop0_93_rule(p)) // ((',' star_target))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17954,7 +17952,7 @@ star_targets_list_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_96_rule(p)) // ','.star_target+ + (a = (asdl_expr_seq*)_gather_95_rule(p)) // ','.star_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -18004,7 +18002,7 @@ star_targets_tuple_seq_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop1_97_rule(p)) // ((',' star_target))+ + (b = _loop1_96_rule(p)) // ((',' star_target))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -18092,7 +18090,7 @@ star_target_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (a = _tmp_98_rule(p)) // !'*' star_target + (a = _tmp_97_rule(p)) // !'*' star_target ) { D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)")); @@ -19015,7 +19013,7 @@ del_targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_100_rule(p)) // ','.del_target+ + (a = (asdl_expr_seq*)_gather_99_rule(p)) // ','.del_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -19373,7 +19371,7 @@ type_expressions_rule(Parser *p) expr_ty b; expr_ty c; if ( - (a = _gather_102_rule(p)) // ','.expression+ + (a = _gather_101_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19412,7 +19410,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_102_rule(p)) // ','.expression+ + (a = _gather_101_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19445,7 +19443,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_102_rule(p)) // ','.expression+ + (a = _gather_101_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19565,7 +19563,7 @@ type_expressions_rule(Parser *p) D(fprintf(stderr, "%*c> type_expressions[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.expression+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_102_rule(p)) // ','.expression+ + (a = (asdl_expr_seq*)_gather_101_rule(p)) // ','.expression+ ) { D(fprintf(stderr, "%*c+ type_expressions[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.expression+")); @@ -19616,7 +19614,7 @@ func_type_comment_rule(Parser *p) && (t = _PyPegen_expect_token(p, TYPE_COMMENT)) // token='TYPE_COMMENT' && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_103_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_102_rule, p) ) { D(fprintf(stderr, "%*c+ func_type_comment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE INDENT)")); @@ -19702,15 +19700,15 @@ invalid_arguments_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' ','.(starred_expression !'=')+")); - asdl_seq * _gather_106_var; - void *_tmp_104_var; + asdl_seq * _gather_105_var; + void *_tmp_103_var; Token * a; if ( - (_tmp_104_var = _tmp_104_rule(p)) // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs + (_tmp_103_var = _tmp_103_rule(p)) // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs && (a = _PyPegen_expect_token(p, 12)) // token=',' && - (_gather_106_var = _gather_106_rule(p)) // ','.(starred_expression !'=')+ + (_gather_105_var = _gather_105_rule(p)) // ','.(starred_expression !'=')+ ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' ','.(starred_expression !'=')+")); @@ -19744,7 +19742,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_107_rule(p), !p->error_indicator) // [args | expression for_if_clauses] + (_opt_var = _tmp_106_rule(p), !p->error_indicator) // [args | expression for_if_clauses] ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); @@ -19804,13 +19802,13 @@ invalid_arguments_rule(Parser *p) expr_ty a; Token * b; if ( - (_opt_var = _tmp_108_rule(p), !p->error_indicator) // [(args ',')] + (_opt_var = _tmp_107_rule(p), !p->error_indicator) // [(args ',')] && (a = _PyPegen_name_token(p)) // NAME && (b = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_109_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_108_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | ')')")); @@ -19948,7 +19946,7 @@ invalid_kwarg_rule(Parser *p) Token* a; Token * b; if ( - (a = (Token*)_tmp_110_rule(p)) // 'True' | 'False' | 'None' + (a = (Token*)_tmp_109_rule(p)) // 'True' | 'False' | 'None' && (b = _PyPegen_expect_token(p, 22)) // token='=' ) @@ -20008,7 +20006,7 @@ invalid_kwarg_rule(Parser *p) expr_ty a; Token * b; if ( - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_111_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_110_rule, p) && (a = expression_rule(p)) // expression && @@ -20349,7 +20347,7 @@ invalid_expression_rule(Parser *p) expr_ty a; expr_ty b; if ( - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_112_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_111_rule, p) && (a = disjunction_rule(p)) // disjunction && @@ -20385,7 +20383,7 @@ invalid_expression_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_113_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_112_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); @@ -20506,7 +20504,7 @@ invalid_named_expression_rule(Parser *p) && (b = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_114_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_113_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | ':=')")); @@ -20532,7 +20530,7 @@ invalid_named_expression_rule(Parser *p) Token * b; expr_ty bitwise_or_var; if ( - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_115_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_114_rule, p) && (a = bitwise_or_rule(p)) // bitwise_or && @@ -20540,7 +20538,7 @@ invalid_named_expression_rule(Parser *p) && (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_114_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_113_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')")); @@ -20620,7 +20618,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_116_var; + asdl_seq * _loop0_115_var; expr_ty a; expr_ty expression_var; if ( @@ -20628,7 +20626,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_116_var = _loop0_116_rule(p)) // star_named_expressions* + (_loop0_115_var = _loop0_115_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -20685,10 +20683,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_117_var; + asdl_seq * _loop0_116_var; expr_ty a; if ( - (_loop0_117_var = _loop0_117_rule(p)) // ((star_targets '='))* + (_loop0_116_var = _loop0_116_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -20715,10 +20713,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_117_var; + asdl_seq * _loop0_116_var; expr_ty a; if ( - (_loop0_117_var = _loop0_117_rule(p)) // ((star_targets '='))* + (_loop0_116_var = _loop0_116_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -20974,11 +20972,11 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_118_var; + void *_tmp_117_var; expr_ty a; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_118_var = _tmp_118_rule(p)) // '[' | '(' | '{' + (_tmp_117_var = _tmp_117_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -21005,12 +21003,12 @@ invalid_comprehension_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses")); Token * _literal; - void *_tmp_119_var; + void *_tmp_118_var; expr_ty a; asdl_expr_seq* b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_119_var = _tmp_119_rule(p)) // '[' | '{' + (_tmp_118_var = _tmp_118_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -21040,12 +21038,12 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' for_if_clauses")); - void *_tmp_119_var; + void *_tmp_118_var; expr_ty a; Token * b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_119_var = _tmp_119_rule(p)) // '[' | '{' + (_tmp_118_var = _tmp_118_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -21180,13 +21178,13 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slash_no_default | slash_with_default) param_maybe_default* '/'")); - asdl_seq * _loop0_33_var; - void *_tmp_120_var; + asdl_seq * _loop0_32_var; + void *_tmp_119_var; Token * a; if ( - (_tmp_120_var = _tmp_120_rule(p)) // slash_no_default | slash_with_default + (_tmp_119_var = _tmp_119_rule(p)) // slash_no_default | slash_with_default && - (_loop0_33_var = _loop0_33_rule(p)) // param_maybe_default* + (_loop0_32_var = _loop0_32_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21210,7 +21208,7 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default? param_no_default* invalid_parameters_helper param_no_default")); - asdl_seq * _loop0_29_var; + asdl_seq * _loop0_28_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21218,7 +21216,7 @@ invalid_parameters_rule(Parser *p) if ( (_opt_var = slash_no_default_rule(p), !p->error_indicator) // slash_no_default? && - (_loop0_29_var = _loop0_29_rule(p)) // param_no_default* + (_loop0_28_var = _loop0_28_rule(p)) // param_no_default* && (invalid_parameters_helper_var = invalid_parameters_helper_rule(p)) // invalid_parameters_helper && @@ -21244,18 +21242,18 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* '(' param_no_default+ ','? ')'")); - asdl_seq * _loop0_29_var; - asdl_seq * _loop1_31_var; + asdl_seq * _loop0_28_var; + asdl_seq * _loop1_30_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_29_var = _loop0_29_rule(p)) // param_no_default* + (_loop0_28_var = _loop0_28_rule(p)) // param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_loop1_31_var = _loop1_31_rule(p)) // param_no_default+ + (_loop1_30_var = _loop1_30_rule(p)) // param_no_default+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21282,22 +21280,22 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(slash_no_default | slash_with_default)] param_maybe_default* '*' (',' | param_no_default) param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_33_var; - asdl_seq * _loop0_33_var_1; + asdl_seq * _loop0_32_var; + asdl_seq * _loop0_32_var_1; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_121_var; + void *_tmp_120_var; Token * a; if ( - (_opt_var = _tmp_120_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] + (_opt_var = _tmp_119_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] && - (_loop0_33_var = _loop0_33_rule(p)) // param_maybe_default* + (_loop0_32_var = _loop0_32_rule(p)) // param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_121_var = _tmp_121_rule(p)) // ',' | param_no_default + (_tmp_120_var = _tmp_120_rule(p)) // ',' | param_no_default && - (_loop0_33_var_1 = _loop0_33_rule(p)) // param_maybe_default* + (_loop0_32_var_1 = _loop0_32_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21322,10 +21320,10 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_34_var; + asdl_seq * _loop1_33_var; Token * a; if ( - (_loop1_34_var = _loop1_34_rule(p)) // param_maybe_default+ + (_loop1_33_var = _loop1_33_rule(p)) // param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21374,7 +21372,7 @@ invalid_default_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_122_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_121_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')")); @@ -21419,12 +21417,12 @@ invalid_star_etc_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); - void *_tmp_123_var; + void *_tmp_122_var; Token * a; if ( (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_123_var = _tmp_123_rule(p)) // ')' | ',' (')' | '**') + (_tmp_122_var = _tmp_122_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -21507,20 +21505,20 @@ invalid_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_33_var; - void *_tmp_124_var; - void *_tmp_124_var_1; + asdl_seq * _loop0_32_var; + void *_tmp_123_var; + void *_tmp_123_var_1; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_124_var = _tmp_124_rule(p)) // param_no_default | ',' + (_tmp_123_var = _tmp_123_rule(p)) // param_no_default | ',' && - (_loop0_33_var = _loop0_33_rule(p)) // param_maybe_default* + (_loop0_32_var = _loop0_32_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_124_var_1 = _tmp_124_rule(p)) // param_no_default | ',' + (_tmp_123_var_1 = _tmp_123_rule(p)) // param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); @@ -21635,7 +21633,7 @@ invalid_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_125_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_124_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')")); @@ -21700,13 +21698,13 @@ invalid_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - asdl_seq * _loop1_32_var; + asdl_seq * _loop1_31_var; if ( - (_loop1_32_var = _loop1_32_rule(p)) // param_with_default+ + (_loop1_31_var = _loop1_31_rule(p)) // param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - _res = _loop1_32_var; + _res = _loop1_31_var; goto done; } p->mark = _mark; @@ -21771,13 +21769,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/'")); - asdl_seq * _loop0_76_var; - void *_tmp_126_var; + asdl_seq * _loop0_75_var; + void *_tmp_125_var; Token * a; if ( - (_tmp_126_var = _tmp_126_rule(p)) // lambda_slash_no_default | lambda_slash_with_default + (_tmp_125_var = _tmp_125_rule(p)) // lambda_slash_no_default | lambda_slash_with_default && - (_loop0_76_var = _loop0_76_rule(p)) // lambda_param_maybe_default* + (_loop0_75_var = _loop0_75_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21801,7 +21799,7 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default")); - asdl_seq * _loop0_72_var; + asdl_seq * _loop0_71_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21809,7 +21807,7 @@ invalid_lambda_parameters_rule(Parser *p) if ( (_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default? && - (_loop0_72_var = _loop0_72_rule(p)) // lambda_param_no_default* + (_loop0_71_var = _loop0_71_rule(p)) // lambda_param_no_default* && (invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper && @@ -21835,18 +21833,18 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* '(' ','.lambda_param+ ','? ')'")); - asdl_seq * _gather_128_var; - asdl_seq * _loop0_72_var; + asdl_seq * _gather_127_var; + asdl_seq * _loop0_71_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_72_var = _loop0_72_rule(p)) // lambda_param_no_default* + (_loop0_71_var = _loop0_71_rule(p)) // lambda_param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_128_var = _gather_128_rule(p)) // ','.lambda_param+ + (_gather_127_var = _gather_127_rule(p)) // ','.lambda_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21873,22 +21871,22 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_76_var; - asdl_seq * _loop0_76_var_1; + asdl_seq * _loop0_75_var; + asdl_seq * _loop0_75_var_1; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_129_var; + void *_tmp_128_var; Token * a; if ( - (_opt_var = _tmp_126_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] + (_opt_var = _tmp_125_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] && - (_loop0_76_var = _loop0_76_rule(p)) // lambda_param_maybe_default* + (_loop0_75_var = _loop0_75_rule(p)) // lambda_param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_129_var = _tmp_129_rule(p)) // ',' | lambda_param_no_default + (_tmp_128_var = _tmp_128_rule(p)) // ',' | lambda_param_no_default && - (_loop0_76_var_1 = _loop0_76_rule(p)) // lambda_param_maybe_default* + (_loop0_75_var_1 = _loop0_75_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21913,10 +21911,10 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_77_var; + asdl_seq * _loop1_76_var; Token * a; if ( - (_loop1_77_var = _loop1_77_rule(p)) // lambda_param_maybe_default+ + (_loop1_76_var = _loop1_76_rule(p)) // lambda_param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21987,13 +21985,13 @@ invalid_lambda_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_75_var; + asdl_seq * _loop1_74_var; if ( - (_loop1_75_var = _loop1_75_rule(p)) // lambda_param_with_default+ + (_loop1_74_var = _loop1_74_rule(p)) // lambda_param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_lambda_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_75_var; + _res = _loop1_74_var; goto done; } p->mark = _mark; @@ -22029,11 +22027,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_130_var; + void *_tmp_129_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_130_var = _tmp_130_rule(p)) // ':' | ',' (':' | '**') + (_tmp_129_var = _tmp_129_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -22086,20 +22084,20 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_76_var; - void *_tmp_131_var; - void *_tmp_131_var_1; + asdl_seq * _loop0_75_var; + void *_tmp_130_var; + void *_tmp_130_var_1; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_131_var = _tmp_131_rule(p)) // lambda_param_no_default | ',' + (_tmp_130_var = _tmp_130_rule(p)) // lambda_param_no_default | ',' && - (_loop0_76_var = _loop0_76_rule(p)) // lambda_param_maybe_default* + (_loop0_75_var = _loop0_75_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_131_var_1 = _tmp_131_rule(p)) // lambda_param_no_default | ',' + (_tmp_130_var_1 = _tmp_130_rule(p)) // lambda_param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); @@ -22217,7 +22215,7 @@ invalid_lambda_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_125_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_124_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')")); @@ -22323,7 +22321,7 @@ invalid_with_item_rule(Parser *p) && (a = expression_rule(p)) // expression && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_37_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_36_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' | ')' | ':')")); @@ -22367,13 +22365,13 @@ invalid_for_if_clause_rule(Parser *p) Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_132_var; + void *_tmp_131_var; if ( (_opt_var = _PyPegen_expect_token(p, 682), !p->error_indicator) // 'async'? && (_keyword = _PyPegen_expect_token(p, 678)) // token='for' && - (_tmp_132_var = _tmp_132_rule(p)) // bitwise_or ((',' bitwise_or))* ','? + (_tmp_131_var = _tmp_131_rule(p)) // bitwise_or ((',' bitwise_or))* ','? && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 679) // token='in' ) @@ -22548,14 +22546,14 @@ invalid_import_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); - asdl_seq * _gather_134_var; + asdl_seq * _gather_133_var; Token * _keyword; Token * a; expr_ty dotted_name_var; if ( (a = _PyPegen_expect_token(p, 622)) // token='import' && - (_gather_134_var = _gather_134_rule(p)) // ','.dotted_name+ + (_gather_133_var = _gather_133_rule(p)) // ','.dotted_name+ && (_keyword = _PyPegen_expect_token(p, 621)) // token='from' && @@ -22702,7 +22700,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_136_var; + asdl_seq * _gather_135_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22712,7 +22710,7 @@ invalid_with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 633)) // token='with' && - (_gather_136_var = _gather_136_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_135_var = _gather_135_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22736,7 +22734,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_138_var; + asdl_seq * _gather_137_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -22752,7 +22750,7 @@ invalid_with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_138_var = _gather_138_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_137_var = _gather_137_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22801,7 +22799,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_136_var; + asdl_seq * _gather_135_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22812,7 +22810,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (a = _PyPegen_expect_token(p, 633)) // token='with' && - (_gather_136_var = _gather_136_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_135_var = _gather_135_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22840,7 +22838,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_138_var; + asdl_seq * _gather_137_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -22857,7 +22855,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_138_var = _gather_138_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_137_var = _gather_137_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22954,7 +22952,7 @@ invalid_try_stmt_rule(Parser *p) && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_139_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_138_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -22979,8 +22977,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_140_var; - asdl_seq * _loop1_38_var; + asdl_seq * _loop0_139_var; + asdl_seq * _loop1_37_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22991,9 +22989,9 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_140_var = _loop0_140_rule(p)) // block* + (_loop0_139_var = _loop0_139_rule(p)) // block* && - (_loop1_38_var = _loop1_38_rule(p)) // except_block+ + (_loop1_37_var = _loop1_37_rule(p)) // except_block+ && (a = _PyPegen_expect_token(p, 663)) // token='except' && @@ -23001,7 +22999,7 @@ invalid_try_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23028,8 +23026,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_140_var; - asdl_seq * _loop1_39_var; + asdl_seq * _loop0_139_var; + asdl_seq * _loop1_38_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -23038,13 +23036,13 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_140_var = _loop0_140_rule(p)) // block* + (_loop0_139_var = _loop0_139_rule(p)) // block* && - (_loop1_39_var = _loop1_39_rule(p)) // except_star_block+ + (_loop1_38_var = _loop1_38_rule(p)) // except_star_block+ && (a = _PyPegen_expect_token(p, 663)) // token='except' && - (_opt_var = _tmp_141_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_140_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23107,7 +23105,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23141,7 +23139,7 @@ invalid_except_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23267,7 +23265,7 @@ invalid_except_star_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23304,7 +23302,7 @@ invalid_except_star_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23329,14 +23327,14 @@ invalid_except_star_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_star_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_142_var; + void *_tmp_141_var; Token * a; if ( (a = _PyPegen_expect_token(p, 663)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_142_var = _tmp_142_rule(p)) // NEWLINE | ':' + (_tmp_141_var = _tmp_141_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_star_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -23477,7 +23475,7 @@ invalid_except_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23571,7 +23569,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23933,7 +23931,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_143_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_142_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -24426,7 +24424,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_3 = _tmp_28_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_3 = _tmp_27_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24485,7 +24483,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_3 = _tmp_28_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_3 = _tmp_27_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -24543,7 +24541,7 @@ invalid_class_def_raw_rule(Parser *p) && (_opt_var = type_params_rule(p), !p->error_indicator) // type_params? && - (_opt_var_1 = _tmp_27_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var_1 = _tmp_26_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24582,7 +24580,7 @@ invalid_class_def_raw_rule(Parser *p) && (_opt_var = type_params_rule(p), !p->error_indicator) // type_params? && - (_opt_var_1 = _tmp_27_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var_1 = _tmp_26_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24632,11 +24630,11 @@ invalid_double_starred_kvpairs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_83_var; + asdl_seq * _gather_82_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_83_var = _gather_83_rule(p)) // ','.double_starred_kvpair+ + (_gather_82_var = _gather_82_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24644,7 +24642,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_83_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_82_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -24697,7 +24695,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_144_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_143_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24807,7 +24805,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_144_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_143_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -25095,7 +25093,7 @@ invalid_replacement_field_rule(Parser *p) && (annotated_rhs_var = annotated_rhs_rule(p)) // annotated_rhs && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_145_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_144_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs !('=' | '!' | ':' | '}')")); @@ -25127,7 +25125,7 @@ invalid_replacement_field_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_146_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_145_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '=' !('!' | ':' | '}')")); @@ -25191,9 +25189,9 @@ invalid_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_147_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_146_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_148_rule, p) + _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_147_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] !(':' | '}')")); @@ -25217,7 +25215,7 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_78_var; + asdl_seq * _loop0_77_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; @@ -25230,11 +25228,11 @@ invalid_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_147_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_146_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_78_var = _loop0_78_rule(p)) // fstring_format_spec* + (_loop0_77_var = _loop0_77_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -25271,7 +25269,7 @@ invalid_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_147_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_146_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -25318,7 +25316,7 @@ invalid_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_148_rule, p) + _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_147_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -25385,14 +25383,14 @@ invalid_arithmetic_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_arithmetic[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "sum ('+' | '-' | '*' | '/' | '%' | '//' | '@') 'not' inversion")); - void *_tmp_149_var; + void *_tmp_148_var; Token * a; expr_ty b; expr_ty sum_var; if ( (sum_var = sum_rule(p)) // sum && - (_tmp_149_var = _tmp_149_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' + (_tmp_148_var = _tmp_148_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' && (a = _PyPegen_expect_token(p, 687)) // token='not' && @@ -25437,11 +25435,11 @@ invalid_factor_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_factor[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('+' | '-' | '~') 'not' factor")); - void *_tmp_150_var; + void *_tmp_149_var; Token * a; expr_ty b; if ( - (_tmp_150_var = _tmp_150_rule(p)) // '+' | '-' | '~' + (_tmp_149_var = _tmp_149_rule(p)) // '+' | '-' | '~' && (a = _PyPegen_expect_token(p, 687)) // token='not' && @@ -26215,12 +26213,12 @@ _loop1_12_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_151_var; + void *_tmp_150_var; while ( - (_tmp_151_var = _tmp_151_rule(p)) // star_targets '=' + (_tmp_150_var = _tmp_150_rule(p)) // star_targets '=' ) { - _res = _tmp_151_var; + _res = _tmp_150_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26259,66 +26257,9 @@ _loop1_12_rule(Parser *p) return _seq; } -// _tmp_13: yield_expr | star_expressions +// _tmp_13: 'from' expression static void * _tmp_13_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // yield_expr - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); - expr_ty yield_expr_var; - if ( - (yield_expr_var = yield_expr_rule(p)) // yield_expr - ) - { - D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); - _res = yield_expr_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); - } - { // star_expressions - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); - expr_ty star_expressions_var; - if ( - (star_expressions_var = star_expressions_rule(p)) // star_expressions - ) - { - D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); - _res = star_expressions_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_14: 'from' expression -static void * -_tmp_14_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26334,7 +26275,7 @@ _tmp_14_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression")); + D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression")); Token * _keyword; expr_ty z; if ( @@ -26343,7 +26284,7 @@ _tmp_14_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_14[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression")); + D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26353,7 +26294,7 @@ _tmp_14_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_14[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from' expression")); } _res = NULL; @@ -26362,9 +26303,9 @@ _tmp_14_rule(Parser *p) return _res; } -// _loop0_15: ',' NAME +// _loop0_14: ',' NAME static asdl_seq * -_loop0_15_rule(Parser *p) +_loop0_14_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26389,7 +26330,7 @@ _loop0_15_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); + D(fprintf(stderr, "%*c> _loop0_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); Token * _literal; expr_ty elem; while ( @@ -26421,7 +26362,7 @@ _loop0_15_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_15[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_14[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' NAME")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26438,9 +26379,9 @@ _loop0_15_rule(Parser *p) return _seq; } -// _gather_16: NAME _loop0_15 +// _gather_15: NAME _loop0_14 static asdl_seq * -_gather_16_rule(Parser *p) +_gather_15_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26451,27 +26392,27 @@ _gather_16_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // NAME _loop0_15 + { // NAME _loop0_14 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_15")); + D(fprintf(stderr, "%*c> _gather_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_14")); expr_ty elem; asdl_seq * seq; if ( (elem = _PyPegen_name_token(p)) // NAME && - (seq = _loop0_15_rule(p)) // _loop0_15 + (seq = _loop0_14_rule(p)) // _loop0_14 ) { - D(fprintf(stderr, "%*c+ _gather_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_15")); + D(fprintf(stderr, "%*c+ _gather_15[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_14")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_16[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_15")); + D(fprintf(stderr, "%*c%s _gather_15[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_14")); } _res = NULL; done: @@ -26479,9 +26420,9 @@ _gather_16_rule(Parser *p) return _res; } -// _tmp_17: ';' | NEWLINE +// _tmp_16: ';' | NEWLINE static void * -_tmp_17_rule(Parser *p) +_tmp_16_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26497,18 +26438,18 @@ _tmp_17_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 13)) // token=';' ) { - D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';'")); } { // NEWLINE @@ -26516,18 +26457,18 @@ _tmp_17_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } _res = NULL; @@ -26536,9 +26477,9 @@ _tmp_17_rule(Parser *p) return _res; } -// _tmp_18: ',' expression +// _tmp_17: ',' expression static void * -_tmp_18_rule(Parser *p) +_tmp_17_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26554,7 +26495,7 @@ _tmp_18_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty z; if ( @@ -26563,7 +26504,7 @@ _tmp_18_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_18[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26573,7 +26514,7 @@ _tmp_18_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_18[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -26582,9 +26523,9 @@ _tmp_18_rule(Parser *p) return _res; } -// _loop0_19: ('.' | '...') +// _loop0_18: ('.' | '...') static asdl_seq * -_loop0_19_rule(Parser *p) +_loop0_18_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26609,13 +26550,13 @@ _loop0_19_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_152_var; + D(fprintf(stderr, "%*c> _loop0_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); + void *_tmp_151_var; while ( - (_tmp_152_var = _tmp_152_rule(p)) // '.' | '...' + (_tmp_151_var = _tmp_151_rule(p)) // '.' | '...' ) { - _res = _tmp_152_var; + _res = _tmp_151_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26632,7 +26573,7 @@ _loop0_19_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_19[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_18[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26649,9 +26590,9 @@ _loop0_19_rule(Parser *p) return _seq; } -// _loop1_20: ('.' | '...') +// _loop1_19: ('.' | '...') static asdl_seq * -_loop1_20_rule(Parser *p) +_loop1_19_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26676,13 +26617,13 @@ _loop1_20_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_152_var; + D(fprintf(stderr, "%*c> _loop1_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); + void *_tmp_151_var; while ( - (_tmp_152_var = _tmp_152_rule(p)) // '.' | '...' + (_tmp_151_var = _tmp_151_rule(p)) // '.' | '...' ) { - _res = _tmp_152_var; + _res = _tmp_151_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26699,7 +26640,7 @@ _loop1_20_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_20[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_19[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')")); } if (_n == 0 || p->error_indicator) { @@ -26721,9 +26662,9 @@ _loop1_20_rule(Parser *p) return _seq; } -// _loop0_21: ',' import_from_as_name +// _loop0_20: ',' import_from_as_name static asdl_seq * -_loop0_21_rule(Parser *p) +_loop0_20_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26748,7 +26689,7 @@ _loop0_21_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name")); + D(fprintf(stderr, "%*c> _loop0_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name")); Token * _literal; alias_ty elem; while ( @@ -26780,7 +26721,7 @@ _loop0_21_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_21[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_20[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' import_from_as_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26797,9 +26738,9 @@ _loop0_21_rule(Parser *p) return _seq; } -// _gather_22: import_from_as_name _loop0_21 +// _gather_21: import_from_as_name _loop0_20 static asdl_seq * -_gather_22_rule(Parser *p) +_gather_21_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26810,27 +26751,27 @@ _gather_22_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // import_from_as_name _loop0_21 + { // import_from_as_name _loop0_20 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_21")); + D(fprintf(stderr, "%*c> _gather_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_20")); alias_ty elem; asdl_seq * seq; if ( (elem = import_from_as_name_rule(p)) // import_from_as_name && - (seq = _loop0_21_rule(p)) // _loop0_21 + (seq = _loop0_20_rule(p)) // _loop0_20 ) { - D(fprintf(stderr, "%*c+ _gather_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_21")); + D(fprintf(stderr, "%*c+ _gather_21[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_20")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_22[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_21")); + D(fprintf(stderr, "%*c%s _gather_21[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_20")); } _res = NULL; done: @@ -26838,9 +26779,9 @@ _gather_22_rule(Parser *p) return _res; } -// _tmp_23: 'as' NAME +// _tmp_22: 'as' NAME static void * -_tmp_23_rule(Parser *p) +_tmp_22_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26856,7 +26797,7 @@ _tmp_23_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( @@ -26865,7 +26806,7 @@ _tmp_23_rule(Parser *p) (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26875,7 +26816,7 @@ _tmp_23_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_22[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -26884,9 +26825,9 @@ _tmp_23_rule(Parser *p) return _res; } -// _loop0_24: ',' dotted_as_name +// _loop0_23: ',' dotted_as_name static asdl_seq * -_loop0_24_rule(Parser *p) +_loop0_23_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26911,7 +26852,7 @@ _loop0_24_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name")); + D(fprintf(stderr, "%*c> _loop0_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name")); Token * _literal; alias_ty elem; while ( @@ -26943,7 +26884,7 @@ _loop0_24_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_24[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_23[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_as_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26960,9 +26901,9 @@ _loop0_24_rule(Parser *p) return _seq; } -// _gather_25: dotted_as_name _loop0_24 +// _gather_24: dotted_as_name _loop0_23 static asdl_seq * -_gather_25_rule(Parser *p) +_gather_24_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26973,27 +26914,27 @@ _gather_25_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // dotted_as_name _loop0_24 + { // dotted_as_name _loop0_23 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_24")); + D(fprintf(stderr, "%*c> _gather_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_23")); alias_ty elem; asdl_seq * seq; if ( (elem = dotted_as_name_rule(p)) // dotted_as_name && - (seq = _loop0_24_rule(p)) // _loop0_24 + (seq = _loop0_23_rule(p)) // _loop0_23 ) { - D(fprintf(stderr, "%*c+ _gather_25[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_24")); + D(fprintf(stderr, "%*c+ _gather_24[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_23")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_25[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_24")); + D(fprintf(stderr, "%*c%s _gather_24[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_23")); } _res = NULL; done: @@ -27001,9 +26942,9 @@ _gather_25_rule(Parser *p) return _res; } -// _loop1_26: ('@' named_expression NEWLINE) +// _loop1_25: ('@' named_expression NEWLINE) static asdl_seq * -_loop1_26_rule(Parser *p) +_loop1_25_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27028,13 +26969,13 @@ _loop1_26_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_153_var; + D(fprintf(stderr, "%*c> _loop1_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); + void *_tmp_152_var; while ( - (_tmp_153_var = _tmp_153_rule(p)) // '@' named_expression NEWLINE + (_tmp_152_var = _tmp_152_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_153_var; + _res = _tmp_152_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -27051,7 +26992,7 @@ _loop1_26_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_26[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_25[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('@' named_expression NEWLINE)")); } if (_n == 0 || p->error_indicator) { @@ -27073,9 +27014,9 @@ _loop1_26_rule(Parser *p) return _seq; } -// _tmp_27: '(' arguments? ')' +// _tmp_26: '(' arguments? ')' static void * -_tmp_27_rule(Parser *p) +_tmp_26_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27091,7 +27032,7 @@ _tmp_27_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *z; @@ -27103,7 +27044,7 @@ _tmp_27_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_27[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_26[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -27113,7 +27054,7 @@ _tmp_27_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_27[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_26[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -27122,9 +27063,9 @@ _tmp_27_rule(Parser *p) return _res; } -// _tmp_28: '->' expression +// _tmp_27: '->' expression static void * -_tmp_28_rule(Parser *p) +_tmp_27_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27140,7 +27081,7 @@ _tmp_28_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty z; if ( @@ -27149,7 +27090,7 @@ _tmp_28_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_28[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_27[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -27159,7 +27100,7 @@ _tmp_28_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_28[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_27[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -27168,9 +27109,143 @@ _tmp_28_rule(Parser *p) return _res; } -// _loop0_29: param_no_default +// _loop0_28: param_no_default +static asdl_seq * +_loop0_28_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // param_no_default + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + arg_ty param_no_default_var; + while ( + (param_no_default_var = param_no_default_rule(p)) // param_no_default + ) + { + _res = param_no_default_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_28[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop0_29: param_with_default static asdl_seq * _loop0_29_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // param_with_default + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + NameDefaultPair* param_with_default_var; + while ( + (param_with_default_var = param_with_default_rule(p)) // param_with_default + ) + { + _res = param_with_default_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_29[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop1_30: param_no_default +static asdl_seq * +_loop1_30_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27195,7 +27270,7 @@ _loop0_29_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -27218,141 +27293,7 @@ _loop0_29_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_29[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop0_30: param_with_default -static asdl_seq * -_loop0_30_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // param_with_default - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); - NameDefaultPair* param_with_default_var; - while ( - (param_with_default_var = param_with_default_rule(p)) // param_with_default - ) - { - _res = param_with_default_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_30[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop1_31: param_no_default -static asdl_seq * -_loop1_31_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // param_no_default - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop1_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); - arg_ty param_no_default_var; - while ( - (param_no_default_var = param_no_default_rule(p)) // param_no_default - ) - { - _res = param_no_default_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_31[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_30[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -27374,9 +27315,9 @@ _loop1_31_rule(Parser *p) return _seq; } -// _loop1_32: param_with_default +// _loop1_31: param_with_default static asdl_seq * -_loop1_32_rule(Parser *p) +_loop1_31_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27401,7 +27342,7 @@ _loop1_32_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -27424,7 +27365,7 @@ _loop1_32_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_32[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_31[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -27446,9 +27387,9 @@ _loop1_32_rule(Parser *p) return _seq; } -// _loop0_33: param_maybe_default +// _loop0_32: param_maybe_default static asdl_seq * -_loop0_33_rule(Parser *p) +_loop0_32_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27473,7 +27414,7 @@ _loop0_33_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -27496,7 +27437,7 @@ _loop0_33_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_33[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_32[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27513,9 +27454,9 @@ _loop0_33_rule(Parser *p) return _seq; } -// _loop1_34: param_maybe_default +// _loop1_33: param_maybe_default static asdl_seq * -_loop1_34_rule(Parser *p) +_loop1_33_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27540,7 +27481,7 @@ _loop1_34_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -27563,7 +27504,7 @@ _loop1_34_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_34[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_33[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -27585,9 +27526,9 @@ _loop1_34_rule(Parser *p) return _seq; } -// _loop0_35: ',' with_item +// _loop0_34: ',' with_item static asdl_seq * -_loop0_35_rule(Parser *p) +_loop0_34_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27612,7 +27553,7 @@ _loop0_35_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -27644,7 +27585,7 @@ _loop0_35_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_35[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_34[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27661,9 +27602,9 @@ _loop0_35_rule(Parser *p) return _seq; } -// _gather_36: with_item _loop0_35 +// _gather_35: with_item _loop0_34 static asdl_seq * -_gather_36_rule(Parser *p) +_gather_35_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27674,27 +27615,27 @@ _gather_36_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_35 + { // with_item _loop0_34 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_35")); + D(fprintf(stderr, "%*c> _gather_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_34")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_35_rule(p)) // _loop0_35 + (seq = _loop0_34_rule(p)) // _loop0_34 ) { - D(fprintf(stderr, "%*c+ _gather_36[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_35")); + D(fprintf(stderr, "%*c+ _gather_35[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_34")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_36[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_35")); + D(fprintf(stderr, "%*c%s _gather_35[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_34")); } _res = NULL; done: @@ -27702,9 +27643,9 @@ _gather_36_rule(Parser *p) return _res; } -// _tmp_37: ',' | ')' | ':' +// _tmp_36: ',' | ')' | ':' static void * -_tmp_37_rule(Parser *p) +_tmp_36_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27720,18 +27661,18 @@ _tmp_37_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_37[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_36[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_37[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_36[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -27739,18 +27680,18 @@ _tmp_37_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_37[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_36[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_37[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_36[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -27758,18 +27699,18 @@ _tmp_37_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_37[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_36[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_37[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_36[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -27778,9 +27719,9 @@ _tmp_37_rule(Parser *p) return _res; } -// _loop1_38: except_block +// _loop1_37: except_block static asdl_seq * -_loop1_38_rule(Parser *p) +_loop1_37_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27805,7 +27746,7 @@ _loop1_38_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); excepthandler_ty except_block_var; while ( (except_block_var = except_block_rule(p)) // except_block @@ -27828,7 +27769,7 @@ _loop1_38_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_38[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_37[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -27850,9 +27791,9 @@ _loop1_38_rule(Parser *p) return _seq; } -// _loop1_39: except_star_block +// _loop1_38: except_star_block static asdl_seq * -_loop1_39_rule(Parser *p) +_loop1_38_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27877,7 +27818,7 @@ _loop1_39_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); excepthandler_ty except_star_block_var; while ( (except_star_block_var = except_star_block_rule(p)) // except_star_block @@ -27900,7 +27841,7 @@ _loop1_39_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_39[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_38[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -27922,9 +27863,9 @@ _loop1_39_rule(Parser *p) return _seq; } -// _loop1_40: case_block +// _loop1_39: case_block static asdl_seq * -_loop1_40_rule(Parser *p) +_loop1_39_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27949,7 +27890,7 @@ _loop1_40_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block")); + D(fprintf(stderr, "%*c> _loop1_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block")); match_case_ty case_block_var; while ( (case_block_var = case_block_rule(p)) // case_block @@ -27972,7 +27913,7 @@ _loop1_40_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_40[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_39[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "case_block")); } if (_n == 0 || p->error_indicator) { @@ -27994,9 +27935,9 @@ _loop1_40_rule(Parser *p) return _seq; } -// _loop0_41: '|' closed_pattern +// _loop0_40: '|' closed_pattern static asdl_seq * -_loop0_41_rule(Parser *p) +_loop0_40_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28021,7 +27962,7 @@ _loop0_41_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern")); + D(fprintf(stderr, "%*c> _loop0_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern")); Token * _literal; pattern_ty elem; while ( @@ -28053,7 +27994,7 @@ _loop0_41_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_41[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_40[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'|' closed_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28070,9 +28011,9 @@ _loop0_41_rule(Parser *p) return _seq; } -// _gather_42: closed_pattern _loop0_41 +// _gather_41: closed_pattern _loop0_40 static asdl_seq * -_gather_42_rule(Parser *p) +_gather_41_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28083,27 +28024,27 @@ _gather_42_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // closed_pattern _loop0_41 + { // closed_pattern _loop0_40 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_41")); + D(fprintf(stderr, "%*c> _gather_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_40")); pattern_ty elem; asdl_seq * seq; if ( (elem = closed_pattern_rule(p)) // closed_pattern && - (seq = _loop0_41_rule(p)) // _loop0_41 + (seq = _loop0_40_rule(p)) // _loop0_40 ) { - D(fprintf(stderr, "%*c+ _gather_42[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_41")); + D(fprintf(stderr, "%*c+ _gather_41[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_40")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_42[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_41")); + D(fprintf(stderr, "%*c%s _gather_41[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_40")); } _res = NULL; done: @@ -28111,9 +28052,9 @@ _gather_42_rule(Parser *p) return _res; } -// _tmp_43: '+' | '-' +// _tmp_42: '+' | '-' static void * -_tmp_43_rule(Parser *p) +_tmp_42_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28129,18 +28070,18 @@ _tmp_43_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c> _tmp_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_43[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c+ _tmp_42[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_43[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_42[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } { // '-' @@ -28148,18 +28089,18 @@ _tmp_43_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c> _tmp_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_43[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c+ _tmp_42[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_43[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_42[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } _res = NULL; @@ -28168,9 +28109,9 @@ _tmp_43_rule(Parser *p) return _res; } -// _tmp_44: '.' | '(' | '=' +// _tmp_43: '.' | '(' | '=' static void * -_tmp_44_rule(Parser *p) +_tmp_43_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28186,18 +28127,18 @@ _tmp_44_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_44[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_43[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_44[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_43[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '(' @@ -28205,18 +28146,18 @@ _tmp_44_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_44[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_43[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_44[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_43[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '=' @@ -28224,18 +28165,18 @@ _tmp_44_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_44[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_43[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_44[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_43[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } _res = NULL; @@ -28244,9 +28185,9 @@ _tmp_44_rule(Parser *p) return _res; } -// _loop0_45: ',' maybe_star_pattern +// _loop0_44: ',' maybe_star_pattern static asdl_seq * -_loop0_45_rule(Parser *p) +_loop0_44_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28271,7 +28212,7 @@ _loop0_45_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); + D(fprintf(stderr, "%*c> _loop0_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); Token * _literal; pattern_ty elem; while ( @@ -28303,7 +28244,7 @@ _loop0_45_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_45[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_44[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' maybe_star_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28320,9 +28261,9 @@ _loop0_45_rule(Parser *p) return _seq; } -// _gather_46: maybe_star_pattern _loop0_45 +// _gather_45: maybe_star_pattern _loop0_44 static asdl_seq * -_gather_46_rule(Parser *p) +_gather_45_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28333,27 +28274,27 @@ _gather_46_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // maybe_star_pattern _loop0_45 + { // maybe_star_pattern _loop0_44 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_45")); + D(fprintf(stderr, "%*c> _gather_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_44")); pattern_ty elem; asdl_seq * seq; if ( (elem = maybe_star_pattern_rule(p)) // maybe_star_pattern && - (seq = _loop0_45_rule(p)) // _loop0_45 + (seq = _loop0_44_rule(p)) // _loop0_44 ) { - D(fprintf(stderr, "%*c+ _gather_46[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_45")); + D(fprintf(stderr, "%*c+ _gather_45[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_44")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_46[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_45")); + D(fprintf(stderr, "%*c%s _gather_45[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_44")); } _res = NULL; done: @@ -28361,9 +28302,9 @@ _gather_46_rule(Parser *p) return _res; } -// _loop0_47: ',' key_value_pattern +// _loop0_46: ',' key_value_pattern static asdl_seq * -_loop0_47_rule(Parser *p) +_loop0_46_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28388,7 +28329,7 @@ _loop0_47_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern")); + D(fprintf(stderr, "%*c> _loop0_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern")); Token * _literal; KeyPatternPair* elem; while ( @@ -28420,7 +28361,7 @@ _loop0_47_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_47[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_46[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' key_value_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28437,9 +28378,9 @@ _loop0_47_rule(Parser *p) return _seq; } -// _gather_48: key_value_pattern _loop0_47 +// _gather_47: key_value_pattern _loop0_46 static asdl_seq * -_gather_48_rule(Parser *p) +_gather_47_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28450,27 +28391,27 @@ _gather_48_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // key_value_pattern _loop0_47 + { // key_value_pattern _loop0_46 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_47")); + D(fprintf(stderr, "%*c> _gather_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_46")); KeyPatternPair* elem; asdl_seq * seq; if ( (elem = key_value_pattern_rule(p)) // key_value_pattern && - (seq = _loop0_47_rule(p)) // _loop0_47 + (seq = _loop0_46_rule(p)) // _loop0_46 ) { - D(fprintf(stderr, "%*c+ _gather_48[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_47")); + D(fprintf(stderr, "%*c+ _gather_47[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_46")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_48[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_47")); + D(fprintf(stderr, "%*c%s _gather_47[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_46")); } _res = NULL; done: @@ -28478,9 +28419,9 @@ _gather_48_rule(Parser *p) return _res; } -// _tmp_49: literal_expr | attr +// _tmp_48: literal_expr | attr static void * -_tmp_49_rule(Parser *p) +_tmp_48_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28496,18 +28437,18 @@ _tmp_49_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr")); + D(fprintf(stderr, "%*c> _tmp_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr")); expr_ty literal_expr_var; if ( (literal_expr_var = literal_expr_rule(p)) // literal_expr ) { - D(fprintf(stderr, "%*c+ _tmp_49[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr")); + D(fprintf(stderr, "%*c+ _tmp_48[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr")); _res = literal_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_49[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_48[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "literal_expr")); } { // attr @@ -28515,18 +28456,18 @@ _tmp_49_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr")); + D(fprintf(stderr, "%*c> _tmp_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr")); expr_ty attr_var; if ( (attr_var = attr_rule(p)) // attr ) { - D(fprintf(stderr, "%*c+ _tmp_49[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr")); + D(fprintf(stderr, "%*c+ _tmp_48[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr")); _res = attr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_49[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_48[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "attr")); } _res = NULL; @@ -28535,9 +28476,9 @@ _tmp_49_rule(Parser *p) return _res; } -// _loop0_50: ',' pattern +// _loop0_49: ',' pattern static asdl_seq * -_loop0_50_rule(Parser *p) +_loop0_49_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28562,7 +28503,7 @@ _loop0_50_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern")); + D(fprintf(stderr, "%*c> _loop0_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern")); Token * _literal; pattern_ty elem; while ( @@ -28594,7 +28535,7 @@ _loop0_50_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_50[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_49[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28611,9 +28552,9 @@ _loop0_50_rule(Parser *p) return _seq; } -// _gather_51: pattern _loop0_50 +// _gather_50: pattern _loop0_49 static asdl_seq * -_gather_51_rule(Parser *p) +_gather_50_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28624,27 +28565,27 @@ _gather_51_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // pattern _loop0_50 + { // pattern _loop0_49 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_50")); + D(fprintf(stderr, "%*c> _gather_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_49")); pattern_ty elem; asdl_seq * seq; if ( (elem = pattern_rule(p)) // pattern && - (seq = _loop0_50_rule(p)) // _loop0_50 + (seq = _loop0_49_rule(p)) // _loop0_49 ) { - D(fprintf(stderr, "%*c+ _gather_51[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_50")); + D(fprintf(stderr, "%*c+ _gather_50[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_49")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_51[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_50")); + D(fprintf(stderr, "%*c%s _gather_50[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_49")); } _res = NULL; done: @@ -28652,9 +28593,9 @@ _gather_51_rule(Parser *p) return _res; } -// _loop0_52: ',' keyword_pattern +// _loop0_51: ',' keyword_pattern static asdl_seq * -_loop0_52_rule(Parser *p) +_loop0_51_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28679,7 +28620,7 @@ _loop0_52_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); + D(fprintf(stderr, "%*c> _loop0_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); Token * _literal; KeyPatternPair* elem; while ( @@ -28711,7 +28652,7 @@ _loop0_52_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_52[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_51[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' keyword_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28728,9 +28669,9 @@ _loop0_52_rule(Parser *p) return _seq; } -// _gather_53: keyword_pattern _loop0_52 +// _gather_52: keyword_pattern _loop0_51 static asdl_seq * -_gather_53_rule(Parser *p) +_gather_52_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28741,27 +28682,27 @@ _gather_53_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // keyword_pattern _loop0_52 + { // keyword_pattern _loop0_51 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_52")); + D(fprintf(stderr, "%*c> _gather_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_51")); KeyPatternPair* elem; asdl_seq * seq; if ( (elem = keyword_pattern_rule(p)) // keyword_pattern && - (seq = _loop0_52_rule(p)) // _loop0_52 + (seq = _loop0_51_rule(p)) // _loop0_51 ) { - D(fprintf(stderr, "%*c+ _gather_53[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_52")); + D(fprintf(stderr, "%*c+ _gather_52[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_51")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_53[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_52")); + D(fprintf(stderr, "%*c%s _gather_52[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_51")); } _res = NULL; done: @@ -28769,9 +28710,9 @@ _gather_53_rule(Parser *p) return _res; } -// _loop0_54: ',' type_param +// _loop0_53: ',' type_param static asdl_seq * -_loop0_54_rule(Parser *p) +_loop0_53_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28796,7 +28737,7 @@ _loop0_54_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param")); + D(fprintf(stderr, "%*c> _loop0_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param")); Token * _literal; type_param_ty elem; while ( @@ -28828,7 +28769,7 @@ _loop0_54_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_54[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_53[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' type_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28845,9 +28786,9 @@ _loop0_54_rule(Parser *p) return _seq; } -// _gather_55: type_param _loop0_54 +// _gather_54: type_param _loop0_53 static asdl_seq * -_gather_55_rule(Parser *p) +_gather_54_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28858,27 +28799,27 @@ _gather_55_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // type_param _loop0_54 + { // type_param _loop0_53 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_54")); + D(fprintf(stderr, "%*c> _gather_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_53")); type_param_ty elem; asdl_seq * seq; if ( (elem = type_param_rule(p)) // type_param && - (seq = _loop0_54_rule(p)) // _loop0_54 + (seq = _loop0_53_rule(p)) // _loop0_53 ) { - D(fprintf(stderr, "%*c+ _gather_55[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "type_param _loop0_54")); + D(fprintf(stderr, "%*c+ _gather_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "type_param _loop0_53")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_55[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "type_param _loop0_54")); + D(fprintf(stderr, "%*c%s _gather_54[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "type_param _loop0_53")); } _res = NULL; done: @@ -28886,9 +28827,9 @@ _gather_55_rule(Parser *p) return _res; } -// _loop1_56: (',' expression) +// _loop1_55: (',' expression) static asdl_seq * -_loop1_56_rule(Parser *p) +_loop1_55_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28913,13 +28854,13 @@ _loop1_56_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_18_var; + D(fprintf(stderr, "%*c> _loop1_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); + void *_tmp_17_var; while ( - (_tmp_18_var = _tmp_18_rule(p)) // ',' expression + (_tmp_17_var = _tmp_17_rule(p)) // ',' expression ) { - _res = _tmp_18_var; + _res = _tmp_17_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28936,7 +28877,7 @@ _loop1_56_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_56[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_55[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' expression)")); } if (_n == 0 || p->error_indicator) { @@ -28958,9 +28899,9 @@ _loop1_56_rule(Parser *p) return _seq; } -// _loop1_57: (',' star_expression) +// _loop1_56: (',' star_expression) static asdl_seq * -_loop1_57_rule(Parser *p) +_loop1_56_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28985,13 +28926,13 @@ _loop1_57_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_154_var; + D(fprintf(stderr, "%*c> _loop1_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); + void *_tmp_153_var; while ( - (_tmp_154_var = _tmp_154_rule(p)) // ',' star_expression + (_tmp_153_var = _tmp_153_rule(p)) // ',' star_expression ) { - _res = _tmp_154_var; + _res = _tmp_153_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29008,7 +28949,7 @@ _loop1_57_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_57[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_56[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)")); } if (_n == 0 || p->error_indicator) { @@ -29030,9 +28971,9 @@ _loop1_57_rule(Parser *p) return _seq; } -// _loop0_58: ',' star_named_expression +// _loop0_57: ',' star_named_expression static asdl_seq * -_loop0_58_rule(Parser *p) +_loop0_57_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29057,7 +28998,7 @@ _loop0_58_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); + D(fprintf(stderr, "%*c> _loop0_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); Token * _literal; expr_ty elem; while ( @@ -29089,7 +29030,7 @@ _loop0_58_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_58[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_57[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29106,9 +29047,9 @@ _loop0_58_rule(Parser *p) return _seq; } -// _gather_59: star_named_expression _loop0_58 +// _gather_58: star_named_expression _loop0_57 static asdl_seq * -_gather_59_rule(Parser *p) +_gather_58_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29119,27 +29060,27 @@ _gather_59_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_named_expression _loop0_58 + { // star_named_expression _loop0_57 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_58")); + D(fprintf(stderr, "%*c> _gather_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_57")); expr_ty elem; asdl_seq * seq; if ( (elem = star_named_expression_rule(p)) // star_named_expression && - (seq = _loop0_58_rule(p)) // _loop0_58 + (seq = _loop0_57_rule(p)) // _loop0_57 ) { - D(fprintf(stderr, "%*c+ _gather_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_58")); + D(fprintf(stderr, "%*c+ _gather_58[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_57")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_59[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_58")); + D(fprintf(stderr, "%*c%s _gather_58[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_57")); } _res = NULL; done: @@ -29147,9 +29088,9 @@ _gather_59_rule(Parser *p) return _res; } -// _loop1_60: ('or' conjunction) +// _loop1_59: ('or' conjunction) static asdl_seq * -_loop1_60_rule(Parser *p) +_loop1_59_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29174,13 +29115,13 @@ _loop1_60_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_155_var; + D(fprintf(stderr, "%*c> _loop1_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); + void *_tmp_154_var; while ( - (_tmp_155_var = _tmp_155_rule(p)) // 'or' conjunction + (_tmp_154_var = _tmp_154_rule(p)) // 'or' conjunction ) { - _res = _tmp_155_var; + _res = _tmp_154_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29197,7 +29138,7 @@ _loop1_60_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_60[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_59[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)")); } if (_n == 0 || p->error_indicator) { @@ -29219,9 +29160,9 @@ _loop1_60_rule(Parser *p) return _seq; } -// _loop1_61: ('and' inversion) +// _loop1_60: ('and' inversion) static asdl_seq * -_loop1_61_rule(Parser *p) +_loop1_60_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29246,13 +29187,13 @@ _loop1_61_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_156_var; + D(fprintf(stderr, "%*c> _loop1_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); + void *_tmp_155_var; while ( - (_tmp_156_var = _tmp_156_rule(p)) // 'and' inversion + (_tmp_155_var = _tmp_155_rule(p)) // 'and' inversion ) { - _res = _tmp_156_var; + _res = _tmp_155_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29269,7 +29210,7 @@ _loop1_61_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_60[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('and' inversion)")); } if (_n == 0 || p->error_indicator) { @@ -29291,9 +29232,9 @@ _loop1_61_rule(Parser *p) return _seq; } -// _loop1_62: compare_op_bitwise_or_pair +// _loop1_61: compare_op_bitwise_or_pair static asdl_seq * -_loop1_62_rule(Parser *p) +_loop1_61_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29318,7 +29259,7 @@ _loop1_62_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); + D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); CmpopExprPair* compare_op_bitwise_or_pair_var; while ( (compare_op_bitwise_or_pair_var = compare_op_bitwise_or_pair_rule(p)) // compare_op_bitwise_or_pair @@ -29341,7 +29282,7 @@ _loop1_62_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_62[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compare_op_bitwise_or_pair")); } if (_n == 0 || p->error_indicator) { @@ -29363,9 +29304,9 @@ _loop1_62_rule(Parser *p) return _seq; } -// _tmp_63: '!=' +// _tmp_62: '!=' static void * -_tmp_63_rule(Parser *p) +_tmp_62_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29381,13 +29322,13 @@ _tmp_63_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c> _tmp_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); Token * tok; if ( (tok = _PyPegen_expect_token(p, 28)) // token='!=' ) { - D(fprintf(stderr, "%*c+ _tmp_63[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c+ _tmp_62[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); _res = _PyPegen_check_barry_as_flufl ( p , tok ) ? NULL : tok; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -29397,7 +29338,7 @@ _tmp_63_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_63[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_62[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!='")); } _res = NULL; @@ -29406,9 +29347,9 @@ _tmp_63_rule(Parser *p) return _res; } -// _loop0_64: ',' (slice | starred_expression) +// _loop0_63: ',' (slice | starred_expression) static asdl_seq * -_loop0_64_rule(Parser *p) +_loop0_63_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29433,13 +29374,13 @@ _loop0_64_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); + D(fprintf(stderr, "%*c> _loop0_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_157_rule(p)) // slice | starred_expression + (elem = _tmp_156_rule(p)) // slice | starred_expression ) { _res = elem; @@ -29465,7 +29406,7 @@ _loop0_64_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_64[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_63[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (slice | starred_expression)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29482,9 +29423,9 @@ _loop0_64_rule(Parser *p) return _seq; } -// _gather_65: (slice | starred_expression) _loop0_64 +// _gather_64: (slice | starred_expression) _loop0_63 static asdl_seq * -_gather_65_rule(Parser *p) +_gather_64_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29495,27 +29436,27 @@ _gather_65_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (slice | starred_expression) _loop0_64 + { // (slice | starred_expression) _loop0_63 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_64")); + D(fprintf(stderr, "%*c> _gather_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_63")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_157_rule(p)) // slice | starred_expression + (elem = _tmp_156_rule(p)) // slice | starred_expression && - (seq = _loop0_64_rule(p)) // _loop0_64 + (seq = _loop0_63_rule(p)) // _loop0_63 ) { - D(fprintf(stderr, "%*c+ _gather_65[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_64")); + D(fprintf(stderr, "%*c+ _gather_64[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_63")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_65[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_64")); + D(fprintf(stderr, "%*c%s _gather_64[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_63")); } _res = NULL; done: @@ -29523,9 +29464,9 @@ _gather_65_rule(Parser *p) return _res; } -// _tmp_66: ':' expression? +// _tmp_65: ':' expression? static void * -_tmp_66_rule(Parser *p) +_tmp_65_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29541,7 +29482,7 @@ _tmp_66_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c> _tmp_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); Token * _literal; void *d; if ( @@ -29550,7 +29491,7 @@ _tmp_66_rule(Parser *p) (d = expression_rule(p), !p->error_indicator) // expression? ) { - D(fprintf(stderr, "%*c+ _tmp_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c+ _tmp_65[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -29560,7 +29501,7 @@ _tmp_66_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_66[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_65[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' expression?")); } _res = NULL; @@ -29569,9 +29510,9 @@ _tmp_66_rule(Parser *p) return _res; } -// _tmp_67: STRING | FSTRING_START +// _tmp_66: STRING | FSTRING_START static void * -_tmp_67_rule(Parser *p) +_tmp_66_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29587,18 +29528,18 @@ _tmp_67_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); + D(fprintf(stderr, "%*c> _tmp_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); expr_ty string_var; if ( (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING")); + D(fprintf(stderr, "%*c+ _tmp_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_66[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING")); } { // FSTRING_START @@ -29606,18 +29547,18 @@ _tmp_67_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); + D(fprintf(stderr, "%*c> _tmp_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); Token * fstring_start_var; if ( (fstring_start_var = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' ) { - D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); + D(fprintf(stderr, "%*c+ _tmp_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); _res = fstring_start_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_66[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START")); } _res = NULL; @@ -29626,9 +29567,9 @@ _tmp_67_rule(Parser *p) return _res; } -// _tmp_68: tuple | group | genexp +// _tmp_67: tuple | group | genexp static void * -_tmp_68_rule(Parser *p) +_tmp_67_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29644,18 +29585,18 @@ _tmp_68_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // group @@ -29663,18 +29604,18 @@ _tmp_68_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); expr_ty group_var; if ( (group_var = group_rule(p)) // group ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); _res = group_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "group")); } { // genexp @@ -29682,18 +29623,18 @@ _tmp_68_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } _res = NULL; @@ -29702,9 +29643,9 @@ _tmp_68_rule(Parser *p) return _res; } -// _tmp_69: list | listcomp +// _tmp_68: list | listcomp static void * -_tmp_69_rule(Parser *p) +_tmp_68_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29720,18 +29661,18 @@ _tmp_69_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // listcomp @@ -29739,18 +29680,18 @@ _tmp_69_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); expr_ty listcomp_var; if ( (listcomp_var = listcomp_rule(p)) // listcomp ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); _res = listcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "listcomp")); } _res = NULL; @@ -29759,9 +29700,9 @@ _tmp_69_rule(Parser *p) return _res; } -// _tmp_70: dict | set | dictcomp | setcomp +// _tmp_69: dict | set | dictcomp | setcomp static void * -_tmp_70_rule(Parser *p) +_tmp_69_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29777,18 +29718,18 @@ _tmp_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); expr_ty dict_var; if ( (dict_var = dict_rule(p)) // dict ) { - D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); _res = dict_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict")); } { // set @@ -29796,18 +29737,18 @@ _tmp_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); expr_ty set_var; if ( (set_var = set_rule(p)) // set ) { - D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); _res = set_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set")); } { // dictcomp @@ -29815,18 +29756,18 @@ _tmp_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); expr_ty dictcomp_var; if ( (dictcomp_var = dictcomp_rule(p)) // dictcomp ) { - D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); _res = dictcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp")); } { // setcomp @@ -29834,18 +29775,18 @@ _tmp_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); expr_ty setcomp_var; if ( (setcomp_var = setcomp_rule(p)) // setcomp ) { - D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); _res = setcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp")); } _res = NULL; @@ -29854,9 +29795,9 @@ _tmp_70_rule(Parser *p) return _res; } -// _tmp_71: yield_expr | named_expression +// _tmp_70: yield_expr | named_expression static void * -_tmp_71_rule(Parser *p) +_tmp_70_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29872,18 +29813,18 @@ _tmp_71_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // named_expression @@ -29891,18 +29832,18 @@ _tmp_71_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); expr_ty named_expression_var; if ( (named_expression_var = named_expression_rule(p)) // named_expression ) { - D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); _res = named_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression")); } _res = NULL; @@ -29911,9 +29852,9 @@ _tmp_71_rule(Parser *p) return _res; } -// _loop0_72: lambda_param_no_default +// _loop0_71: lambda_param_no_default static asdl_seq * -_loop0_72_rule(Parser *p) +_loop0_71_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29938,7 +29879,7 @@ _loop0_72_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -29961,7 +29902,7 @@ _loop0_72_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_72[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_71[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29978,9 +29919,9 @@ _loop0_72_rule(Parser *p) return _seq; } -// _loop0_73: lambda_param_with_default +// _loop0_72: lambda_param_with_default static asdl_seq * -_loop0_73_rule(Parser *p) +_loop0_72_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30005,7 +29946,7 @@ _loop0_73_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -30028,7 +29969,7 @@ _loop0_73_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_73[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_72[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30045,9 +29986,9 @@ _loop0_73_rule(Parser *p) return _seq; } -// _loop1_74: lambda_param_no_default +// _loop1_73: lambda_param_no_default static asdl_seq * -_loop1_74_rule(Parser *p) +_loop1_73_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30072,7 +30013,7 @@ _loop1_74_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -30095,7 +30036,7 @@ _loop1_74_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_74[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_73[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -30117,9 +30058,9 @@ _loop1_74_rule(Parser *p) return _seq; } -// _loop1_75: lambda_param_with_default +// _loop1_74: lambda_param_with_default static asdl_seq * -_loop1_75_rule(Parser *p) +_loop1_74_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30144,7 +30085,7 @@ _loop1_75_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -30167,7 +30108,7 @@ _loop1_75_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_75[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_74[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -30189,9 +30130,9 @@ _loop1_75_rule(Parser *p) return _seq; } -// _loop0_76: lambda_param_maybe_default +// _loop0_75: lambda_param_maybe_default static asdl_seq * -_loop0_76_rule(Parser *p) +_loop0_75_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30216,7 +30157,7 @@ _loop0_76_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -30239,7 +30180,7 @@ _loop0_76_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_76[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_75[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30256,9 +30197,9 @@ _loop0_76_rule(Parser *p) return _seq; } -// _loop1_77: lambda_param_maybe_default +// _loop1_76: lambda_param_maybe_default static asdl_seq * -_loop1_77_rule(Parser *p) +_loop1_76_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30283,7 +30224,7 @@ _loop1_77_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -30306,7 +30247,7 @@ _loop1_77_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_77[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_76[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -30328,9 +30269,9 @@ _loop1_77_rule(Parser *p) return _seq; } -// _loop0_78: fstring_format_spec +// _loop0_77: fstring_format_spec static asdl_seq * -_loop0_78_rule(Parser *p) +_loop0_77_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30355,7 +30296,7 @@ _loop0_78_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -30378,7 +30319,7 @@ _loop0_78_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_77[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30395,9 +30336,9 @@ _loop0_78_rule(Parser *p) return _seq; } -// _loop0_79: fstring_middle +// _loop0_78: fstring_middle static asdl_seq * -_loop0_79_rule(Parser *p) +_loop0_78_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30422,7 +30363,7 @@ _loop0_79_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); + D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); expr_ty fstring_middle_var; while ( (fstring_middle_var = fstring_middle_rule(p)) // fstring_middle @@ -30445,7 +30386,7 @@ _loop0_79_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_79[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_middle")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30462,9 +30403,9 @@ _loop0_79_rule(Parser *p) return _seq; } -// _loop1_80: (fstring | string) +// _loop1_79: (fstring | string) static asdl_seq * -_loop1_80_rule(Parser *p) +_loop1_79_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30489,13 +30430,13 @@ _loop1_80_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_158_var; + D(fprintf(stderr, "%*c> _loop1_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); + void *_tmp_157_var; while ( - (_tmp_158_var = _tmp_158_rule(p)) // fstring | string + (_tmp_157_var = _tmp_157_rule(p)) // fstring | string ) { - _res = _tmp_158_var; + _res = _tmp_157_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30512,7 +30453,7 @@ _loop1_80_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_80[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_79[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | string)")); } if (_n == 0 || p->error_indicator) { @@ -30534,9 +30475,9 @@ _loop1_80_rule(Parser *p) return _seq; } -// _tmp_81: star_named_expression ',' star_named_expressions? +// _tmp_80: star_named_expression ',' star_named_expressions? static void * -_tmp_81_rule(Parser *p) +_tmp_80_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30552,7 +30493,7 @@ _tmp_81_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c> _tmp_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); Token * _literal; expr_ty y; void *z; @@ -30564,7 +30505,7 @@ _tmp_81_rule(Parser *p) (z = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions? ) { - D(fprintf(stderr, "%*c+ _tmp_81[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c+ _tmp_80[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); _res = _PyPegen_seq_insert_in_front ( p , y , z ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -30574,7 +30515,7 @@ _tmp_81_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_81[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_80[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?")); } _res = NULL; @@ -30583,9 +30524,9 @@ _tmp_81_rule(Parser *p) return _res; } -// _loop0_82: ',' double_starred_kvpair +// _loop0_81: ',' double_starred_kvpair static asdl_seq * -_loop0_82_rule(Parser *p) +_loop0_81_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30610,7 +30551,7 @@ _loop0_82_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -30642,7 +30583,7 @@ _loop0_82_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_82[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_81[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30659,9 +30600,9 @@ _loop0_82_rule(Parser *p) return _seq; } -// _gather_83: double_starred_kvpair _loop0_82 +// _gather_82: double_starred_kvpair _loop0_81 static asdl_seq * -_gather_83_rule(Parser *p) +_gather_82_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30672,27 +30613,27 @@ _gather_83_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_82 + { // double_starred_kvpair _loop0_81 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_82")); + D(fprintf(stderr, "%*c> _gather_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_81")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_82_rule(p)) // _loop0_82 + (seq = _loop0_81_rule(p)) // _loop0_81 ) { - D(fprintf(stderr, "%*c+ _gather_83[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_82")); + D(fprintf(stderr, "%*c+ _gather_82[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_81")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_83[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_82")); + D(fprintf(stderr, "%*c%s _gather_82[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_81")); } _res = NULL; done: @@ -30700,9 +30641,9 @@ _gather_83_rule(Parser *p) return _res; } -// _loop1_84: for_if_clause +// _loop1_83: for_if_clause static asdl_seq * -_loop1_84_rule(Parser *p) +_loop1_83_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30727,7 +30668,7 @@ _loop1_84_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); + D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); comprehension_ty for_if_clause_var; while ( (for_if_clause_var = for_if_clause_rule(p)) // for_if_clause @@ -30750,7 +30691,7 @@ _loop1_84_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_84[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause")); } if (_n == 0 || p->error_indicator) { @@ -30772,9 +30713,9 @@ _loop1_84_rule(Parser *p) return _seq; } -// _loop0_85: ('if' disjunction) +// _loop0_84: ('if' disjunction) static asdl_seq * -_loop0_85_rule(Parser *p) +_loop0_84_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30799,13 +30740,13 @@ _loop0_85_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_159_var; + D(fprintf(stderr, "%*c> _loop0_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_158_var; while ( - (_tmp_159_var = _tmp_159_rule(p)) // 'if' disjunction + (_tmp_158_var = _tmp_158_rule(p)) // 'if' disjunction ) { - _res = _tmp_159_var; + _res = _tmp_158_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30822,7 +30763,7 @@ _loop0_85_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_85[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_84[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30839,9 +30780,9 @@ _loop0_85_rule(Parser *p) return _seq; } -// _tmp_86: assignment_expression | expression !':=' +// _tmp_85: assignment_expression | expression !':=' static void * -_tmp_86_rule(Parser *p) +_tmp_85_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30857,18 +30798,18 @@ _tmp_86_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_86[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_85[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_86[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_85[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -30876,7 +30817,7 @@ _tmp_86_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -30884,12 +30825,12 @@ _tmp_86_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_86[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_85[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_86[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_85[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -30898,9 +30839,9 @@ _tmp_86_rule(Parser *p) return _res; } -// _loop0_87: ',' (starred_expression | (assignment_expression | expression !':=') !'=') +// _loop0_86: ',' (starred_expression | (assignment_expression | expression !':=') !'=') static asdl_seq * -_loop0_87_rule(Parser *p) +_loop0_86_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30925,13 +30866,13 @@ _loop0_87_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_160_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_159_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -30957,7 +30898,7 @@ _loop0_87_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_87[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30974,10 +30915,10 @@ _loop0_87_rule(Parser *p) return _seq; } -// _gather_88: -// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_87 +// _gather_87: +// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_86 static asdl_seq * -_gather_88_rule(Parser *p) +_gather_87_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30988,27 +30929,27 @@ _gather_88_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_87 + { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_86 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_87")); + D(fprintf(stderr, "%*c> _gather_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_86")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_160_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_159_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && - (seq = _loop0_87_rule(p)) // _loop0_87 + (seq = _loop0_86_rule(p)) // _loop0_86 ) { - D(fprintf(stderr, "%*c+ _gather_88[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_87")); + D(fprintf(stderr, "%*c+ _gather_87[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_86")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_88[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_87")); + D(fprintf(stderr, "%*c%s _gather_87[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_86")); } _res = NULL; done: @@ -31016,9 +30957,9 @@ _gather_88_rule(Parser *p) return _res; } -// _tmp_89: ',' kwargs +// _tmp_88: ',' kwargs static void * -_tmp_89_rule(Parser *p) +_tmp_88_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31034,7 +30975,7 @@ _tmp_89_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c> _tmp_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); Token * _literal; asdl_seq* k; if ( @@ -31043,7 +30984,7 @@ _tmp_89_rule(Parser *p) (k = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c+ _tmp_88[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); _res = k; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -31053,7 +30994,7 @@ _tmp_89_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_89[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_88[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs")); } _res = NULL; @@ -31062,9 +31003,9 @@ _tmp_89_rule(Parser *p) return _res; } -// _loop0_90: ',' kwarg_or_starred +// _loop0_89: ',' kwarg_or_starred static asdl_seq * -_loop0_90_rule(Parser *p) +_loop0_89_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31089,7 +31030,7 @@ _loop0_90_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c> _loop0_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -31121,7 +31062,7 @@ _loop0_90_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_90[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_89[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31138,9 +31079,9 @@ _loop0_90_rule(Parser *p) return _seq; } -// _gather_91: kwarg_or_starred _loop0_90 +// _gather_90: kwarg_or_starred _loop0_89 static asdl_seq * -_gather_91_rule(Parser *p) +_gather_90_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31151,27 +31092,27 @@ _gather_91_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_starred _loop0_90 + { // kwarg_or_starred _loop0_89 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_90")); + D(fprintf(stderr, "%*c> _gather_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_89")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred && - (seq = _loop0_90_rule(p)) // _loop0_90 + (seq = _loop0_89_rule(p)) // _loop0_89 ) { - D(fprintf(stderr, "%*c+ _gather_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_90")); + D(fprintf(stderr, "%*c+ _gather_90[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_89")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_91[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_90")); + D(fprintf(stderr, "%*c%s _gather_90[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_89")); } _res = NULL; done: @@ -31179,9 +31120,9 @@ _gather_91_rule(Parser *p) return _res; } -// _loop0_92: ',' kwarg_or_double_starred +// _loop0_91: ',' kwarg_or_double_starred static asdl_seq * -_loop0_92_rule(Parser *p) +_loop0_91_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31206,7 +31147,7 @@ _loop0_92_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + D(fprintf(stderr, "%*c> _loop0_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -31238,7 +31179,7 @@ _loop0_92_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_92[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_91[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31255,9 +31196,9 @@ _loop0_92_rule(Parser *p) return _seq; } -// _gather_93: kwarg_or_double_starred _loop0_92 +// _gather_92: kwarg_or_double_starred _loop0_91 static asdl_seq * -_gather_93_rule(Parser *p) +_gather_92_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31268,27 +31209,27 @@ _gather_93_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_92 + { // kwarg_or_double_starred _loop0_91 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_92")); + D(fprintf(stderr, "%*c> _gather_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_91")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred && - (seq = _loop0_92_rule(p)) // _loop0_92 + (seq = _loop0_91_rule(p)) // _loop0_91 ) { - D(fprintf(stderr, "%*c+ _gather_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_92")); + D(fprintf(stderr, "%*c+ _gather_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_91")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_93[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_92")); + D(fprintf(stderr, "%*c%s _gather_92[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_91")); } _res = NULL; done: @@ -31296,9 +31237,9 @@ _gather_93_rule(Parser *p) return _res; } -// _loop0_94: (',' star_target) +// _loop0_93: (',' star_target) static asdl_seq * -_loop0_94_rule(Parser *p) +_loop0_93_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31323,13 +31264,13 @@ _loop0_94_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_161_var; + D(fprintf(stderr, "%*c> _loop0_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_160_var; while ( - (_tmp_161_var = _tmp_161_rule(p)) // ',' star_target + (_tmp_160_var = _tmp_160_rule(p)) // ',' star_target ) { - _res = _tmp_161_var; + _res = _tmp_160_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31346,7 +31287,7 @@ _loop0_94_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_94[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_93[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31363,9 +31304,9 @@ _loop0_94_rule(Parser *p) return _seq; } -// _loop0_95: ',' star_target +// _loop0_94: ',' star_target static asdl_seq * -_loop0_95_rule(Parser *p) +_loop0_94_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31390,7 +31331,7 @@ _loop0_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _loop0_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty elem; while ( @@ -31422,7 +31363,7 @@ _loop0_95_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31439,9 +31380,9 @@ _loop0_95_rule(Parser *p) return _seq; } -// _gather_96: star_target _loop0_95 +// _gather_95: star_target _loop0_94 static asdl_seq * -_gather_96_rule(Parser *p) +_gather_95_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31452,27 +31393,27 @@ _gather_96_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_target _loop0_95 + { // star_target _loop0_94 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_95")); + D(fprintf(stderr, "%*c> _gather_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_94")); expr_ty elem; asdl_seq * seq; if ( (elem = star_target_rule(p)) // star_target && - (seq = _loop0_95_rule(p)) // _loop0_95 + (seq = _loop0_94_rule(p)) // _loop0_94 ) { - D(fprintf(stderr, "%*c+ _gather_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_95")); + D(fprintf(stderr, "%*c+ _gather_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_94")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_96[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_95")); + D(fprintf(stderr, "%*c%s _gather_95[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_94")); } _res = NULL; done: @@ -31480,9 +31421,9 @@ _gather_96_rule(Parser *p) return _res; } -// _loop1_97: (',' star_target) +// _loop1_96: (',' star_target) static asdl_seq * -_loop1_97_rule(Parser *p) +_loop1_96_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31507,13 +31448,13 @@ _loop1_97_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_161_var; + D(fprintf(stderr, "%*c> _loop1_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_160_var; while ( - (_tmp_161_var = _tmp_161_rule(p)) // ',' star_target + (_tmp_160_var = _tmp_160_rule(p)) // ',' star_target ) { - _res = _tmp_161_var; + _res = _tmp_160_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31530,7 +31471,7 @@ _loop1_97_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } if (_n == 0 || p->error_indicator) { @@ -31552,9 +31493,9 @@ _loop1_97_rule(Parser *p) return _seq; } -// _tmp_98: !'*' star_target +// _tmp_97: !'*' star_target static void * -_tmp_98_rule(Parser *p) +_tmp_97_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31570,7 +31511,7 @@ _tmp_98_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); expr_ty star_target_var; if ( _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16) // token='*' @@ -31578,12 +31519,12 @@ _tmp_98_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_98[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); _res = star_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target")); } _res = NULL; @@ -31592,9 +31533,9 @@ _tmp_98_rule(Parser *p) return _res; } -// _loop0_99: ',' del_target +// _loop0_98: ',' del_target static asdl_seq * -_loop0_99_rule(Parser *p) +_loop0_98_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31619,7 +31560,7 @@ _loop0_99_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); + D(fprintf(stderr, "%*c> _loop0_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); Token * _literal; expr_ty elem; while ( @@ -31651,7 +31592,7 @@ _loop0_99_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_99[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_98[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31668,9 +31609,9 @@ _loop0_99_rule(Parser *p) return _seq; } -// _gather_100: del_target _loop0_99 +// _gather_99: del_target _loop0_98 static asdl_seq * -_gather_100_rule(Parser *p) +_gather_99_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31681,27 +31622,27 @@ _gather_100_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // del_target _loop0_99 + { // del_target _loop0_98 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_99")); + D(fprintf(stderr, "%*c> _gather_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_98")); expr_ty elem; asdl_seq * seq; if ( (elem = del_target_rule(p)) // del_target && - (seq = _loop0_99_rule(p)) // _loop0_99 + (seq = _loop0_98_rule(p)) // _loop0_98 ) { - D(fprintf(stderr, "%*c+ _gather_100[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_99")); + D(fprintf(stderr, "%*c+ _gather_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_98")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_100[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_99")); + D(fprintf(stderr, "%*c%s _gather_99[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_98")); } _res = NULL; done: @@ -31709,9 +31650,9 @@ _gather_100_rule(Parser *p) return _res; } -// _loop0_101: ',' expression +// _loop0_100: ',' expression static asdl_seq * -_loop0_101_rule(Parser *p) +_loop0_100_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31736,7 +31677,7 @@ _loop0_101_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -31768,7 +31709,7 @@ _loop0_101_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_101[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_100[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31785,9 +31726,9 @@ _loop0_101_rule(Parser *p) return _seq; } -// _gather_102: expression _loop0_101 +// _gather_101: expression _loop0_100 static asdl_seq * -_gather_102_rule(Parser *p) +_gather_101_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31798,27 +31739,27 @@ _gather_102_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_101 + { // expression _loop0_100 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_101")); + D(fprintf(stderr, "%*c> _gather_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_100")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_101_rule(p)) // _loop0_101 + (seq = _loop0_100_rule(p)) // _loop0_100 ) { - D(fprintf(stderr, "%*c+ _gather_102[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_101")); + D(fprintf(stderr, "%*c+ _gather_101[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_100")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_102[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_101")); + D(fprintf(stderr, "%*c%s _gather_101[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_100")); } _res = NULL; done: @@ -31826,9 +31767,9 @@ _gather_102_rule(Parser *p) return _res; } -// _tmp_103: NEWLINE INDENT +// _tmp_102: NEWLINE INDENT static void * -_tmp_103_rule(Parser *p) +_tmp_102_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31844,7 +31785,7 @@ _tmp_103_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c> _tmp_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); Token * indent_var; Token * newline_var; if ( @@ -31853,12 +31794,12 @@ _tmp_103_rule(Parser *p) (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' ) { - D(fprintf(stderr, "%*c+ _tmp_103[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c+ _tmp_102[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); _res = _PyPegen_dummy_name(p, newline_var, indent_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_103[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_102[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE INDENT")); } _res = NULL; @@ -31867,11 +31808,11 @@ _tmp_103_rule(Parser *p) return _res; } -// _tmp_104: +// _tmp_103: // | (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) // | kwargs static void * -_tmp_104_rule(Parser *p) +_tmp_103_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31887,18 +31828,18 @@ _tmp_104_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); - void *_tmp_162_var; + D(fprintf(stderr, "%*c> _tmp_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + void *_tmp_161_var; if ( - (_tmp_162_var = _tmp_162_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs + (_tmp_161_var = _tmp_161_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_104[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); - _res = _tmp_162_var; + D(fprintf(stderr, "%*c+ _tmp_103[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + _res = _tmp_161_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_104[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_103[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); } { // kwargs @@ -31906,18 +31847,18 @@ _tmp_104_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwargs")); + D(fprintf(stderr, "%*c> _tmp_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwargs")); asdl_seq* kwargs_var; if ( (kwargs_var = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_104[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwargs")); + D(fprintf(stderr, "%*c+ _tmp_103[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwargs")); _res = kwargs_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_104[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_103[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwargs")); } _res = NULL; @@ -31926,9 +31867,9 @@ _tmp_104_rule(Parser *p) return _res; } -// _loop0_105: ',' (starred_expression !'=') +// _loop0_104: ',' (starred_expression !'=') static asdl_seq * -_loop0_105_rule(Parser *p) +_loop0_104_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31953,13 +31894,13 @@ _loop0_105_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression !'=')")); + D(fprintf(stderr, "%*c> _loop0_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression !'=')")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_163_rule(p)) // starred_expression !'=' + (elem = _tmp_162_rule(p)) // starred_expression !'=' ) { _res = elem; @@ -31985,7 +31926,7 @@ _loop0_105_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_105[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_104[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression !'=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32002,9 +31943,9 @@ _loop0_105_rule(Parser *p) return _seq; } -// _gather_106: (starred_expression !'=') _loop0_105 +// _gather_105: (starred_expression !'=') _loop0_104 static asdl_seq * -_gather_106_rule(Parser *p) +_gather_105_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32015,27 +31956,27 @@ _gather_106_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression !'=') _loop0_105 + { // (starred_expression !'=') _loop0_104 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_105")); + D(fprintf(stderr, "%*c> _gather_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_104")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_163_rule(p)) // starred_expression !'=' + (elem = _tmp_162_rule(p)) // starred_expression !'=' && - (seq = _loop0_105_rule(p)) // _loop0_105 + (seq = _loop0_104_rule(p)) // _loop0_104 ) { - D(fprintf(stderr, "%*c+ _gather_106[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_105")); + D(fprintf(stderr, "%*c+ _gather_105[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_104")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_106[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression !'=') _loop0_105")); + D(fprintf(stderr, "%*c%s _gather_105[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression !'=') _loop0_104")); } _res = NULL; done: @@ -32043,9 +31984,9 @@ _gather_106_rule(Parser *p) return _res; } -// _tmp_107: args | expression for_if_clauses +// _tmp_106: args | expression for_if_clauses static void * -_tmp_107_rule(Parser *p) +_tmp_106_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32061,18 +32002,18 @@ _tmp_107_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); expr_ty args_var; if ( (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ _tmp_107[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_106[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); _res = args_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_107[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_106[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args")); } { // expression for_if_clauses @@ -32080,7 +32021,7 @@ _tmp_107_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); expr_ty expression_var; asdl_comprehension_seq* for_if_clauses_var; if ( @@ -32089,12 +32030,12 @@ _tmp_107_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_107[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_106[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_107[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_106[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses")); } _res = NULL; @@ -32103,9 +32044,9 @@ _tmp_107_rule(Parser *p) return _res; } -// _tmp_108: args ',' +// _tmp_107: args ',' static void * -_tmp_108_rule(Parser *p) +_tmp_107_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32121,7 +32062,7 @@ _tmp_108_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c> _tmp_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); Token * _literal; expr_ty args_var; if ( @@ -32130,12 +32071,12 @@ _tmp_108_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_108[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c+ _tmp_107[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); _res = _PyPegen_dummy_name(p, args_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_108[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_107[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ','")); } _res = NULL; @@ -32144,9 +32085,9 @@ _tmp_108_rule(Parser *p) return _res; } -// _tmp_109: ',' | ')' +// _tmp_108: ',' | ')' static void * -_tmp_109_rule(Parser *p) +_tmp_108_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32162,18 +32103,18 @@ _tmp_109_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_108[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_109[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_108[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -32181,18 +32122,18 @@ _tmp_109_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_108[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_109[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_108[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } _res = NULL; @@ -32201,9 +32142,9 @@ _tmp_109_rule(Parser *p) return _res; } -// _tmp_110: 'True' | 'False' | 'None' +// _tmp_109: 'True' | 'False' | 'None' static void * -_tmp_110_rule(Parser *p) +_tmp_109_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32219,18 +32160,18 @@ _tmp_110_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 610)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_109[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'False' @@ -32238,18 +32179,18 @@ _tmp_110_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 612)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_109[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } { // 'None' @@ -32257,18 +32198,18 @@ _tmp_110_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 611)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_109[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } _res = NULL; @@ -32277,9 +32218,9 @@ _tmp_110_rule(Parser *p) return _res; } -// _tmp_111: NAME '=' +// _tmp_110: NAME '=' static void * -_tmp_111_rule(Parser *p) +_tmp_110_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32295,7 +32236,7 @@ _tmp_111_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); Token * _literal; expr_ty name_var; if ( @@ -32304,12 +32245,12 @@ _tmp_111_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); _res = _PyPegen_dummy_name(p, name_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME '='")); } _res = NULL; @@ -32318,9 +32259,9 @@ _tmp_111_rule(Parser *p) return _res; } -// _tmp_112: NAME STRING | SOFT_KEYWORD +// _tmp_111: NAME STRING | SOFT_KEYWORD static void * -_tmp_112_rule(Parser *p) +_tmp_111_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32336,7 +32277,7 @@ _tmp_112_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); expr_ty name_var; expr_ty string_var; if ( @@ -32345,12 +32286,12 @@ _tmp_112_rule(Parser *p) (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); _res = _PyPegen_dummy_name(p, name_var, string_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME STRING")); } { // SOFT_KEYWORD @@ -32358,18 +32299,18 @@ _tmp_112_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); expr_ty soft_keyword_var; if ( (soft_keyword_var = _PyPegen_soft_keyword_token(p)) // SOFT_KEYWORD ) { - D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); _res = soft_keyword_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "SOFT_KEYWORD")); } _res = NULL; @@ -32378,9 +32319,9 @@ _tmp_112_rule(Parser *p) return _res; } -// _tmp_113: 'else' | ':' +// _tmp_112: 'else' | ':' static void * -_tmp_113_rule(Parser *p) +_tmp_112_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32396,18 +32337,18 @@ _tmp_113_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 671)) // token='else' ) { - D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'else'")); } { // ':' @@ -32415,18 +32356,18 @@ _tmp_113_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -32435,9 +32376,9 @@ _tmp_113_rule(Parser *p) return _res; } -// _tmp_114: '=' | ':=' +// _tmp_113: '=' | ':=' static void * -_tmp_114_rule(Parser *p) +_tmp_113_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32453,18 +32394,18 @@ _tmp_114_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -32472,18 +32413,18 @@ _tmp_114_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -32492,9 +32433,9 @@ _tmp_114_rule(Parser *p) return _res; } -// _tmp_115: list | tuple | genexp | 'True' | 'None' | 'False' +// _tmp_114: list | tuple | genexp | 'True' | 'None' | 'False' static void * -_tmp_115_rule(Parser *p) +_tmp_114_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32510,18 +32451,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // tuple @@ -32529,18 +32470,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // genexp @@ -32548,18 +32489,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } { // 'True' @@ -32567,18 +32508,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 610)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'None' @@ -32586,18 +32527,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 611)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } { // 'False' @@ -32605,18 +32546,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 612)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } _res = NULL; @@ -32625,9 +32566,9 @@ _tmp_115_rule(Parser *p) return _res; } -// _loop0_116: star_named_expressions +// _loop0_115: star_named_expressions static asdl_seq * -_loop0_116_rule(Parser *p) +_loop0_115_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32652,7 +32593,7 @@ _loop0_116_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_expr_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -32675,7 +32616,7 @@ _loop0_116_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_115[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32692,9 +32633,9 @@ _loop0_116_rule(Parser *p) return _seq; } -// _loop0_117: (star_targets '=') +// _loop0_116: (star_targets '=') static asdl_seq * -_loop0_117_rule(Parser *p) +_loop0_116_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32719,13 +32660,13 @@ _loop0_117_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_151_var; + D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_150_var; while ( - (_tmp_151_var = _tmp_151_rule(p)) // star_targets '=' + (_tmp_150_var = _tmp_150_rule(p)) // star_targets '=' ) { - _res = _tmp_151_var; + _res = _tmp_150_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32742,7 +32683,7 @@ _loop0_117_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_117[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32759,9 +32700,9 @@ _loop0_117_rule(Parser *p) return _seq; } -// _tmp_118: '[' | '(' | '{' +// _tmp_117: '[' | '(' | '{' static void * -_tmp_118_rule(Parser *p) +_tmp_117_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32777,18 +32718,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_117[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '(' @@ -32796,18 +32737,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_117[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '{' @@ -32815,18 +32756,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_117[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -32835,9 +32776,9 @@ _tmp_118_rule(Parser *p) return _res; } -// _tmp_119: '[' | '{' +// _tmp_118: '[' | '{' static void * -_tmp_119_rule(Parser *p) +_tmp_118_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32853,18 +32794,18 @@ _tmp_119_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_119[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -32872,18 +32813,18 @@ _tmp_119_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_119[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -32892,9 +32833,9 @@ _tmp_119_rule(Parser *p) return _res; } -// _tmp_120: slash_no_default | slash_with_default +// _tmp_119: slash_no_default | slash_with_default static void * -_tmp_120_rule(Parser *p) +_tmp_119_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32910,18 +32851,18 @@ _tmp_120_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_119[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -32929,18 +32870,18 @@ _tmp_120_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_119[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -32949,9 +32890,9 @@ _tmp_120_rule(Parser *p) return _res; } -// _tmp_121: ',' | param_no_default +// _tmp_120: ',' | param_no_default static void * -_tmp_121_rule(Parser *p) +_tmp_120_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32967,18 +32908,18 @@ _tmp_121_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // param_no_default @@ -32986,18 +32927,18 @@ _tmp_121_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } _res = NULL; @@ -33006,9 +32947,9 @@ _tmp_121_rule(Parser *p) return _res; } -// _tmp_122: ')' | ',' +// _tmp_121: ')' | ',' static void * -_tmp_122_rule(Parser *p) +_tmp_121_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33024,18 +32965,18 @@ _tmp_122_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' @@ -33043,18 +32984,18 @@ _tmp_122_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -33063,9 +33004,9 @@ _tmp_122_rule(Parser *p) return _res; } -// _tmp_123: ')' | ',' (')' | '**') +// _tmp_122: ')' | ',' (')' | '**') static void * -_tmp_123_rule(Parser *p) +_tmp_122_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33081,18 +33022,18 @@ _tmp_123_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -33100,21 +33041,21 @@ _tmp_123_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_164_var; + void *_tmp_163_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_164_var = _tmp_164_rule(p)) // ')' | '**' + (_tmp_163_var = _tmp_163_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_164_var); + D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_163_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -33123,9 +33064,9 @@ _tmp_123_rule(Parser *p) return _res; } -// _tmp_124: param_no_default | ',' +// _tmp_123: param_no_default | ',' static void * -_tmp_124_rule(Parser *p) +_tmp_123_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33141,18 +33082,18 @@ _tmp_124_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -33160,18 +33101,18 @@ _tmp_124_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -33180,9 +33121,9 @@ _tmp_124_rule(Parser *p) return _res; } -// _tmp_125: '*' | '**' | '/' +// _tmp_124: '*' | '**' | '/' static void * -_tmp_125_rule(Parser *p) +_tmp_124_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33198,18 +33139,18 @@ _tmp_125_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -33217,18 +33158,18 @@ _tmp_125_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -33236,18 +33177,18 @@ _tmp_125_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -33256,9 +33197,9 @@ _tmp_125_rule(Parser *p) return _res; } -// _tmp_126: lambda_slash_no_default | lambda_slash_with_default +// _tmp_125: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_126_rule(Parser *p) +_tmp_125_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33274,18 +33215,18 @@ _tmp_126_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -33293,18 +33234,18 @@ _tmp_126_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -33313,9 +33254,9 @@ _tmp_126_rule(Parser *p) return _res; } -// _loop0_127: ',' lambda_param +// _loop0_126: ',' lambda_param static asdl_seq * -_loop0_127_rule(Parser *p) +_loop0_126_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33340,7 +33281,7 @@ _loop0_127_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); + D(fprintf(stderr, "%*c> _loop0_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); Token * _literal; arg_ty elem; while ( @@ -33372,7 +33313,7 @@ _loop0_127_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_126[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' lambda_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33389,9 +33330,9 @@ _loop0_127_rule(Parser *p) return _seq; } -// _gather_128: lambda_param _loop0_127 +// _gather_127: lambda_param _loop0_126 static asdl_seq * -_gather_128_rule(Parser *p) +_gather_127_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33402,27 +33343,27 @@ _gather_128_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // lambda_param _loop0_127 + { // lambda_param _loop0_126 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_127")); + D(fprintf(stderr, "%*c> _gather_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_126")); arg_ty elem; asdl_seq * seq; if ( (elem = lambda_param_rule(p)) // lambda_param && - (seq = _loop0_127_rule(p)) // _loop0_127 + (seq = _loop0_126_rule(p)) // _loop0_126 ) { - D(fprintf(stderr, "%*c+ _gather_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_127")); + D(fprintf(stderr, "%*c+ _gather_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_126")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_128[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_127")); + D(fprintf(stderr, "%*c%s _gather_127[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_126")); } _res = NULL; done: @@ -33430,9 +33371,9 @@ _gather_128_rule(Parser *p) return _res; } -// _tmp_129: ',' | lambda_param_no_default +// _tmp_128: ',' | lambda_param_no_default static void * -_tmp_129_rule(Parser *p) +_tmp_128_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33448,18 +33389,18 @@ _tmp_129_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_128[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // lambda_param_no_default @@ -33467,18 +33408,18 @@ _tmp_129_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_128[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } _res = NULL; @@ -33487,9 +33428,9 @@ _tmp_129_rule(Parser *p) return _res; } -// _tmp_130: ':' | ',' (':' | '**') +// _tmp_129: ':' | ',' (':' | '**') static void * -_tmp_130_rule(Parser *p) +_tmp_129_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33505,18 +33446,18 @@ _tmp_130_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -33524,21 +33465,21 @@ _tmp_130_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_165_var; + void *_tmp_164_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_165_var = _tmp_165_rule(p)) // ':' | '**' + (_tmp_164_var = _tmp_164_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_165_var); + D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_164_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -33547,9 +33488,9 @@ _tmp_130_rule(Parser *p) return _res; } -// _tmp_131: lambda_param_no_default | ',' +// _tmp_130: lambda_param_no_default | ',' static void * -_tmp_131_rule(Parser *p) +_tmp_130_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33565,18 +33506,18 @@ _tmp_131_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -33584,18 +33525,18 @@ _tmp_131_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -33604,9 +33545,9 @@ _tmp_131_rule(Parser *p) return _res; } -// _tmp_132: bitwise_or ((',' bitwise_or))* ','? +// _tmp_131: bitwise_or ((',' bitwise_or))* ','? static void * -_tmp_132_rule(Parser *p) +_tmp_131_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33622,25 +33563,25 @@ _tmp_132_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); - asdl_seq * _loop0_166_var; + D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); + asdl_seq * _loop0_165_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty bitwise_or_var; if ( (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - (_loop0_166_var = _loop0_166_rule(p)) // ((',' bitwise_or))* + (_loop0_165_var = _loop0_165_rule(p)) // ((',' bitwise_or))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); - _res = _PyPegen_dummy_name(p, bitwise_or_var, _loop0_166_var, _opt_var); + D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); + _res = _PyPegen_dummy_name(p, bitwise_or_var, _loop0_165_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); } _res = NULL; @@ -33649,9 +33590,9 @@ _tmp_132_rule(Parser *p) return _res; } -// _loop0_133: ',' dotted_name +// _loop0_132: ',' dotted_name static asdl_seq * -_loop0_133_rule(Parser *p) +_loop0_132_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33676,7 +33617,7 @@ _loop0_133_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); + D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); Token * _literal; expr_ty elem; while ( @@ -33708,7 +33649,7 @@ _loop0_133_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_133[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_132[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33725,9 +33666,9 @@ _loop0_133_rule(Parser *p) return _seq; } -// _gather_134: dotted_name _loop0_133 +// _gather_133: dotted_name _loop0_132 static asdl_seq * -_gather_134_rule(Parser *p) +_gather_133_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33738,27 +33679,27 @@ _gather_134_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // dotted_name _loop0_133 + { // dotted_name _loop0_132 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_133")); + D(fprintf(stderr, "%*c> _gather_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_132")); expr_ty elem; asdl_seq * seq; if ( (elem = dotted_name_rule(p)) // dotted_name && - (seq = _loop0_133_rule(p)) // _loop0_133 + (seq = _loop0_132_rule(p)) // _loop0_132 ) { - D(fprintf(stderr, "%*c+ _gather_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_133")); + D(fprintf(stderr, "%*c+ _gather_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_132")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_134[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_133")); + D(fprintf(stderr, "%*c%s _gather_133[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_132")); } _res = NULL; done: @@ -33766,9 +33707,9 @@ _gather_134_rule(Parser *p) return _res; } -// _loop0_135: ',' (expression ['as' star_target]) +// _loop0_134: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_135_rule(Parser *p) +_loop0_134_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33793,13 +33734,13 @@ _loop0_135_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_167_rule(p)) // expression ['as' star_target] + (elem = _tmp_166_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -33825,7 +33766,7 @@ _loop0_135_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_135[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_134[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33842,9 +33783,9 @@ _loop0_135_rule(Parser *p) return _seq; } -// _gather_136: (expression ['as' star_target]) _loop0_135 +// _gather_135: (expression ['as' star_target]) _loop0_134 static asdl_seq * -_gather_136_rule(Parser *p) +_gather_135_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33855,27 +33796,27 @@ _gather_136_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_135 + { // (expression ['as' star_target]) _loop0_134 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_135")); + D(fprintf(stderr, "%*c> _gather_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_134")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_167_rule(p)) // expression ['as' star_target] + (elem = _tmp_166_rule(p)) // expression ['as' star_target] && - (seq = _loop0_135_rule(p)) // _loop0_135 + (seq = _loop0_134_rule(p)) // _loop0_134 ) { - D(fprintf(stderr, "%*c+ _gather_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_135")); + D(fprintf(stderr, "%*c+ _gather_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_134")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_136[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_135")); + D(fprintf(stderr, "%*c%s _gather_135[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_134")); } _res = NULL; done: @@ -33883,9 +33824,9 @@ _gather_136_rule(Parser *p) return _res; } -// _loop0_137: ',' (expressions ['as' star_target]) +// _loop0_136: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_137_rule(Parser *p) +_loop0_136_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33910,13 +33851,13 @@ _loop0_137_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_168_rule(p)) // expressions ['as' star_target] + (elem = _tmp_167_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -33942,7 +33883,7 @@ _loop0_137_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_137[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33959,9 +33900,9 @@ _loop0_137_rule(Parser *p) return _seq; } -// _gather_138: (expressions ['as' star_target]) _loop0_137 +// _gather_137: (expressions ['as' star_target]) _loop0_136 static asdl_seq * -_gather_138_rule(Parser *p) +_gather_137_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -33972,27 +33913,27 @@ _gather_138_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_137 + { // (expressions ['as' star_target]) _loop0_136 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_137")); + D(fprintf(stderr, "%*c> _gather_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_136")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_168_rule(p)) // expressions ['as' star_target] + (elem = _tmp_167_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_137_rule(p)) // _loop0_137 + (seq = _loop0_136_rule(p)) // _loop0_136 ) { - D(fprintf(stderr, "%*c+ _gather_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_137")); + D(fprintf(stderr, "%*c+ _gather_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_136")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_138[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_137")); + D(fprintf(stderr, "%*c%s _gather_137[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_136")); } _res = NULL; done: @@ -34000,9 +33941,9 @@ _gather_138_rule(Parser *p) return _res; } -// _tmp_139: 'except' | 'finally' +// _tmp_138: 'except' | 'finally' static void * -_tmp_139_rule(Parser *p) +_tmp_138_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34018,18 +33959,18 @@ _tmp_139_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 663)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); } { // 'finally' @@ -34037,18 +33978,18 @@ _tmp_139_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 659)) // token='finally' ) { - D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; @@ -34057,9 +33998,9 @@ _tmp_139_rule(Parser *p) return _res; } -// _loop0_140: block +// _loop0_139: block static asdl_seq * -_loop0_140_rule(Parser *p) +_loop0_139_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34084,7 +34025,7 @@ _loop0_140_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -34107,7 +34048,7 @@ _loop0_140_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_140[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_139[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34124,9 +34065,9 @@ _loop0_140_rule(Parser *p) return _seq; } -// _tmp_141: expression ['as' NAME] +// _tmp_140: expression ['as' NAME] static void * -_tmp_141_rule(Parser *p) +_tmp_140_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34142,22 +34083,22 @@ _tmp_141_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_23_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_22_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -34166,9 +34107,9 @@ _tmp_141_rule(Parser *p) return _res; } -// _tmp_142: NEWLINE | ':' +// _tmp_141: NEWLINE | ':' static void * -_tmp_142_rule(Parser *p) +_tmp_141_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34184,18 +34125,18 @@ _tmp_142_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -34203,18 +34144,18 @@ _tmp_142_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -34223,9 +34164,9 @@ _tmp_142_rule(Parser *p) return _res; } -// _tmp_143: positional_patterns ',' +// _tmp_142: positional_patterns ',' static void * -_tmp_143_rule(Parser *p) +_tmp_142_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34241,7 +34182,7 @@ _tmp_143_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -34250,12 +34191,12 @@ _tmp_143_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -34264,9 +34205,9 @@ _tmp_143_rule(Parser *p) return _res; } -// _tmp_144: '}' | ',' +// _tmp_143: '}' | ',' static void * -_tmp_144_rule(Parser *p) +_tmp_143_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34282,18 +34223,18 @@ _tmp_144_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -34301,18 +34242,18 @@ _tmp_144_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -34321,9 +34262,9 @@ _tmp_144_rule(Parser *p) return _res; } -// _tmp_145: '=' | '!' | ':' | '}' +// _tmp_144: '=' | '!' | ':' | '}' static void * -_tmp_145_rule(Parser *p) +_tmp_144_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34339,18 +34280,18 @@ _tmp_145_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // '!' @@ -34358,18 +34299,18 @@ _tmp_145_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -34377,18 +34318,18 @@ _tmp_145_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -34396,18 +34337,18 @@ _tmp_145_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -34416,9 +34357,9 @@ _tmp_145_rule(Parser *p) return _res; } -// _tmp_146: '!' | ':' | '}' +// _tmp_145: '!' | ':' | '}' static void * -_tmp_146_rule(Parser *p) +_tmp_145_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34434,18 +34375,18 @@ _tmp_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -34453,18 +34394,18 @@ _tmp_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -34472,18 +34413,18 @@ _tmp_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -34492,9 +34433,9 @@ _tmp_146_rule(Parser *p) return _res; } -// _tmp_147: '!' NAME +// _tmp_146: '!' NAME static void * -_tmp_147_rule(Parser *p) +_tmp_146_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34510,7 +34451,7 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -34519,12 +34460,12 @@ _tmp_147_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -34533,9 +34474,9 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: ':' | '}' +// _tmp_147: ':' | '}' static void * -_tmp_148_rule(Parser *p) +_tmp_147_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34551,18 +34492,18 @@ _tmp_148_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -34570,18 +34511,18 @@ _tmp_148_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -34590,9 +34531,9 @@ _tmp_148_rule(Parser *p) return _res; } -// _tmp_149: '+' | '-' | '*' | '/' | '%' | '//' | '@' +// _tmp_148: '+' | '-' | '*' | '/' | '%' | '//' | '@' static void * -_tmp_149_rule(Parser *p) +_tmp_148_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34608,18 +34549,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } { // '-' @@ -34627,18 +34568,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } { // '*' @@ -34646,18 +34587,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '/' @@ -34665,18 +34606,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } { // '%' @@ -34684,18 +34625,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'%'")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'%'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 24)) // token='%' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'%'")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'%'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'%'")); } { // '//' @@ -34703,18 +34644,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'//'")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'//'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 47)) // token='//' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'//'")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'//'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'//'")); } { // '@' @@ -34722,18 +34663,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 49)) // token='@' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); } _res = NULL; @@ -34742,9 +34683,9 @@ _tmp_149_rule(Parser *p) return _res; } -// _tmp_150: '+' | '-' | '~' +// _tmp_149: '+' | '-' | '~' static void * -_tmp_150_rule(Parser *p) +_tmp_149_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34760,18 +34701,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } { // '-' @@ -34779,18 +34720,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } { // '~' @@ -34798,18 +34739,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'~'")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'~'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 31)) // token='~' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'~'")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'~'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'~'")); } _res = NULL; @@ -34818,9 +34759,9 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: star_targets '=' +// _tmp_150: star_targets '=' static void * -_tmp_151_rule(Parser *p) +_tmp_150_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34836,7 +34777,7 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -34845,7 +34786,7 @@ _tmp_151_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -34855,7 +34796,7 @@ _tmp_151_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -34864,9 +34805,9 @@ _tmp_151_rule(Parser *p) return _res; } -// _tmp_152: '.' | '...' +// _tmp_151: '.' | '...' static void * -_tmp_152_rule(Parser *p) +_tmp_151_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34882,18 +34823,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -34901,18 +34842,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -34921,9 +34862,9 @@ _tmp_152_rule(Parser *p) return _res; } -// _tmp_153: '@' named_expression NEWLINE +// _tmp_152: '@' named_expression NEWLINE static void * -_tmp_153_rule(Parser *p) +_tmp_152_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34939,7 +34880,7 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -34951,7 +34892,7 @@ _tmp_153_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -34961,7 +34902,7 @@ _tmp_153_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -34970,9 +34911,9 @@ _tmp_153_rule(Parser *p) return _res; } -// _tmp_154: ',' star_expression +// _tmp_153: ',' star_expression static void * -_tmp_154_rule(Parser *p) +_tmp_153_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34988,7 +34929,7 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -34997,7 +34938,7 @@ _tmp_154_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -35007,7 +34948,7 @@ _tmp_154_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -35016,9 +34957,9 @@ _tmp_154_rule(Parser *p) return _res; } -// _tmp_155: 'or' conjunction +// _tmp_154: 'or' conjunction static void * -_tmp_155_rule(Parser *p) +_tmp_154_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35034,7 +34975,7 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -35043,7 +34984,7 @@ _tmp_155_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -35053,7 +34994,7 @@ _tmp_155_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -35062,9 +35003,9 @@ _tmp_155_rule(Parser *p) return _res; } -// _tmp_156: 'and' inversion +// _tmp_155: 'and' inversion static void * -_tmp_156_rule(Parser *p) +_tmp_155_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35080,7 +35021,7 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -35089,7 +35030,7 @@ _tmp_156_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -35099,7 +35040,7 @@ _tmp_156_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -35108,9 +35049,9 @@ _tmp_156_rule(Parser *p) return _res; } -// _tmp_157: slice | starred_expression +// _tmp_156: slice | starred_expression static void * -_tmp_157_rule(Parser *p) +_tmp_156_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35126,18 +35067,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -35145,18 +35086,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -35165,9 +35106,9 @@ _tmp_157_rule(Parser *p) return _res; } -// _tmp_158: fstring | string +// _tmp_157: fstring | string static void * -_tmp_158_rule(Parser *p) +_tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35183,18 +35124,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -35202,18 +35143,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -35222,9 +35163,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _tmp_159: 'if' disjunction +// _tmp_158: 'if' disjunction static void * -_tmp_159_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35240,7 +35181,7 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -35249,7 +35190,7 @@ _tmp_159_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -35259,7 +35200,7 @@ _tmp_159_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -35268,9 +35209,9 @@ _tmp_159_rule(Parser *p) return _res; } -// _tmp_160: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_159: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_160_rule(Parser *p) +_tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35286,18 +35227,18 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -35305,20 +35246,20 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_86_var; + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_85_var; if ( - (_tmp_86_var = _tmp_86_rule(p)) // assignment_expression | expression !':=' + (_tmp_85_var = _tmp_85_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_86_var; + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_85_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -35327,9 +35268,9 @@ _tmp_160_rule(Parser *p) return _res; } -// _tmp_161: ',' star_target +// _tmp_160: ',' star_target static void * -_tmp_161_rule(Parser *p) +_tmp_160_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35345,7 +35286,7 @@ _tmp_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -35354,7 +35295,7 @@ _tmp_161_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -35364,7 +35305,7 @@ _tmp_161_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -35373,10 +35314,10 @@ _tmp_161_rule(Parser *p) return _res; } -// _tmp_162: +// _tmp_161: // | ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs static void * -_tmp_162_rule(Parser *p) +_tmp_161_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35392,24 +35333,24 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); - asdl_seq * _gather_88_var; + D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + asdl_seq * _gather_87_var; Token * _literal; asdl_seq* kwargs_var; if ( - (_gather_88_var = _gather_88_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + (_gather_87_var = _gather_87_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && (kwargs_var = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); - _res = _PyPegen_dummy_name(p, _gather_88_var, _literal, kwargs_var); + D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + _res = _PyPegen_dummy_name(p, _gather_87_var, _literal, kwargs_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); } _res = NULL; @@ -35418,9 +35359,9 @@ _tmp_162_rule(Parser *p) return _res; } -// _tmp_163: starred_expression !'=' +// _tmp_162: starred_expression !'=' static void * -_tmp_163_rule(Parser *p) +_tmp_162_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35436,7 +35377,7 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); + D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression @@ -35444,12 +35385,12 @@ _tmp_163_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); + D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression !'='")); } _res = NULL; @@ -35458,9 +35399,9 @@ _tmp_163_rule(Parser *p) return _res; } -// _tmp_164: ')' | '**' +// _tmp_163: ')' | '**' static void * -_tmp_164_rule(Parser *p) +_tmp_163_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35476,18 +35417,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -35495,18 +35436,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -35515,9 +35456,9 @@ _tmp_164_rule(Parser *p) return _res; } -// _tmp_165: ':' | '**' +// _tmp_164: ':' | '**' static void * -_tmp_165_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35533,18 +35474,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -35552,18 +35493,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -35572,9 +35513,9 @@ _tmp_165_rule(Parser *p) return _res; } -// _loop0_166: (',' bitwise_or) +// _loop0_165: (',' bitwise_or) static asdl_seq * -_loop0_166_rule(Parser *p) +_loop0_165_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35599,13 +35540,13 @@ _loop0_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' bitwise_or)")); - void *_tmp_169_var; + D(fprintf(stderr, "%*c> _loop0_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' bitwise_or)")); + void *_tmp_168_var; while ( - (_tmp_169_var = _tmp_169_rule(p)) // ',' bitwise_or + (_tmp_168_var = _tmp_168_rule(p)) // ',' bitwise_or ) { - _res = _tmp_169_var; + _res = _tmp_168_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35622,7 +35563,7 @@ _loop0_166_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' bitwise_or)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35639,9 +35580,9 @@ _loop0_166_rule(Parser *p) return _seq; } -// _tmp_167: expression ['as' star_target] +// _tmp_166: expression ['as' star_target] static void * -_tmp_167_rule(Parser *p) +_tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35657,22 +35598,22 @@ _tmp_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_170_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_169_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -35681,9 +35622,9 @@ _tmp_167_rule(Parser *p) return _res; } -// _tmp_168: expressions ['as' star_target] +// _tmp_167: expressions ['as' star_target] static void * -_tmp_168_rule(Parser *p) +_tmp_167_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35699,22 +35640,22 @@ _tmp_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_170_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_169_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -35723,9 +35664,9 @@ _tmp_168_rule(Parser *p) return _res; } -// _tmp_169: ',' bitwise_or +// _tmp_168: ',' bitwise_or static void * -_tmp_169_rule(Parser *p) +_tmp_168_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35741,7 +35682,7 @@ _tmp_169_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); + D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); Token * _literal; expr_ty bitwise_or_var; if ( @@ -35750,12 +35691,12 @@ _tmp_169_rule(Parser *p) (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or ) { - D(fprintf(stderr, "%*c+ _tmp_169[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); + D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); _res = _PyPegen_dummy_name(p, _literal, bitwise_or_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_169[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' bitwise_or")); } _res = NULL; @@ -35764,9 +35705,9 @@ _tmp_169_rule(Parser *p) return _res; } -// _tmp_170: 'as' star_target +// _tmp_169: 'as' star_target static void * -_tmp_170_rule(Parser *p) +_tmp_169_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35782,7 +35723,7 @@ _tmp_170_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -35791,12 +35732,12 @@ _tmp_170_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_169[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_170[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_169[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; From db23b8bb13863fcd88ff91bc22398f8e0312039e Mon Sep 17 00:00:00 2001 From: "Tomas R." Date: Sun, 6 Oct 2024 15:16:41 +0200 Subject: [PATCH 019/247] gh-125008: Fix `tokenize.untokenize` roundtrip for `\n{{` (#125013) --- Lib/test/test_tokenize.py | 20 +++++++++++++++++++ Lib/tokenize.py | 2 +- ...-10-05-23-53-06.gh-issue-125008.ETANpd.rst | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index de0e0b430a21bf..75710db7d05375 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1919,6 +1919,26 @@ def test_roundtrip(self): self.check_roundtrip(r"f'\\\\N{{'") self.check_roundtrip(r"f'\\\\\\N{{'") self.check_roundtrip(r"f'\\\\\\\\N{{'") + + self.check_roundtrip(r"f'\n{{foo}}'") + self.check_roundtrip(r"f'\\n{{foo}}'") + self.check_roundtrip(r"f'\\\n{{foo}}'") + self.check_roundtrip(r"f'\\\\n{{foo}}'") + + self.check_roundtrip(r"f'\t{{foo}}'") + self.check_roundtrip(r"f'\\t{{foo}}'") + self.check_roundtrip(r"f'\\\t{{foo}}'") + self.check_roundtrip(r"f'\\\\t{{foo}}'") + + self.check_roundtrip(r"rf'\t{{foo}}'") + self.check_roundtrip(r"rf'\\t{{foo}}'") + self.check_roundtrip(r"rf'\\\t{{foo}}'") + self.check_roundtrip(r"rf'\\\\t{{foo}}'") + + self.check_roundtrip(r"rf'\{{foo}}'") + self.check_roundtrip(r"f'\\{{foo}}'") + self.check_roundtrip(r"rf'\\\{{foo}}'") + self.check_roundtrip(r"f'\\\\{{foo}}'") cases = [ """ if 1: diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 7f418bb7a1b37f..4b4c3cfe16999b 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -200,7 +200,7 @@ def escape_brackets(self, token): characters[-2::-1] ) ) - if n_backslashes % 2 == 0: + if n_backslashes % 2 == 0 or characters[-1] != "N": characters.append(character) else: consume_until_next_bracket = True diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst new file mode 100644 index 00000000000000..8971e052860225 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst @@ -0,0 +1,2 @@ +Fix :func:`tokenize.untokenize` producing invalid syntax for +double braces preceded by certain escape characters. From 3fc673e97dafb8a73ee99937cf2bf0b849b1f418 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sun, 6 Oct 2024 11:47:13 -0700 Subject: [PATCH 020/247] =?UTF-8?q?gh-119535:=20python=F0=9D=9C=8B=20(#119?= =?UTF-8?q?536)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- Lib/venv/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 028e9483196694..a5cb2bdb064692 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -303,8 +303,11 @@ def setup_python(self, context): copier(context.executable, path) if not os.path.islink(path): os.chmod(path, 0o755) - for suffix in ('python', 'python3', - f'python3.{sys.version_info[1]}'): + + suffixes = ['python', 'python3', f'python3.{sys.version_info[1]}'] + if sys.version_info[:2] == (3, 14): + suffixes.append('python𝜋') + for suffix in suffixes: path = os.path.join(binpath, suffix) if not os.path.exists(path): # Issue 18807: make copies if From a1be83dae311e4a1a6e66ed5e128b1ad8794f72f Mon Sep 17 00:00:00 2001 From: "Tomas R." Date: Sun, 6 Oct 2024 21:46:03 +0200 Subject: [PATCH 021/247] gh-125010: Fix `use-after-free` in AST `repr()` (#125015) --- Lib/test/test_ast/test_ast.py | 7 +++++++ Parser/asdl_c.py | 1 - Python/Python-ast.c | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index f052822cb45273..01d2e392302e86 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -789,6 +789,13 @@ def test_repr(self) -> None: with self.subTest(test_input=test): self.assertEqual(repr(ast.parse(test)), snapshot) + def test_repr_large_input_crash(self): + # gh-125010: Fix use-after-free in ast repr() + source = "0x0" + "e" * 10_000 + with self.assertRaisesRegex(ValueError, + r"Exceeds the limit \(\d+ digits\)"): + repr(ast.Constant(value=eval(source))) + class CopyTests(unittest.TestCase): """Test copying and pickling AST nodes.""" diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index ab5fd229cc46ea..f50c28afcfe205 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1608,7 +1608,6 @@ def visitModule(self, mod): if (!value_repr) { Py_DECREF(name); - Py_DECREF(value); goto error; } diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 4a58c0973d1118..89c52b9dc73cac 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -5809,7 +5809,6 @@ ast_repr_max_depth(AST_object *self, int depth) if (!value_repr) { Py_DECREF(name); - Py_DECREF(value); goto error; } From feca4cf64e9742b9c002d5533ced47e68b34a880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Delfino?= Date: Sun, 6 Oct 2024 19:22:19 -0300 Subject: [PATCH 022/247] Doc: Simplify the definition of 'soft deprecated' (#124988) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Sergey B Kirpichev Co-authored-by: Carol Willing --- Doc/glossary.rst | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index c9d3eba66b07d9..e72a8d002d507d 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1160,16 +1160,12 @@ Glossary (subscript) notation uses :class:`slice` objects internally. soft deprecated - A soft deprecation can be used when using an API which should no longer - be used to write new code, but it remains safe to continue using it in - existing code. The API remains documented and tested, but will not be - developed further (no enhancement). + A soft deprecated API should not be used in new code, + but it is safe for already existing code to use it. + The API remains documented and tested, but will not be enhanced further. - The main difference between a "soft" and a (regular) "hard" deprecation - is that the soft deprecation does not imply scheduling the removal of the - deprecated API. - - Another difference is that a soft deprecation does not issue a warning. + Soft deprecation, unlike normal deprecation, does not plan on removing the API + and will not emit warnings. See `PEP 387: Soft Deprecation `_. From 1e098dc766ba4f29a63da4f188fb214af7623365 Mon Sep 17 00:00:00 2001 From: Jan Kaliszewski Date: Mon, 7 Oct 2024 00:57:03 +0200 Subject: [PATCH 023/247] gh-125025: `_thread` docs: fix/update the *caveats* list (GH-125026) --- Doc/library/_thread.rst | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 81f0cac947f602..5fd604c05380ac 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -213,9 +213,8 @@ In addition to these methods, lock objects can also be used via the .. index:: pair: module; signal -* Threads interact strangely with interrupts: the :exc:`KeyboardInterrupt` - exception will be received by an arbitrary thread. (When the :mod:`signal` - module is available, interrupts always go to the main thread.) +* Interrupts always go to the main thread (the :exc:`KeyboardInterrupt` + exception will be received by that thread.) * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is equivalent to calling :func:`_thread.exit`. @@ -229,7 +228,3 @@ In addition to these methods, lock objects can also be used via the :keyword:`try` ... :keyword:`finally` clauses or executing object destructors. -* When the main thread exits, it does not do any of its usual cleanup (except - that :keyword:`try` ... :keyword:`finally` clauses are honored), and the - standard I/O files are not flushed. - From 31516c98dd7097047ba10da8dcf728c3d580f3d6 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Mon, 7 Oct 2024 05:43:03 +0100 Subject: [PATCH 024/247] GH-109975: Announce final release in What's New in Python 3.13 (#125007) Prepare What's New in Python 3.13 for final release --- Doc/whatsnew/3.12.rst | 2 +- Doc/whatsnew/3.13.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ec110a3952c07c..fb8809feda4ec7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -59,7 +59,7 @@ Summary -- Release highlights .. This section singles out the most important changes in Python 3.12. Brevity is key. -Python 3.12 is the latest stable release of the Python programming language, +Python 3.12 is a stable release of the Python programming language, with a mix of changes to the language and the standard library. The library changes focus on cleaning up deprecated APIs, usability, and correctness. Of note, the :mod:`!distutils` package has been removed from the standard library. diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index e629fc122f1397..a47d5e077a357b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -46,7 +46,7 @@ when researching a change. This article explains the new features in Python 3.13, compared to 3.12. -Python 3.13 will be released on October 7, 2024. +Python 3.13 was released on October 7, 2024. For full details, see the :ref:`changelog `. .. seealso:: @@ -60,7 +60,7 @@ Summary -- Release Highlights .. This section singles out the most important changes in Python 3.13. Brevity is key. -Python 3.13 will be the latest stable release of the Python programming +Python 3.13 is the latest stable release of the Python programming language, with a mix of changes to the language, the implementation and the standard library. The biggest changes include a new `interactive interpreter From f55273b3b7124dc570911724107c2440f37905fc Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 7 Oct 2024 11:46:33 +0100 Subject: [PATCH 025/247] GH-116968: Remove branch from advance_backoff_counter (GH-124469) --- Include/internal/pycore_backoff.h | 46 ++++++++++++++----------------- Python/bytecodes.c | 4 +-- Python/executor_cases.c.h | 4 +-- Python/instrumentation.c | 8 +++--- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/Include/internal/pycore_backoff.h b/Include/internal/pycore_backoff.h index a9d1bce127e63d..20436a68b69677 100644 --- a/Include/internal/pycore_backoff.h +++ b/Include/internal/pycore_backoff.h @@ -15,13 +15,7 @@ extern "C" { typedef struct { - union { - struct { - uint16_t backoff : 4; - uint16_t value : 12; - }; - uint16_t as_counter; // For printf("%#x", ...) - }; + uint16_t value_and_backoff; } _Py_BackoffCounter; @@ -38,17 +32,19 @@ typedef struct { and a 4-bit 'backoff' field. When resetting the counter, the backoff field is incremented (until it reaches a limit) and the value is set to a bit mask representing the value 2**backoff - 1. - The maximum backoff is 12 (the number of value bits). + The maximum backoff is 12 (the number of bits in the value). There is an exceptional value which must not be updated, 0xFFFF. */ -#define UNREACHABLE_BACKOFF 0xFFFF +#define BACKOFF_BITS 4 +#define MAX_BACKOFF 12 +#define UNREACHABLE_BACKOFF 15 static inline bool is_unreachable_backoff_counter(_Py_BackoffCounter counter) { - return counter.as_counter == UNREACHABLE_BACKOFF; + return counter.value_and_backoff == UNREACHABLE_BACKOFF; } static inline _Py_BackoffCounter @@ -57,8 +53,7 @@ make_backoff_counter(uint16_t value, uint16_t backoff) assert(backoff <= 15); assert(value <= 0xFFF); _Py_BackoffCounter result; - result.value = value; - result.backoff = backoff; + result.value_and_backoff = (value << BACKOFF_BITS) | backoff; return result; } @@ -66,7 +61,7 @@ static inline _Py_BackoffCounter forge_backoff_counter(uint16_t counter) { _Py_BackoffCounter result; - result.as_counter = counter; + result.value_and_backoff = counter; return result; } @@ -74,35 +69,36 @@ static inline _Py_BackoffCounter restart_backoff_counter(_Py_BackoffCounter counter) { assert(!is_unreachable_backoff_counter(counter)); - if (counter.backoff < 12) { - return make_backoff_counter((1 << (counter.backoff + 1)) - 1, counter.backoff + 1); + int backoff = counter.value_and_backoff & 15; + if (backoff < MAX_BACKOFF) { + return make_backoff_counter((1 << (backoff + 1)) - 1, backoff + 1); } else { - return make_backoff_counter((1 << 12) - 1, 12); + return make_backoff_counter((1 << MAX_BACKOFF) - 1, MAX_BACKOFF); } } static inline _Py_BackoffCounter pause_backoff_counter(_Py_BackoffCounter counter) { - return make_backoff_counter(counter.value | 1, counter.backoff); + _Py_BackoffCounter result; + result.value_and_backoff = counter.value_and_backoff | (1 << BACKOFF_BITS); + return result; } static inline _Py_BackoffCounter advance_backoff_counter(_Py_BackoffCounter counter) { - if (!is_unreachable_backoff_counter(counter)) { - return make_backoff_counter((counter.value - 1) & 0xFFF, counter.backoff); - } - else { - return counter; - } + _Py_BackoffCounter result; + result.value_and_backoff = counter.value_and_backoff - (1 << BACKOFF_BITS); + return result; } static inline bool backoff_counter_triggers(_Py_BackoffCounter counter) { - return counter.value == 0; + /* Test whether the value is zero and the backoff is not UNREACHABLE_BACKOFF */ + return counter.value_and_backoff < UNREACHABLE_BACKOFF; } /* Initial JUMP_BACKWARD counter. @@ -136,7 +132,7 @@ initial_temperature_backoff_counter(void) static inline _Py_BackoffCounter initial_unreachable_backoff_counter(void) { - return forge_backoff_counter(UNREACHABLE_BACKOFF); + return make_backoff_counter(0, UNREACHABLE_BACKOFF); } #ifdef __cplusplus diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c712c772201e10..f251b79e00ebe7 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4705,7 +4705,7 @@ dummy_func( printf("SIDE EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", - exit - current_executor->exits, exit->temperature.as_counter, + exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyCode_CODE(code)), _PyOpcode_OpName[target->op.code]); } @@ -4794,7 +4794,7 @@ dummy_func( printf("DYNAMIC EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", - exit - current_executor->exits, exit->temperature.as_counter, + exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))), _PyOpcode_OpName[target->op.code]); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index fdfec66b73c730..1716d5d8e68827 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5252,7 +5252,7 @@ printf("SIDE EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", - exit - current_executor->exits, exit->temperature.as_counter, + exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyCode_CODE(code)), _PyOpcode_OpName[target->op.code]); } @@ -5390,7 +5390,7 @@ printf("DYNAMIC EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", - exit - current_executor->exits, exit->temperature.as_counter, + exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))), _PyOpcode_OpName[target->op.code]); } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 8fd7c08beac92a..e1e494c31a1120 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -643,8 +643,8 @@ de_instrument(PyCodeObject *code, int i, int event) CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented); FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, deinstrumented); if (_PyOpcode_Caches[deinstrumented]) { - FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.as_counter, - adaptive_counter_warmup().as_counter); + FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.value_and_backoff, + adaptive_counter_warmup().value_and_backoff); } } @@ -719,8 +719,8 @@ instrument(PyCodeObject *code, int i) assert(instrumented); FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, instrumented); if (_PyOpcode_Caches[deopt]) { - FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.as_counter, - adaptive_counter_warmup().as_counter); + FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.value_and_backoff, + adaptive_counter_warmup().value_and_backoff); instr[1].counter = adaptive_counter_warmup(); } } From 7487db4c7af629f0a81b2127a3ee0000a288cefc Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 7 Oct 2024 14:53:02 +0300 Subject: [PATCH 026/247] gh-121249: Support _Complex types in the struct module (#121613) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Peter Bierma Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Victor Stinner --- Doc/library/struct.rst | 19 ++ Lib/ctypes/__init__.py | 2 + Lib/test/test_struct.py | 37 ++- ...-07-10-08-13-34.gh-issue-121249.W9Gd09.rst | 3 + Modules/_struct.c | 289 ++++++++++++++++-- 5 files changed, 321 insertions(+), 29 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 4769affdf1d666..3ea9e5ba071289 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -267,12 +267,26 @@ platform-dependent. | ``P`` | :c:expr:`void \*` | integer | | \(5) | +--------+--------------------------+--------------------+----------------+------------+ +Additionally, if IEC 60559 compatible complex arithmetic (Annex G of the +C11 standard) is supported, the following format characters are available: + ++--------+--------------------------+--------------------+----------------+------------+ +| Format | C Type | Python type | Standard size | Notes | ++========+==========================+====================+================+============+ +| ``E`` | :c:expr:`float complex` | complex | 8 | \(10) | ++--------+--------------------------+--------------------+----------------+------------+ +| ``C`` | :c:expr:`double complex` | complex | 16 | \(10) | ++--------+--------------------------+--------------------+----------------+------------+ + .. versionchanged:: 3.3 Added support for the ``'n'`` and ``'N'`` formats. .. versionchanged:: 3.6 Added support for the ``'e'`` format. +.. versionchanged:: 3.14 + Added support for the ``'E'`` and ``'C'`` formats. + Notes: @@ -349,6 +363,11 @@ Notes: of bytes. As a special case, ``'0s'`` means a single, empty string (while ``'0c'`` means 0 characters). +(10) + For the ``'E'`` and ``'C'`` format characters, the packed representation uses + the IEEE 754 binary32 and binary64 format for components of the complex + number, regardless of the floating-point format used by the platform. + A format character may be preceded by an integral repeat count. For example, the format string ``'4h'`` means exactly the same as ``'hhhh'``. diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index cb3a61287bfe5d..4a368f02d851c5 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -208,8 +208,10 @@ class c_longdouble(_SimpleCData): try: class c_double_complex(_SimpleCData): _type_ = "C" + _check_size(c_double_complex) class c_float_complex(_SimpleCData): _type_ = "E" + _check_size(c_float_complex) class c_longdouble_complex(_SimpleCData): _type_ = "F" except AttributeError: diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index bdbf8800cfd8f6..e3193c7863fbae 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -1,4 +1,5 @@ from collections import abc +from itertools import combinations import array import gc import math @@ -11,12 +12,22 @@ from test import support from test.support import import_helper, suppress_immortalization from test.support.script_helper import assert_python_ok +from test.support.testcase import ComplexesAreIdenticalMixin ISBIGENDIAN = sys.byteorder == "big" integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' byteorders = '', '@', '=', '<', '>', '!' +INF = float('inf') +NAN = float('nan') + +try: + struct.pack('C', 1j) + have_c_complex = True +except struct.error: + have_c_complex = False + def iter_integer_formats(byteorders=byteorders): for code in integer_codes: for byteorder in byteorders: @@ -33,7 +44,7 @@ def bigendian_to_native(value): else: return string_reverse(value) -class StructTest(unittest.TestCase): +class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase): def test_isbigendian(self): self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) @@ -783,6 +794,30 @@ def test_repr(self): s = struct.Struct('=i2H') self.assertEqual(repr(s), f'Struct({s.format!r})') + @unittest.skipUnless(have_c_complex, "requires C11 complex type support") + def test_c_complex_round_trip(self): + values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2, + -3, INF, -INF, NAN], 2)] + for z in values: + for f in ['E', 'C', '>E', '>C', ' // offsetof() /*[clinic input] @@ -80,6 +83,10 @@ typedef struct { char c; int x; } st_int; typedef struct { char c; long x; } st_long; typedef struct { char c; float x; } st_float; typedef struct { char c; double x; } st_double; +#ifdef Py_HAVE_C_COMPLEX +typedef struct { char c; float complex x; } st_float_complex; +typedef struct { char c; double complex x; } st_double_complex; +#endif typedef struct { char c; void *x; } st_void_p; typedef struct { char c; size_t x; } st_size_t; typedef struct { char c; _Bool x; } st_bool; @@ -89,6 +96,10 @@ typedef struct { char c; _Bool x; } st_bool; #define LONG_ALIGN (sizeof(st_long) - sizeof(long)) #define FLOAT_ALIGN (sizeof(st_float) - sizeof(float)) #define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double)) +#ifdef Py_HAVE_C_COMPLEX +# define FLOAT_COMPLEX_ALIGN (sizeof(st_float_complex) - sizeof(float complex)) +# define DOUBLE_COMPLEX_ALIGN (sizeof(st_double_complex) - sizeof(double complex)) +#endif #define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *)) #define SIZE_T_ALIGN (sizeof(st_size_t) - sizeof(size_t)) #define BOOL_ALIGN (sizeof(st_bool) - sizeof(_Bool)) @@ -407,7 +418,7 @@ static PyObject * nu_short(_structmodulestate *state, const char *p, const formatdef *f) { short x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromLong((long)x); } @@ -415,7 +426,7 @@ static PyObject * nu_ushort(_structmodulestate *state, const char *p, const formatdef *f) { unsigned short x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromLong((long)x); } @@ -423,7 +434,7 @@ static PyObject * nu_int(_structmodulestate *state, const char *p, const formatdef *f) { int x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromLong((long)x); } @@ -431,7 +442,7 @@ static PyObject * nu_uint(_structmodulestate *state, const char *p, const formatdef *f) { unsigned int x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromUnsignedLong((unsigned long)x); } @@ -439,7 +450,7 @@ static PyObject * nu_long(_structmodulestate *state, const char *p, const formatdef *f) { long x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromLong(x); } @@ -447,7 +458,7 @@ static PyObject * nu_ulong(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromUnsignedLong(x); } @@ -455,7 +466,7 @@ static PyObject * nu_ssize_t(_structmodulestate *state, const char *p, const formatdef *f) { Py_ssize_t x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromSsize_t(x); } @@ -463,7 +474,7 @@ static PyObject * nu_size_t(_structmodulestate *state, const char *p, const formatdef *f) { size_t x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromSize_t(x); } @@ -471,7 +482,7 @@ static PyObject * nu_longlong(_structmodulestate *state, const char *p, const formatdef *f) { long long x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromLongLong(x); } @@ -479,7 +490,7 @@ static PyObject * nu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long long x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromUnsignedLongLong(x); } @@ -487,7 +498,7 @@ static PyObject * nu_bool(_structmodulestate *state, const char *p, const formatdef *f) { _Bool x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyBool_FromLong(x != 0); } @@ -506,7 +517,7 @@ static PyObject * nu_float(_structmodulestate *state, const char *p, const formatdef *f) { float x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyFloat_FromDouble((double)x); } @@ -514,15 +525,35 @@ static PyObject * nu_double(_structmodulestate *state, const char *p, const formatdef *f) { double x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyFloat_FromDouble(x); } +#ifdef Py_HAVE_C_COMPLEX +static PyObject * +nu_float_complex(_structmodulestate *state, const char *p, const formatdef *f) +{ + float complex x; + + memcpy(&x, p, sizeof(x)); + return PyComplex_FromDoubles(creal(x), cimag(x)); +} + +static PyObject * +nu_double_complex(_structmodulestate *state, const char *p, const formatdef *f) +{ + double complex x; + + memcpy(&x, p, sizeof(x)); + return PyComplex_FromDoubles(creal(x), cimag(x)); +} +#endif + static PyObject * nu_void_p(_structmodulestate *state, const char *p, const formatdef *f) { void *x; - memcpy((char *)&x, p, sizeof x); + memcpy(&x, p, sizeof x); return PyLong_FromVoidPtr(x); } @@ -587,7 +618,7 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) RANGE_ERROR(state, f, 0); } y = (short)x; - memcpy(p, (char *)&y, sizeof y); + memcpy(p, &y, sizeof y); return 0; } @@ -606,7 +637,7 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) RANGE_ERROR(state, f, 1); } y = (unsigned short)x; - memcpy(p, (char *)&y, sizeof y); + memcpy(p, &y, sizeof y); return 0; } @@ -626,7 +657,7 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) RANGE_ERROR(state, f, 0); #endif y = (int)x; - memcpy(p, (char *)&y, sizeof y); + memcpy(p, &y, sizeof y); return 0; } @@ -646,7 +677,7 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) if (x > ((unsigned long)UINT_MAX)) RANGE_ERROR(state, f, 1); #endif - memcpy(p, (char *)&y, sizeof y); + memcpy(p, &y, sizeof y); return 0; } @@ -660,7 +691,7 @@ np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) } return -1; } - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -674,7 +705,7 @@ np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) } return -1; } - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -688,7 +719,7 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) } return -1; } - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -702,7 +733,7 @@ np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) } return -1; } - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -720,7 +751,7 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) } return -1; } - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -737,7 +768,7 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f } return -1; } - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -751,7 +782,7 @@ np_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) if (y < 0) return -1; x = y; - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -774,7 +805,7 @@ np_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -787,9 +818,61 @@ np_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - memcpy(p, (char *)&x, sizeof(double)); + memcpy(p, &x, sizeof(double)); + return 0; +} + +#ifdef Py_HAVE_C_COMPLEX +static int +np_float_complex(_structmodulestate *state, char *p, PyObject *v, + const formatdef *f) +{ + Py_complex c = PyComplex_AsCComplex(v); + float complex x = CMPLXF((float)c.real, (float)c.imag); + + if (c.real == -1 && PyErr_Occurred()) { + PyErr_SetString(state->StructError, + "required argument is not a complex"); + return -1; + } + memcpy(p, &x, sizeof(x)); + return 0; +} + +static int +np_double_complex(_structmodulestate *state, char *p, PyObject *v, + const formatdef *f) +{ + Py_complex c = PyComplex_AsCComplex(v); + double complex x = CMPLX(c.real, c.imag); + + if (c.real == -1 && PyErr_Occurred()) { + PyErr_SetString(state->StructError, + "required argument is not a complex"); + return -1; + } + memcpy(p, &x, sizeof(x)); return 0; } +#else +static int +np_complex_stub(_structmodulestate *state, char *p, PyObject *v, + const formatdef *f) +{ + PyErr_Format(state->StructError, + "'%c' format not supported on this system", + f->format); + return -1; +} +static PyObject * +nu_complex_stub(_structmodulestate *state, const char *p, const formatdef *f) +{ + PyErr_Format(state->StructError, + "'%c' format not supported on this system", + f->format); + return NULL; +} +#endif static int np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) @@ -804,7 +887,7 @@ np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_DECREF(v); if (x == NULL && PyErr_Occurred()) return -1; - memcpy(p, (char *)&x, sizeof x); + memcpy(p, &x, sizeof x); return 0; } @@ -829,6 +912,13 @@ static const formatdef native_table[] = { {'e', sizeof(short), SHORT_ALIGN, nu_halffloat, np_halffloat}, {'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float}, {'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double}, +#ifdef Py_HAVE_C_COMPLEX + {'E', sizeof(float complex), FLOAT_COMPLEX_ALIGN, nu_float_complex, np_float_complex}, + {'C', sizeof(double complex), DOUBLE_COMPLEX_ALIGN, nu_double_complex, np_double_complex}, +#else + {'E', 1, 0, nu_complex_stub, np_complex_stub}, + {'C', 1, 0, nu_complex_stub, np_complex_stub}, +#endif {'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p}, {0} }; @@ -929,6 +1019,38 @@ bu_double(_structmodulestate *state, const char *p, const formatdef *f) return unpack_double(p, 0); } +#ifdef Py_HAVE_C_COMPLEX +static PyObject * +bu_float_complex(_structmodulestate *state, const char *p, const formatdef *f) +{ + double x = PyFloat_Unpack4(p, 0); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + double y = PyFloat_Unpack4(p + 4, 0); + if (y == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyComplex_FromDoubles(x, y); +} + +static PyObject * +bu_double_complex(_structmodulestate *state, const char *p, const formatdef *f) +{ + double x, y; + + x = PyFloat_Unpack8(p, 0); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + y = PyFloat_Unpack8(p + 8, 0); + if (y == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyComplex_FromDoubles(x, y); +} +#endif + static PyObject * bu_bool(_structmodulestate *state, const char *p, const formatdef *f) { @@ -1068,6 +1190,38 @@ bp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) return PyFloat_Pack8(x, p, 0); } +#ifdef Py_HAVE_C_COMPLEX +static int +bp_float_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) +{ + Py_complex x = PyComplex_AsCComplex(v); + if (x.real == -1 && PyErr_Occurred()) { + PyErr_SetString(state->StructError, + "required argument is not a complex"); + return -1; + } + if (PyFloat_Pack4(x.real, p, 0)) { + return -1; + } + return PyFloat_Pack4(x.imag, p + 4, 0); +} + +static int +bp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) +{ + Py_complex x = PyComplex_AsCComplex(v); + if (x.real == -1 && PyErr_Occurred()) { + PyErr_SetString(state->StructError, + "required argument is not a complex"); + return -1; + } + if (PyFloat_Pack8(x.real, p, 0)) { + return -1; + } + return PyFloat_Pack8(x.imag, p + 8, 0); +} +#endif + static int bp_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { @@ -1098,6 +1252,13 @@ static formatdef bigendian_table[] = { {'e', 2, 0, bu_halffloat, bp_halffloat}, {'f', 4, 0, bu_float, bp_float}, {'d', 8, 0, bu_double, bp_double}, +#ifdef Py_HAVE_C_COMPLEX + {'E', 8, 0, bu_float_complex, bp_float_complex}, + {'C', 16, 0, bu_double_complex, bp_double_complex}, +#else + {'E', 1, 0, nu_complex_stub, np_complex_stub}, + {'C', 1, 0, nu_complex_stub, np_complex_stub}, +#endif {0} }; @@ -1197,6 +1358,38 @@ lu_double(_structmodulestate *state, const char *p, const formatdef *f) return unpack_double(p, 1); } +#ifdef Py_HAVE_C_COMPLEX +static PyObject * +lu_float_complex(_structmodulestate *state, const char *p, const formatdef *f) +{ + double x = PyFloat_Unpack4(p, 1); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + double y = PyFloat_Unpack4(p + 4, 1); + if (y == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyComplex_FromDoubles(x, y); +} + +static PyObject * +lu_double_complex(_structmodulestate *state, const char *p, const formatdef *f) +{ + double x, y; + + x = PyFloat_Unpack8(p, 1); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + y = PyFloat_Unpack8(p + 8, 1); + if (y == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyComplex_FromDoubles(x, y); +} +#endif + static int lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { @@ -1330,6 +1523,39 @@ lp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) return PyFloat_Pack8(x, p, 1); } +#ifdef Py_HAVE_C_COMPLEX +static int +lp_float_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) +{ + Py_complex x = PyComplex_AsCComplex(v); + if (x.real == -1 && PyErr_Occurred()) { + PyErr_SetString(state->StructError, + "required argument is not a complex"); + return -1; + } + if (PyFloat_Pack4(x.real, p, 1)) { + return -1; + } + return PyFloat_Pack4(x.imag, p + 4, 1); + +} + +static int +lp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) +{ + Py_complex x = PyComplex_AsCComplex(v); + if (x.real == -1 && PyErr_Occurred()) { + PyErr_SetString(state->StructError, + "required argument is not a complex"); + return -1; + } + if (PyFloat_Pack8(x.real, p, 1)) { + return -1; + } + return PyFloat_Pack8(x.imag, p + 8, 1); +} +#endif + static formatdef lilendian_table[] = { {'x', 1, 0, NULL}, {'b', 1, 0, nu_byte, np_byte}, @@ -1350,6 +1576,13 @@ static formatdef lilendian_table[] = { {'e', 2, 0, lu_halffloat, lp_halffloat}, {'f', 4, 0, lu_float, lp_float}, {'d', 8, 0, lu_double, lp_double}, +#ifdef Py_HAVE_C_COMPLEX + {'E', 8, 0, lu_float_complex, lp_float_complex}, + {'C', 16, 0, lu_double_complex, lp_double_complex}, +#else + {'E', 1, 0, nu_complex_stub, np_complex_stub}, + {'C', 1, 0, nu_complex_stub, np_complex_stub}, +#endif {0} }; From d8f707420b3b0975567e0d9cab60c978d6cb7111 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 7 Oct 2024 15:27:36 +0200 Subject: [PATCH 027/247] gh-111178: Fix function signatures in fileio.c (#125043) * Add "fileio_" prefix to getter functions. * Small refactoring. --- Modules/_io/fileio.c | 88 +++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 8dae465fd20f8b..d9597f860b9429 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -86,6 +86,7 @@ typedef struct { } fileio; #define PyFileIO_Check(state, op) (PyObject_TypeCheck((op), state->PyFileIO_Type)) +#define _PyFileIO_CAST(op) _Py_CAST(fileio*, (op)) /* Forward declarations */ static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error); @@ -93,15 +94,16 @@ static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool int _PyFileIO_closed(PyObject *self) { - return ((fileio *)self)->fd < 0; + return (_PyFileIO_CAST(self)->fd < 0); } /* Because this can call arbitrary code, it shouldn't be called when the refcount is 0 (that is, not directly from tp_dealloc unless the refcount has been temporarily re-incremented). */ static PyObject * -fileio_dealloc_warn(fileio *self, PyObject *source) +fileio_dealloc_warn(PyObject *op, PyObject *source) { + fileio *self = _PyFileIO_CAST(op); if (self->fd >= 0 && self->closefd) { PyObject *exc = PyErr_GetRaisedException(); if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) { @@ -171,7 +173,7 @@ _io_FileIO_close_impl(fileio *self, PyTypeObject *cls) exc = PyErr_GetRaisedException(); } if (self->finalizing) { - PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); + PyObject *r = fileio_dealloc_warn((PyObject*)self, (PyObject *) self); if (r) { Py_DECREF(r); } @@ -192,23 +194,22 @@ _io_FileIO_close_impl(fileio *self, PyTypeObject *cls) static PyObject * fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - fileio *self; - assert(type != NULL && type->tp_alloc != NULL); - self = (fileio *) type->tp_alloc(type, 0); - if (self != NULL) { - self->fd = -1; - self->created = 0; - self->readable = 0; - self->writable = 0; - self->appending = 0; - self->seekable = -1; - self->stat_atopen = NULL; - self->closefd = 1; - self->weakreflist = NULL; + fileio *self = (fileio *) type->tp_alloc(type, 0); + if (self == NULL) { + return NULL; } + self->fd = -1; + self->created = 0; + self->readable = 0; + self->writable = 0; + self->appending = 0; + self->seekable = -1; + self->stat_atopen = NULL; + self->closefd = 1; + self->weakreflist = NULL; return (PyObject *) self; } @@ -539,36 +540,43 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, } static int -fileio_traverse(fileio *self, visitproc visit, void *arg) +fileio_traverse(PyObject *op, visitproc visit, void *arg) { + fileio *self = _PyFileIO_CAST(op); Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } static int -fileio_clear(fileio *self) +fileio_clear(PyObject *op) { + fileio *self = _PyFileIO_CAST(op); Py_CLEAR(self->dict); return 0; } static void -fileio_dealloc(fileio *self) +fileio_dealloc(PyObject *op) { - PyTypeObject *tp = Py_TYPE(self); + fileio *self = _PyFileIO_CAST(op); self->finalizing = 1; - if (_PyIOBase_finalize((PyObject *) self) < 0) + if (_PyIOBase_finalize(op) < 0) { return; + } + _PyObject_GC_UNTRACK(self); if (self->stat_atopen != NULL) { PyMem_Free(self->stat_atopen); self->stat_atopen = NULL; } - if (self->weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) self); - (void)fileio_clear(self); - tp->tp_free((PyObject *)self); + if (self->weakreflist != NULL) { + PyObject_ClearWeakRefs(op); + } + (void)fileio_clear(op); + + PyTypeObject *tp = Py_TYPE(op); + tp->tp_free(op); Py_DECREF(tp); } @@ -1151,18 +1159,20 @@ mode_string(fileio *self) } static PyObject * -fileio_repr(fileio *self) +fileio_repr(PyObject *op) { - PyObject *nameobj, *res; - const char *type_name = Py_TYPE((PyObject *) self)->tp_name; + fileio *self = _PyFileIO_CAST(op); + const char *type_name = Py_TYPE(self)->tp_name; if (self->fd < 0) { return PyUnicode_FromFormat("<%.100s [closed]>", type_name); } + PyObject *nameobj; if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { return NULL; } + PyObject *res; if (nameobj == NULL) { res = PyUnicode_FromFormat( "<%.100s fd=%d mode='%s' closefd=%s>", @@ -1224,7 +1234,7 @@ static PyMethodDef fileio_methods[] = { _IO_FILEIO_WRITABLE_METHODDEF _IO_FILEIO_FILENO_METHODDEF _IO_FILEIO_ISATTY_METHODDEF - {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, + {"_dealloc_warn", fileio_dealloc_warn, METH_O, NULL}, {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS}, {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O}, {NULL, NULL} /* sentinel */ @@ -1233,26 +1243,30 @@ static PyMethodDef fileio_methods[] = { /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */ static PyObject * -get_closed(fileio *self, void *closure) +fileio_get_closed(PyObject *op, void *closure) { + fileio *self = _PyFileIO_CAST(op); return PyBool_FromLong((long)(self->fd < 0)); } static PyObject * -get_closefd(fileio *self, void *closure) +fileio_get_closefd(PyObject *op, void *closure) { + fileio *self = _PyFileIO_CAST(op); return PyBool_FromLong((long)(self->closefd)); } static PyObject * -get_mode(fileio *self, void *closure) +fileio_get_mode(PyObject *op, void *closure) { + fileio *self = _PyFileIO_CAST(op); return PyUnicode_FromString(mode_string(self)); } static PyObject * -get_blksize(fileio *self, void *closure) +fileio_get_blksize(PyObject *op, void *closure) { + fileio *self = _PyFileIO_CAST(op); #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE if (self->stat_atopen != NULL && self->stat_atopen->st_blksize > 1) { return PyLong_FromLong(self->stat_atopen->st_blksize); @@ -1262,11 +1276,11 @@ get_blksize(fileio *self, void *closure) } static PyGetSetDef fileio_getsetlist[] = { - {"closed", (getter)get_closed, NULL, "True if the file is closed"}, - {"closefd", (getter)get_closefd, NULL, + {"closed", fileio_get_closed, NULL, "True if the file is closed"}, + {"closefd", fileio_get_closefd, NULL, "True if the file descriptor will be closed by close()."}, - {"mode", (getter)get_mode, NULL, "String giving the file mode"}, - {"_blksize", (getter)get_blksize, NULL, "Stat st_blksize if available"}, + {"mode", fileio_get_mode, NULL, "String giving the file mode"}, + {"_blksize", fileio_get_blksize, NULL, "Stat st_blksize if available"}, {NULL}, }; From cda3b5a576412a8671bbe4c68bb792ec14f1a4b1 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 7 Oct 2024 23:44:18 +1000 Subject: [PATCH 028/247] gh-125018: Add importlib.metadata semantic link targets (#125027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows direct intersphinx references to APIs via references like `` :func:`importlib.metadata.version` ``. --------- Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/importlib.metadata.rst | 188 ++++++++++++++---- ...-10-07-00-31-17.gh-issue-125018.yKnymn.rst | 4 + 2 files changed, 148 insertions(+), 44 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 66ba621084c898..ddb72784694fd9 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -100,6 +100,13 @@ You can also get a :ref:`distribution's version number `, list its :ref:`requirements`. +.. exception:: PackageNotFoundError + + Subclass of :class:`ModuleNotFoundError` raised by several functions in this + module when queried for a distribution package which is not installed in the + current Python environment. + + Functional API ============== @@ -111,31 +118,53 @@ This package provides the following functionality via its public API. Entry points ------------ -The ``entry_points()`` function returns a collection of entry points. -Entry points are represented by ``EntryPoint`` instances; -each ``EntryPoint`` has a ``.name``, ``.group``, and ``.value`` attributes and -a ``.load()`` method to resolve the value. There are also ``.module``, -``.attr``, and ``.extras`` attributes for getting the components of the -``.value`` attribute. +.. function:: entry_points(**select_params) + + Returns a :class:`EntryPoints` instance describing entry points for the + current environment. Any given keyword parameters are passed to the + :meth:`!~EntryPoints.select` method for comparison to the attributes of + the individual entry point definitions. + + Note: it is not currently possible to query for entry points based on + their :attr:`!EntryPoint.dist` attribute (as different :class:`!Distribution` + instances do not currently compare equal, even if they have the same attributes) + +.. class:: EntryPoints + + Details of a collection of installed entry points. + + Also provides a ``.groups`` attribute that reports all identifed entry + point groups, and a ``.names`` attribute that reports all identified entry + point names. + +.. class:: EntryPoint + + Details of an installed entry point. + + Each :class:`!EntryPoint` instance has ``.name``, ``.group``, and ``.value`` + attributes and a ``.load()`` method to resolve the value. There are also + ``.module``, ``.attr``, and ``.extras`` attributes for getting the + components of the ``.value`` attribute, and ``.dist`` for obtaining + information regarding the distribution package that provides the entry point. Query all entry points:: >>> eps = entry_points() # doctest: +SKIP -The ``entry_points()`` function returns an ``EntryPoints`` object, -a collection of all ``EntryPoint`` objects with ``names`` and ``groups`` +The :func:`!entry_points` function returns a :class:`!EntryPoints` object, +a collection of all :class:`!EntryPoint` objects with ``names`` and ``groups`` attributes for convenience:: >>> sorted(eps.groups) # doctest: +SKIP ['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation'] -``EntryPoints`` has a ``select`` method to select entry points +:class:`!EntryPoints` has a :meth:`!~EntryPoints.select` method to select entry points matching specific properties. Select entry points in the ``console_scripts`` group:: >>> scripts = eps.select(group='console_scripts') # doctest: +SKIP -Equivalently, since ``entry_points`` passes keyword arguments +Equivalently, since :func:`!entry_points` passes keyword arguments through to select:: >>> scripts = entry_points(group='console_scripts') # doctest: +SKIP @@ -189,31 +218,41 @@ for more information on entry points, their definition, and usage. Distribution metadata --------------------- -Every `Distribution Package `_ includes some metadata, -which you can extract using the -``metadata()`` function:: +.. function:: metadata(distribution_name) + + Return the distribution metadata corresponding to the named + distribution package as a :class:`PackageMetadata` instance. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + +.. class:: PackageMetadata + + A concrete implementation of the + `PackageMetadata protocol `_. + + In addition to providing the defined protocol methods and attributes, subscripting + the instance is equivalent to calling the :meth:`!~PackageMetadata.get` method. + +Every `Distribution Package `_ +includes some metadata, which you can extract using the :func:`!metadata` function:: >>> wheel_metadata = metadata('wheel') # doctest: +SKIP -The keys of the returned data structure, a ``PackageMetadata``, -name the metadata keywords, and +The keys of the returned data structure name the metadata keywords, and the values are returned unparsed from the distribution metadata:: >>> wheel_metadata['Requires-Python'] # doctest: +SKIP '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' -``PackageMetadata`` also presents a ``json`` attribute that returns +:class:`PackageMetadata` also presents a :attr:`!~PackageMetadata.json` attribute that returns all the metadata in a JSON-compatible form per :PEP:`566`:: >>> wheel_metadata.json['requires_python'] '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' -.. note:: - - The actual type of the object returned by ``metadata()`` is an - implementation detail and should be accessed only through the interface - described by the - `PackageMetadata protocol `_. +The full set of available metadata is not described here. +See the PyPA `Core metadata specification `_ for additional details. .. versionchanged:: 3.10 The ``Description`` is now included in the metadata when presented @@ -227,7 +266,15 @@ all the metadata in a JSON-compatible form per :PEP:`566`:: Distribution versions --------------------- -The ``version()`` function is the quickest way to get a +.. function:: version(distribution_name) + + Return the installed distribution package version for the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + +The :func:`!version` function is the quickest way to get a `Distribution Package `_'s version number, as a string:: @@ -240,12 +287,28 @@ number, as a string:: Distribution files ------------------ -You can also get the full set of files contained within a distribution. The -``files()`` function takes a `Distribution Package `_ name -and returns all of the -files installed by this distribution. Each file object returned is a -``PackagePath``, a :class:`pathlib.PurePath` derived object with additional ``dist``, -``size``, and ``hash`` properties as indicated by the metadata. For example:: +.. function:: files(distribution_name) + + Return the full set of files contained within the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + + Returns :const:`None` if the distribution is found but the installation + database records reporting the files associated with the distribuion package + are missing. + +.. class:: PackagePath + + A :class:`pathlib.PurePath` derived object with additional ``dist``, + ``size``, and ``hash`` properties corresponding to the distribution + package's installation metadata for that file. + +The :func:`!files` function takes a +`Distribution Package `_ +name and returns all of the files installed by this distribution. Each file is reported +as a :class:`PackagePath` instance. For example:: >>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP >>> util # doctest: +SKIP @@ -268,16 +331,16 @@ Once you have the file, you can also read its contents:: return s.encode('utf-8') return s -You can also use the ``locate`` method to get a the absolute path to the -file:: +You can also use the :meth:`!~PackagePath.locate` method to get the absolute +path to the file:: >>> util.locate() # doctest: +SKIP PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py') In the case where the metadata file listing files -(RECORD or SOURCES.txt) is missing, ``files()`` will -return ``None``. The caller may wish to wrap calls to -``files()`` in `always_iterable +(``RECORD`` or ``SOURCES.txt``) is missing, :func:`!files` will +return :const:`None`. The caller may wish to wrap calls to +:func:`!files` in `always_iterable `_ or otherwise guard against this condition if the target distribution is not known to have the metadata present. @@ -287,8 +350,16 @@ distribution is not known to have the metadata present. Distribution requirements ------------------------- +.. function:: requires(distribution_name) + + Return the declared dependency specifiers for the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + To get the full set of requirements for a `Distribution Package `_, -use the ``requires()`` +use the :func:`!requires` function:: >>> requires('wheel') # doctest: +SKIP @@ -301,6 +372,16 @@ function:: Mapping import to distribution packages --------------------------------------- +.. function:: packages_distributions() + + Return a mapping from the top level module and import package + names found via :attr:`sys.meta_path` to the names of the distribution + packages (if any) that provide the corresponding files. + + To allow for namespace packages (which may have members provided by + multiple distribution packages), each top level import name maps to a + list of distribution names rather than mapping directly to a single name. + A convenience method to resolve the `Distribution Package `_ name (or names, in the case of a namespace package) that provide each importable top-level @@ -320,23 +401,42 @@ function is not reliable with such installs. Distributions ============= -While the above API is the most common and convenient usage, you can get all -of that information from the ``Distribution`` class. A ``Distribution`` is an -abstract object that represents the metadata for -a Python `Distribution Package `_. You can -get the ``Distribution`` instance:: +.. function:: distribution(distribution_name) + + Return a :class:`Distribution` instance describing the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + +.. class:: Distribution + + Details of an installed distribution package. + + Note: different :class:`!Distribution` instances do not currently compare + equal, even if they relate to the same installed distribution and + accordingly have the same attributes. + +While the module level API described above is the most common and convenient usage, +you can get all of that information from the :class:`!Distribution` class. +:class:`!Distribution` is an abstract object that represents the metadata for +a Python `Distribution Package `_. +You can get the concreate :class:`!Distribution` subclass instance for an installed +distribution package by calling the :func:`distribution` function:: >>> from importlib.metadata import distribution # doctest: +SKIP >>> dist = distribution('wheel') # doctest: +SKIP + >>> type(dist) # doctest: +SKIP + Thus, an alternative way to get the version number is through the -``Distribution`` instance:: +:class:`!Distribution` instance:: >>> dist.version # doctest: +SKIP '0.32.3' -There are all kinds of additional metadata available on the ``Distribution`` -instance:: +There are all kinds of additional metadata available on :class:`!Distribution` +instances:: >>> dist.metadata['Requires-Python'] # doctest: +SKIP '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' @@ -350,7 +450,7 @@ metadata:: 'file:///path/to/wheel-0.32.3.editable-py3-none-any.whl' The full set of available metadata is not described here. -See the `Core metadata specifications `_ for additional details. +See the PyPA `Core metadata specification `_ for additional details. .. versionadded:: 3.13 The ``.origin`` property was added. diff --git a/Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst b/Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst new file mode 100644 index 00000000000000..e910da5b879ba5 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst @@ -0,0 +1,4 @@ +The :mod:`importlib.metadata` documentation now includes semantic +cross-reference targets for the significant documented APIs. This means +intersphinx references like :func:`importlib.metadata.version` will +now work as expected. From da071fa3e8e01e0cacf13d632aae0835a2203eb2 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 7 Oct 2024 14:56:39 +0100 Subject: [PATCH 029/247] GH-119866: Spill the stack around escaping calls. (GH-124392) * Spill the evaluation around escaping calls in the generated interpreter and JIT. * The code generator tracks live, cached values so they can be saved to memory when needed. * Spills the stack pointer around escaping calls, so that the exact stack is visible to the cycle GC. --- Include/internal/pycore_ceval.h | 3 + Include/internal/pycore_opcode_metadata.h | 42 +- Include/internal/pycore_uop_ids.h | 240 +-- Include/internal/pycore_uop_metadata.h | 30 +- Include/opcode_ids.h | 1 - Lib/_opcode_metadata.py | 1 - Lib/test/test_asyncio/test_streams.py | 6 +- Lib/test/test_generated_cases.py | 363 +++- Lib/test/test_monitoring.py | 2 - Python/bytecodes.c | 650 +++--- Python/ceval.c | 18 +- Python/ceval_macros.h | 1 + Python/executor_cases.c.h | 935 ++++++--- Python/generated_cases.c.h | 1960 +++++++++++------- Python/opcode_targets.h | 2 +- Python/optimizer_bytecodes.c | 20 +- Python/optimizer_cases.c.h | 176 +- Tools/cases_generator/analyzer.py | 371 ++-- Tools/cases_generator/cwriter.py | 5 +- Tools/cases_generator/generators_common.py | 385 +++- Tools/cases_generator/lexer.py | 5 +- Tools/cases_generator/optimizer_generator.py | 78 +- Tools/cases_generator/stack.py | 433 +++- Tools/cases_generator/tier1_generator.py | 54 +- Tools/cases_generator/tier2_generator.py | 90 +- 25 files changed, 3839 insertions(+), 2032 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 363845106e40dc..594fbb1c8e443b 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -251,6 +251,7 @@ typedef struct _special_method { } _Py_SpecialMethod; PyAPI_DATA(const _Py_SpecialMethod) _Py_SpecialMethods[]; +PyAPI_DATA(const size_t) _Py_FunctionAttributeOffsets[]; PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right); PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right); @@ -274,6 +275,8 @@ PyAPI_FUNC(PyObject *) _PyEval_GetANext(PyObject *aiter); PyAPI_FUNC(void) _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name, _PyStackRef *writeto); PyAPI_FUNC(PyObject *) _PyEval_GetAwaitable(PyObject *iterable, int oparg); PyAPI_FUNC(PyObject *) _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name); +PyAPI_FUNC(int) +_Py_Check_ArgsIterable(PyThreadState *tstate, PyObject *func, PyObject *args); /* Bits that can be set in PyThreadState.eval_breaker */ #define _PY_GIL_DROP_REQUEST_BIT (1U << 0) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 3344ede5e92c07..a0d3072d2cd5f6 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -483,8 +483,6 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 5; case YIELD_VALUE: return 1; - case _DO_CALL_FUNCTION_EX: - return 3 + (oparg & 1); default: return -1; } @@ -944,8 +942,6 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 6; case YIELD_VALUE: return 1; - case _DO_CALL_FUNCTION_EX: - return 1; default: return -1; } @@ -1022,7 +1018,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, @@ -1030,7 +1026,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, + [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, [BINARY_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, @@ -1079,7 +1075,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [CONTAINS_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP_DICT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP_SET] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, + [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [DELETE_ATTR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1114,8 +1110,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [INSTRUMENTED_CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, - [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, + [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1127,10 +1123,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, + [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, 0 }, [IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, @@ -1140,7 +1136,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, @@ -1148,7 +1144,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1171,7 +1167,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, - [MAKE_FUNCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [MAKE_FUNCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MAP_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_KEYS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1192,13 +1188,13 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG }, [RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, - [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [RETURN_VALUE] = { true, INSTR_FMT_IX, 0 }, - [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [SET_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, + [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [SET_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_ATTR] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG }, @@ -1218,10 +1214,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, [TO_BOOL_BOOL] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, - [TO_BOOL_INT] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [TO_BOOL_INT] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, [TO_BOOL_LIST] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, [TO_BOOL_NONE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, - [TO_BOOL_STR] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [TO_BOOL_STR] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, [UNARY_INVERT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNARY_NOT] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, @@ -1231,8 +1227,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, - [_DO_CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_IF_FALSE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_IF_TRUE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1661,7 +1656,6 @@ const char *_PyOpcode_OpName[266] = { [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [YIELD_VALUE] = "YIELD_VALUE", - [_DO_CALL_FUNCTION_EX] = "_DO_CALL_FUNCTION_EX", }; #endif @@ -1908,12 +1902,12 @@ const uint8_t _PyOpcode_Deopt[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = UNPACK_SEQUENCE, [WITH_EXCEPT_START] = WITH_EXCEPT_START, [YIELD_VALUE] = YIELD_VALUE, - [_DO_CALL_FUNCTION_EX] = _DO_CALL_FUNCTION_EX, }; #endif // NEED_OPCODE_METADATA #define EXTRA_CASES \ + case 116: \ case 117: \ case 118: \ case 119: \ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 927dae88c1fa73..48bafacabcfd1d 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -97,54 +97,55 @@ extern "C" { #define _DICT_MERGE DICT_MERGE #define _DICT_UPDATE DICT_UPDATE #define _DO_CALL 356 -#define _DO_CALL_KW 357 -#define _DYNAMIC_EXIT 358 +#define _DO_CALL_FUNCTION_EX 357 +#define _DO_CALL_KW 358 +#define _DYNAMIC_EXIT 359 #define _END_SEND END_SEND -#define _ERROR_POP_N 359 +#define _ERROR_POP_N 360 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _EXPAND_METHOD 360 -#define _EXPAND_METHOD_KW 361 -#define _FATAL_ERROR 362 +#define _EXPAND_METHOD 361 +#define _EXPAND_METHOD_KW 362 +#define _FATAL_ERROR 363 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 363 -#define _FOR_ITER_GEN_FRAME 364 -#define _FOR_ITER_TIER_TWO 365 +#define _FOR_ITER 364 +#define _FOR_ITER_GEN_FRAME 365 +#define _FOR_ITER_TIER_TWO 366 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER GET_ITER #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BOTH_FLOAT 366 -#define _GUARD_BOTH_INT 367 -#define _GUARD_BOTH_UNICODE 368 -#define _GUARD_BUILTINS_VERSION 369 -#define _GUARD_DORV_NO_DICT 370 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 371 -#define _GUARD_GLOBALS_VERSION 372 -#define _GUARD_IS_FALSE_POP 373 -#define _GUARD_IS_NONE_POP 374 -#define _GUARD_IS_NOT_NONE_POP 375 -#define _GUARD_IS_TRUE_POP 376 -#define _GUARD_KEYS_VERSION 377 -#define _GUARD_NOS_FLOAT 378 -#define _GUARD_NOS_INT 379 -#define _GUARD_NOT_EXHAUSTED_LIST 380 -#define _GUARD_NOT_EXHAUSTED_RANGE 381 -#define _GUARD_NOT_EXHAUSTED_TUPLE 382 -#define _GUARD_TOS_FLOAT 383 -#define _GUARD_TOS_INT 384 -#define _GUARD_TYPE_VERSION 385 +#define _GUARD_BOTH_FLOAT 367 +#define _GUARD_BOTH_INT 368 +#define _GUARD_BOTH_UNICODE 369 +#define _GUARD_BUILTINS_VERSION 370 +#define _GUARD_DORV_NO_DICT 371 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 372 +#define _GUARD_GLOBALS_VERSION 373 +#define _GUARD_IS_FALSE_POP 374 +#define _GUARD_IS_NONE_POP 375 +#define _GUARD_IS_NOT_NONE_POP 376 +#define _GUARD_IS_TRUE_POP 377 +#define _GUARD_KEYS_VERSION 378 +#define _GUARD_NOS_FLOAT 379 +#define _GUARD_NOS_INT 380 +#define _GUARD_NOT_EXHAUSTED_LIST 381 +#define _GUARD_NOT_EXHAUSTED_RANGE 382 +#define _GUARD_NOT_EXHAUSTED_TUPLE 383 +#define _GUARD_TOS_FLOAT 384 +#define _GUARD_TOS_INT 385 +#define _GUARD_TYPE_VERSION 386 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 386 -#define _INIT_CALL_PY_EXACT_ARGS 387 -#define _INIT_CALL_PY_EXACT_ARGS_0 388 -#define _INIT_CALL_PY_EXACT_ARGS_1 389 -#define _INIT_CALL_PY_EXACT_ARGS_2 390 -#define _INIT_CALL_PY_EXACT_ARGS_3 391 -#define _INIT_CALL_PY_EXACT_ARGS_4 392 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 387 +#define _INIT_CALL_PY_EXACT_ARGS 388 +#define _INIT_CALL_PY_EXACT_ARGS_0 389 +#define _INIT_CALL_PY_EXACT_ARGS_1 390 +#define _INIT_CALL_PY_EXACT_ARGS_2 391 +#define _INIT_CALL_PY_EXACT_ARGS_3 392 +#define _INIT_CALL_PY_EXACT_ARGS_4 393 #define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX #define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER @@ -156,131 +157,133 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _INTERNAL_INCREMENT_OPT_COUNTER 393 -#define _IS_NONE 394 +#define _INTERNAL_INCREMENT_OPT_COUNTER 394 +#define _IS_NONE 395 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 395 -#define _ITER_CHECK_RANGE 396 -#define _ITER_CHECK_TUPLE 397 -#define _ITER_JUMP_LIST 398 -#define _ITER_JUMP_RANGE 399 -#define _ITER_JUMP_TUPLE 400 -#define _ITER_NEXT_LIST 401 -#define _ITER_NEXT_RANGE 402 -#define _ITER_NEXT_TUPLE 403 -#define _JUMP_TO_TOP 404 +#define _ITER_CHECK_LIST 396 +#define _ITER_CHECK_RANGE 397 +#define _ITER_CHECK_TUPLE 398 +#define _ITER_JUMP_LIST 399 +#define _ITER_JUMP_RANGE 400 +#define _ITER_JUMP_TUPLE 401 +#define _ITER_NEXT_LIST 402 +#define _ITER_NEXT_RANGE 403 +#define _ITER_NEXT_TUPLE 404 +#define _JUMP_TO_TOP 405 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 405 -#define _LOAD_ATTR_CLASS 406 -#define _LOAD_ATTR_CLASS_0 407 -#define _LOAD_ATTR_CLASS_1 408 +#define _LOAD_ATTR 406 +#define _LOAD_ATTR_CLASS 407 +#define _LOAD_ATTR_CLASS_0 408 +#define _LOAD_ATTR_CLASS_1 409 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 409 -#define _LOAD_ATTR_INSTANCE_VALUE_0 410 -#define _LOAD_ATTR_INSTANCE_VALUE_1 411 -#define _LOAD_ATTR_METHOD_LAZY_DICT 412 -#define _LOAD_ATTR_METHOD_NO_DICT 413 -#define _LOAD_ATTR_METHOD_WITH_VALUES 414 -#define _LOAD_ATTR_MODULE 415 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 416 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 417 -#define _LOAD_ATTR_PROPERTY_FRAME 418 -#define _LOAD_ATTR_SLOT 419 -#define _LOAD_ATTR_SLOT_0 420 -#define _LOAD_ATTR_SLOT_1 421 -#define _LOAD_ATTR_WITH_HINT 422 +#define _LOAD_ATTR_INSTANCE_VALUE 410 +#define _LOAD_ATTR_INSTANCE_VALUE_0 411 +#define _LOAD_ATTR_INSTANCE_VALUE_1 412 +#define _LOAD_ATTR_METHOD_LAZY_DICT 413 +#define _LOAD_ATTR_METHOD_NO_DICT 414 +#define _LOAD_ATTR_METHOD_WITH_VALUES 415 +#define _LOAD_ATTR_MODULE 416 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 417 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 418 +#define _LOAD_ATTR_PROPERTY_FRAME 419 +#define _LOAD_ATTR_SLOT 420 +#define _LOAD_ATTR_SLOT_0 421 +#define _LOAD_ATTR_SLOT_1 422 +#define _LOAD_ATTR_WITH_HINT 423 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 423 -#define _LOAD_CONST_INLINE_BORROW 424 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 425 -#define _LOAD_CONST_INLINE_WITH_NULL 426 +#define _LOAD_CONST_INLINE 424 +#define _LOAD_CONST_INLINE_BORROW 425 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 426 +#define _LOAD_CONST_INLINE_WITH_NULL 427 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 427 -#define _LOAD_FAST_0 428 -#define _LOAD_FAST_1 429 -#define _LOAD_FAST_2 430 -#define _LOAD_FAST_3 431 -#define _LOAD_FAST_4 432 -#define _LOAD_FAST_5 433 -#define _LOAD_FAST_6 434 -#define _LOAD_FAST_7 435 +#define _LOAD_FAST 428 +#define _LOAD_FAST_0 429 +#define _LOAD_FAST_1 430 +#define _LOAD_FAST_2 431 +#define _LOAD_FAST_3 432 +#define _LOAD_FAST_4 433 +#define _LOAD_FAST_5 434 +#define _LOAD_FAST_6 435 +#define _LOAD_FAST_7 436 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 436 -#define _LOAD_GLOBAL_BUILTINS 437 -#define _LOAD_GLOBAL_MODULE 438 +#define _LOAD_GLOBAL 437 +#define _LOAD_GLOBAL_BUILTINS 438 +#define _LOAD_GLOBAL_MODULE 439 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME #define _LOAD_SPECIAL LOAD_SPECIAL #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD +#define _MAKE_CALLARGS_A_TUPLE 440 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 439 +#define _MAKE_WARM 441 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 440 -#define _MONITOR_CALL 441 -#define _MONITOR_JUMP_BACKWARD 442 -#define _MONITOR_RESUME 443 +#define _MAYBE_EXPAND_METHOD 442 +#define _MAYBE_EXPAND_METHOD_KW 443 +#define _MONITOR_CALL 444 +#define _MONITOR_JUMP_BACKWARD 445 +#define _MONITOR_RESUME 446 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_JUMP_IF_FALSE 444 -#define _POP_JUMP_IF_TRUE 445 +#define _POP_JUMP_IF_FALSE 447 +#define _POP_JUMP_IF_TRUE 448 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 446 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 449 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 447 +#define _PUSH_FRAME 450 #define _PUSH_NULL PUSH_NULL -#define _PY_FRAME_GENERAL 448 -#define _PY_FRAME_KW 449 -#define _QUICKEN_RESUME 450 -#define _REPLACE_WITH_TRUE 451 +#define _PY_FRAME_GENERAL 451 +#define _PY_FRAME_KW 452 +#define _QUICKEN_RESUME 453 +#define _REPLACE_WITH_TRUE 454 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 452 -#define _SEND 453 -#define _SEND_GEN_FRAME 454 +#define _SAVE_RETURN_OFFSET 455 +#define _SEND 456 +#define _SEND_GEN_FRAME 457 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 455 -#define _STORE_ATTR 456 -#define _STORE_ATTR_INSTANCE_VALUE 457 -#define _STORE_ATTR_SLOT 458 -#define _STORE_ATTR_WITH_HINT 459 +#define _START_EXECUTOR 458 +#define _STORE_ATTR 459 +#define _STORE_ATTR_INSTANCE_VALUE 460 +#define _STORE_ATTR_SLOT 461 +#define _STORE_ATTR_WITH_HINT 462 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 460 -#define _STORE_FAST_0 461 -#define _STORE_FAST_1 462 -#define _STORE_FAST_2 463 -#define _STORE_FAST_3 464 -#define _STORE_FAST_4 465 -#define _STORE_FAST_5 466 -#define _STORE_FAST_6 467 -#define _STORE_FAST_7 468 +#define _STORE_FAST 463 +#define _STORE_FAST_0 464 +#define _STORE_FAST_1 465 +#define _STORE_FAST_2 466 +#define _STORE_FAST_3 467 +#define _STORE_FAST_4 468 +#define _STORE_FAST_5 469 +#define _STORE_FAST_6 470 +#define _STORE_FAST_7 471 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 469 -#define _STORE_SUBSCR 470 +#define _STORE_SLICE 472 +#define _STORE_SUBSCR 473 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 471 -#define _TO_BOOL 472 +#define _TIER2_RESUME_CHECK 474 +#define _TO_BOOL 475 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT #define _TO_BOOL_LIST TO_BOOL_LIST @@ -290,14 +293,13 @@ extern "C" { #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 473 +#define _UNPACK_SEQUENCE 476 #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define __DO_CALL_FUNCTION_EX _DO_CALL_FUNCTION_EX -#define MAX_UOP_ID 473 +#define MAX_UOP_ID 476 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 07606135d7a356..c68ee594947283 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -54,10 +54,10 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_UNARY_NOT] = HAS_PURE_FLAG, [_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_TO_BOOL_BOOL] = HAS_EXIT_FLAG, - [_TO_BOOL_INT] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG, + [_TO_BOOL_INT] = HAS_EXIT_FLAG, [_TO_BOOL_LIST] = HAS_EXIT_FLAG, [_TO_BOOL_NONE] = HAS_EXIT_FLAG, - [_TO_BOOL_STR] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG, + [_TO_BOOL_STR] = HAS_EXIT_FLAG, [_REPLACE_WITH_TRUE] = 0, [_UNARY_INVERT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_BOTH_INT] = HAS_EXIT_FLAG, @@ -74,7 +74,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, [_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG, [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG, [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -82,7 +82,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_BINARY_SUBSCR_STR_INT] = HAS_DEOPT_FLAG, [_BINARY_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG, [_BINARY_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_BINARY_SUBSCR_CHECK_FUNC] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_BINARY_SUBSCR_CHECK_FUNC] = HAS_DEOPT_FLAG, [_BINARY_SUBSCR_INIT_CALL] = 0, [_LIST_APPEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG, [_SET_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -97,7 +97,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GET_ANEXT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_GET_AWAITABLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_SEND_GEN_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_YIELD_VALUE] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, + [_YIELD_VALUE] = HAS_ARG_FLAG, [_POP_EXCEPT] = HAS_ESCAPES_FLAG, [_LOAD_COMMON_CONSTANT] = HAS_ARG_FLAG, [_LOAD_BUILD_CLASS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -156,7 +156,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_ATTR_CLASS_0] = 0, [_LOAD_ATTR_CLASS_1] = 0, [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG | HAS_OPARG_AND_1_FLAG, - [_LOAD_ATTR_PROPERTY_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_PROPERTY_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_GUARD_DORV_NO_DICT] = HAS_EXIT_FLAG, [_STORE_ATTR_INSTANCE_VALUE] = 0, [_STORE_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, @@ -225,7 +225,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_CALL_STR_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -239,17 +239,19 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_NOARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_MAYBE_EXPAND_METHOD_KW] = HAS_ARG_FLAG, [_PY_FRAME_KW] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CHECK_FUNCTION_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_CHECK_METHOD_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_EXPAND_METHOD_KW] = HAS_ARG_FLAG, [_CHECK_IS_NOT_PY_CALLABLE_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_CALL_KW_NON_PY] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_RETURN_GENERATOR] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_MAKE_CALLARGS_A_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG, + [_RETURN_GENERATOR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BUILD_SLICE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, - [_CONVERT_VALUE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, + [_CONVERT_VALUE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_FORMAT_SIMPLE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_FORMAT_WITH_SPEC] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_COPY] = HAS_ARG_FLAG | HAS_PURE_FLAG, @@ -480,6 +482,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_LOAD_SPECIAL] = "_LOAD_SPECIAL", [_LOAD_SUPER_ATTR_ATTR] = "_LOAD_SUPER_ATTR_ATTR", [_LOAD_SUPER_ATTR_METHOD] = "_LOAD_SUPER_ATTR_METHOD", + [_MAKE_CALLARGS_A_TUPLE] = "_MAKE_CALLARGS_A_TUPLE", [_MAKE_CELL] = "_MAKE_CELL", [_MAKE_FUNCTION] = "_MAKE_FUNCTION", [_MAKE_WARM] = "_MAKE_WARM", @@ -489,6 +492,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_MATCH_MAPPING] = "_MATCH_MAPPING", [_MATCH_SEQUENCE] = "_MATCH_SEQUENCE", [_MAYBE_EXPAND_METHOD] = "_MAYBE_EXPAND_METHOD", + [_MAYBE_EXPAND_METHOD_KW] = "_MAYBE_EXPAND_METHOD_KW", [_NOP] = "_NOP", [_POP_EXCEPT] = "_POP_EXCEPT", [_POP_TOP] = "_POP_TOP", @@ -994,6 +998,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 2 + oparg; case _CALL_METHOD_DESCRIPTOR_FAST: return 2 + oparg; + case _MAYBE_EXPAND_METHOD_KW: + return 3 + oparg; case _PY_FRAME_KW: return 3 + oparg; case _CHECK_FUNCTION_VERSION_KW: @@ -1006,6 +1012,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 3 + oparg; case _CALL_KW_NON_PY: return 3 + oparg; + case _MAKE_CALLARGS_A_TUPLE: + return 3 + (oparg & 1); case _MAKE_FUNCTION: return 1; case _SET_FUNCTION_ATTRIBUTE: diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 8ba1ab25a77770..327bdb792464a0 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -126,7 +126,6 @@ extern "C" { #define UNPACK_EX 113 #define UNPACK_SEQUENCE 114 #define YIELD_VALUE 115 -#define _DO_CALL_FUNCTION_EX 116 #define RESUME 149 #define BINARY_OP_ADD_FLOAT 150 #define BINARY_OP_ADD_INT 151 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index dd70c5250c0b1e..9a793717cf082b 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -315,7 +315,6 @@ 'UNPACK_EX': 113, 'UNPACK_SEQUENCE': 114, 'YIELD_VALUE': 115, - '_DO_CALL_FUNCTION_EX': 116, 'INSTRUMENTED_END_FOR': 236, 'INSTRUMENTED_END_SEND': 237, 'INSTRUMENTED_LOAD_SUPER_ATTR': 238, diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 0688299447d064..dbe5646c2b7c08 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -1214,9 +1214,9 @@ async def main(): # can't use assertRaises because that clears frames exc = excs.exceptions[0] self.assertIsNotNone(exc) - self.assertListEqual(gc.get_referrers(exc), []) - - asyncio.run(main()) + self.assertListEqual(gc.get_referrers(exc), [main_coro]) + main_coro = main() + asyncio.run(main_coro) if __name__ == '__main__': diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 214e53dde64bbf..5b15838f077f3b 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -60,7 +60,7 @@ def test_effect_sizes(self): stack.pop(y) stack.pop(x) for out in outputs: - stack.push(Local.local(out)) + stack.push(Local.undefined(out)) self.assertEqual(stack.base_offset.to_c(), "-1 - oparg - oparg*2") self.assertEqual(stack.top_offset.to_c(), "1 - oparg - oparg*2 + oparg*4") @@ -122,7 +122,7 @@ def run_cases_test(self, input: str, expected: str): def test_inst_no_args(self): input = """ inst(OP, (--)) { - spam(); + SPAM(); } """ output = """ @@ -130,7 +130,7 @@ def test_inst_no_args(self): frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); - spam(); + SPAM(); DISPATCH(); } """ @@ -139,7 +139,8 @@ def test_inst_no_args(self): def test_inst_one_pop(self): input = """ inst(OP, (value --)) { - spam(value); + SPAM(value); + DEAD(value); } """ output = """ @@ -149,7 +150,7 @@ def test_inst_one_pop(self): INSTRUCTION_STATS(OP); _PyStackRef value; value = stack_pointer[-1]; - spam(value); + SPAM(value); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -160,7 +161,7 @@ def test_inst_one_pop(self): def test_inst_one_push(self): input = """ inst(OP, (-- res)) { - res = spam(); + res = SPAM(); } """ output = """ @@ -169,7 +170,7 @@ def test_inst_one_push(self): next_instr += 1; INSTRUCTION_STATS(OP); _PyStackRef res; - res = spam(); + res = SPAM(); stack_pointer[0] = res; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -181,7 +182,8 @@ def test_inst_one_push(self): def test_inst_one_push_one_pop(self): input = """ inst(OP, (value -- res)) { - res = spam(value); + res = SPAM(value); + DEAD(value); } """ output = """ @@ -192,7 +194,7 @@ def test_inst_one_push_one_pop(self): _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; - res = spam(value); + res = SPAM(value); stack_pointer[-1] = res; DISPATCH(); } @@ -202,7 +204,9 @@ def test_inst_one_push_one_pop(self): def test_binary_op(self): input = """ inst(OP, (left, right -- res)) { - res = spam(left, right); + res = SPAM(left, right); + INPUTS_DEAD(); + } """ output = """ @@ -215,7 +219,7 @@ def test_binary_op(self): _PyStackRef res; right = stack_pointer[-1]; left = stack_pointer[-2]; - res = spam(left, right); + res = SPAM(left, right); stack_pointer[-2] = res; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -227,7 +231,8 @@ def test_binary_op(self): def test_overlap(self): input = """ inst(OP, (left, right -- left, result)) { - result = spam(left, right); + result = SPAM(left, right); + INPUTS_DEAD(); } """ output = """ @@ -240,7 +245,7 @@ def test_overlap(self): _PyStackRef result; right = stack_pointer[-1]; left = stack_pointer[-2]; - result = spam(left, right); + result = SPAM(left, right); stack_pointer[-1] = result; DISPATCH(); } @@ -249,7 +254,8 @@ def test_overlap(self): def test_predictions(self): input = """ - inst(OP1, (arg -- rest)) { + inst(OP1, (arg -- res)) { + res = Py_None; } inst(OP3, (arg -- res)) { DEOPT_IF(xxx); @@ -263,7 +269,9 @@ def test_predictions(self): next_instr += 1; INSTRUCTION_STATS(OP1); PREDICTED(OP1); - stack_pointer[-1] = rest; + _PyStackRef res; + res = Py_None; + stack_pointer[-1] = res; DISPATCH(); } @@ -281,6 +289,67 @@ def test_predictions(self): """ self.run_cases_test(input, output) + def test_sync_sp(self): + input = """ + inst(A, (arg -- res)) { + SYNC_SP(); + escaping_call(); + res = Py_None; + } + inst(B, (arg -- res)) { + res = Py_None; + SYNC_SP(); + escaping_call(); + } + """ + output = """ + TARGET(A) { + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(A); + _PyStackRef res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + escaping_call(); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = Py_None; + stack_pointer[0] = res; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(B) { + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(B); + _PyStackRef res; + res = Py_None; + stack_pointer[-1] = res; + _PyFrame_SetStackPointer(frame, stack_pointer); + escaping_call(); + stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + """ + self.run_cases_test(input, output) + + + def test_pep7_condition(self): + input = """ + inst(OP, (arg1 -- out)) { + if (arg1) + out = 0; + else { + out = 1; + } + } + """ + output = "" + with self.assertRaises(SyntaxError): + self.run_cases_test(input, output) + def test_error_if_plain(self): input = """ inst(OP, (--)) { @@ -319,8 +388,10 @@ def test_error_if_plain_with_comment(self): def test_error_if_pop(self): input = """ inst(OP, (left, right -- res)) { - res = spam(left, right); + SPAM(left, right); + INPUTS_DEAD(); ERROR_IF(cond, label); + res = 0; } """ output = """ @@ -333,7 +404,36 @@ def test_error_if_pop(self): _PyStackRef res; right = stack_pointer[-1]; left = stack_pointer[-2]; - res = spam(left, right); + SPAM(left, right); + if (cond) goto pop_2_label; + res = 0; + stack_pointer[-2] = res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + """ + self.run_cases_test(input, output) + + def test_error_if_pop_with_result(self): + input = """ + inst(OP, (left, right -- res)) { + res = SPAM(left, right); + INPUTS_DEAD(); + ERROR_IF(cond, label); + } + """ + output = """ + TARGET(OP) { + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); + _PyStackRef left; + _PyStackRef right; + _PyStackRef res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = SPAM(left, right); if (cond) goto pop_2_label; stack_pointer[-2] = res; stack_pointer += -1; @@ -388,10 +488,12 @@ def test_macro_instruction(self): } op(OP2, (extra/2, arg2, left, right -- res)) { res = op2(arg2, left, right); + INPUTS_DEAD(); } macro(OP) = OP1 + cache/2 + OP2; inst(OP3, (unused/5, arg2, left, right -- res)) { res = op3(arg2, left, right); + INPUTS_DEAD(); } family(OP, INLINE_CACHE_ENTRIES_OP) = { OP3 }; """ @@ -408,20 +510,24 @@ def test_macro_instruction(self): _PyStackRef arg2; _PyStackRef res; // _OP1 - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; + _PyFrame_SetStackPointer(frame, stack_pointer); op1(left, right); + stack_pointer = _PyFrame_GetStackPointer(frame); } /* Skip 2 cache entries */ // OP2 - arg2 = stack_pointer[-3]; { + arg2 = stack_pointer[-3]; uint32_t extra = read_u32(&this_instr[4].cache); (void)extra; + _PyFrame_SetStackPointer(frame, stack_pointer); res = op2(arg2, left, right); + stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer[-3] = res; stack_pointer += -2; @@ -440,7 +546,9 @@ def test_macro_instruction(self): left = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; + _PyFrame_SetStackPointer(frame, stack_pointer); op1(left, right); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH(); } @@ -457,7 +565,9 @@ def test_macro_instruction(self): right = stack_pointer[-1]; left = stack_pointer[-2]; arg2 = stack_pointer[-3]; + _PyFrame_SetStackPointer(frame, stack_pointer); res = op3(arg2, left, right); + stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer[-3] = res; stack_pointer += -2; assert(WITHIN_STACK_BOUNDS()); @@ -469,7 +579,7 @@ def test_macro_instruction(self): def test_unused_caches(self): input = """ inst(OP, (unused/1, unused/2 --)) { - body(); + body; } """ output = """ @@ -479,7 +589,7 @@ def test_unused_caches(self): INSTRUCTION_STATS(OP); /* Skip 1 cache entry */ /* Skip 2 cache entries */ - body(); + body; DISPATCH(); } """ @@ -556,7 +666,7 @@ def test_pseudo_instruction_as_sequence(self): def test_array_input(self): input = """ inst(OP, (below, values[oparg*2], above --)) { - spam(values, oparg); + SPAM(values, oparg); } """ output = """ @@ -566,7 +676,7 @@ def test_array_input(self): INSTRUCTION_STATS(OP); _PyStackRef *values; values = &stack_pointer[-1 - oparg*2]; - spam(values, oparg); + SPAM(values, oparg); stack_pointer += -2 - oparg*2; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -577,7 +687,9 @@ def test_array_input(self): def test_array_output(self): input = """ inst(OP, (unused, unused -- below, values[oparg*3], above)) { - spam(values, oparg); + SPAM(values, oparg); + below = 0; + above = 0; } """ output = """ @@ -585,9 +697,13 @@ def test_array_output(self): frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); + _PyStackRef below; _PyStackRef *values; + _PyStackRef above; values = &stack_pointer[-1]; - spam(values, oparg); + SPAM(values, oparg); + below = 0; + above = 0; stack_pointer[-2] = below; stack_pointer[-1 + oparg*3] = above; stack_pointer += oparg*3; @@ -600,7 +716,8 @@ def test_array_output(self): def test_array_input_output(self): input = """ inst(OP, (values[oparg] -- values[oparg], above)) { - spam(values, oparg); + SPAM(values, oparg); + above = 0; } """ output = """ @@ -609,8 +726,10 @@ def test_array_input_output(self): next_instr += 1; INSTRUCTION_STATS(OP); _PyStackRef *values; + _PyStackRef above; values = &stack_pointer[-oparg]; - spam(values, oparg); + SPAM(values, oparg); + above = 0; stack_pointer[0] = above; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -645,7 +764,10 @@ def test_array_error_if(self): def test_cond_effect(self): input = """ inst(OP, (aa, input if ((oparg & 1) == 1), cc -- xx, output if (oparg & 2), zz)) { - output = spam(oparg, aa, cc, input); + output = SPAM(oparg, aa, cc, input); + INPUTS_DEAD(); + xx = 0; + zz = 0; } """ output = """ @@ -656,11 +778,15 @@ def test_cond_effect(self): _PyStackRef aa; _PyStackRef input = PyStackRef_NULL; _PyStackRef cc; + _PyStackRef xx; _PyStackRef output = PyStackRef_NULL; + _PyStackRef zz; cc = stack_pointer[-1]; if ((oparg & 1) == 1) { input = stack_pointer[-1 - (((oparg & 1) == 1) ? 1 : 0)]; } aa = stack_pointer[-2 - (((oparg & 1) == 1) ? 1 : 0)]; - output = spam(oparg, aa, cc, input); + output = SPAM(oparg, aa, cc, input); + xx = 0; + zz = 0; stack_pointer[-2 - (((oparg & 1) == 1) ? 1 : 0)] = xx; if (oparg & 2) stack_pointer[-1 - (((oparg & 1) == 1) ? 1 : 0)] = output; stack_pointer[-1 - (((oparg & 1) == 1) ? 1 : 0) + ((oparg & 2) ? 1 : 0)] = zz; @@ -674,11 +800,14 @@ def test_cond_effect(self): def test_macro_cond_effect(self): input = """ op(A, (left, middle, right --)) { - use(left, middle, right); + USE(left, middle, right); + INPUTS_DEAD(); } op(B, (-- deep, extra if (oparg), res)) { + deep = -1; res = 0; extra = 1; + INPUTS_DEAD(); } macro(M) = A + B; """ @@ -690,17 +819,19 @@ def test_macro_cond_effect(self): _PyStackRef left; _PyStackRef middle; _PyStackRef right; + _PyStackRef deep; _PyStackRef extra = PyStackRef_NULL; _PyStackRef res; // A - right = stack_pointer[-1]; - middle = stack_pointer[-2]; - left = stack_pointer[-3]; { - use(left, middle, right); + right = stack_pointer[-1]; + middle = stack_pointer[-2]; + left = stack_pointer[-3]; + USE(left, middle, right); } // B { + deep = -1; res = 0; extra = 1; } @@ -717,10 +848,10 @@ def test_macro_cond_effect(self): def test_macro_push_push(self): input = """ op(A, (-- val1)) { - val1 = spam(); + val1 = SPAM(); } op(B, (-- val2)) { - val2 = spam(); + val2 = SPAM(); } macro(M) = A + B; """ @@ -733,11 +864,11 @@ def test_macro_push_push(self): _PyStackRef val2; // A { - val1 = spam(); + val1 = SPAM(); } // B { - val2 = spam(); + val2 = SPAM(); } stack_pointer[0] = val1; stack_pointer[1] = val2; @@ -751,10 +882,10 @@ def test_macro_push_push(self): def test_override_inst(self): input = """ inst(OP, (--)) { - spam(); + spam; } override inst(OP, (--)) { - ham(); + ham; } """ output = """ @@ -762,7 +893,7 @@ def test_override_inst(self): frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); - ham(); + ham; DISPATCH(); } """ @@ -771,11 +902,11 @@ def test_override_inst(self): def test_override_op(self): input = """ op(OP, (--)) { - spam(); + spam; } macro(M) = OP; override op(OP, (--)) { - ham(); + ham; } """ output = """ @@ -783,7 +914,7 @@ def test_override_op(self): frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(M); - ham(); + ham; DISPATCH(); } """ @@ -792,7 +923,7 @@ def test_override_op(self): def test_annotated_inst(self): input = """ pure inst(OP, (--)) { - ham(); + ham; } """ output = """ @@ -800,7 +931,7 @@ def test_annotated_inst(self): frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); - ham(); + ham; DISPATCH(); } """ @@ -809,7 +940,7 @@ def test_annotated_inst(self): def test_annotated_op(self): input = """ pure op(OP, (--)) { - spam(); + SPAM(); } macro(M) = OP; """ @@ -818,7 +949,7 @@ def test_annotated_op(self): frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(M); - spam(); + SPAM(); DISPATCH(); } """ @@ -826,7 +957,7 @@ def test_annotated_op(self): input = """ pure register specializing op(OP, (--)) { - spam(); + SPAM(); } macro(M) = OP; """ @@ -840,7 +971,7 @@ def test_deopt_and_exit(self): } """ output = "" - with self.assertRaises(Exception): + with self.assertRaises(SyntaxError): self.run_cases_test(input, output) def test_array_of_one(self): @@ -868,6 +999,7 @@ def test_pointer_to_stackref(self): input = """ inst(OP, (arg: _PyStackRef * -- out)) { out = *arg; + DEAD(arg); } """ output = """ @@ -922,14 +1054,14 @@ def test_unused_named_values(self): def test_used_unused_used(self): input = """ op(FIRST, (w -- w)) { - use(w); + USE(w); } op(SECOND, (x -- x)) { } op(THIRD, (y -- y)) { - use(y); + USE(y); } macro(TEST) = FIRST + SECOND + THIRD; @@ -942,17 +1074,17 @@ def test_used_unused_used(self): _PyStackRef w; _PyStackRef y; // FIRST - w = stack_pointer[-1]; { - use(w); + w = stack_pointer[-1]; + USE(w); } // SECOND { } // THIRD - y = w; { - use(y); + y = w; + USE(y); } DISPATCH(); } @@ -965,11 +1097,11 @@ def test_unused_used_used(self): } op(SECOND, (x -- x)) { - use(x); + USE(x); } op(THIRD, (y -- y)) { - use(y); + USE(y); } macro(TEST) = FIRST + SECOND + THIRD; @@ -985,14 +1117,14 @@ def test_unused_used_used(self): { } // SECOND - x = stack_pointer[-1]; { - use(x); + x = stack_pointer[-1]; + USE(x); } // THIRD - y = x; { - use(y); + y = x; + USE(y); } DISPATCH(); } @@ -1007,7 +1139,8 @@ def test_flush(self): } op(SECOND, (a, b -- )) { - use(a, b); + USE(a, b); + INPUTS_DEAD(); } macro(TEST) = FIRST + flush + SECOND; @@ -1030,10 +1163,8 @@ def test_flush(self): stack_pointer += 2; assert(WITHIN_STACK_BOUNDS()); // SECOND - b = stack_pointer[-1]; - a = stack_pointer[-2]; { - use(a, b); + USE(a, b); } stack_pointer += -2; assert(WITHIN_STACK_BOUNDS()); @@ -1047,14 +1178,16 @@ def test_pop_on_error_peeks(self): input = """ op(FIRST, (x, y -- a, b)) { a = x; + DEAD(x); b = y; + DEAD(y); } op(SECOND, (a, b -- a, b)) { } op(THIRD, (j, k --)) { - j,k; // Mark j and k as used + INPUTS_DEAD(); // Mark j and k as used ERROR_IF(cond, error); } @@ -1069,12 +1202,10 @@ def test_pop_on_error_peeks(self): _PyStackRef y; _PyStackRef a; _PyStackRef b; - _PyStackRef j; - _PyStackRef k; // FIRST - y = stack_pointer[-1]; - x = stack_pointer[-2]; { + y = stack_pointer[-1]; + x = stack_pointer[-2]; a = x; b = y; } @@ -1082,10 +1213,8 @@ def test_pop_on_error_peeks(self): { } // THIRD - k = b; - j = a; { - j,k; // Mark j and k as used + // Mark j and k as used if (cond) goto pop_2_error; } stack_pointer += -2; @@ -1126,7 +1255,8 @@ def test_push_then_error(self): b = 1; if (cond) { stack_pointer[0] = a; - stack_pointer += 1; + stack_pointer[1] = b; + stack_pointer += 2; assert(WITHIN_STACK_BOUNDS()); goto error; } @@ -1178,6 +1308,69 @@ def test_array_size_inconsistency(self): with self.assertRaises(SyntaxError): self.run_cases_test(input, output) + def test_stack_save_reload(self): + + input = """ + inst(BALANCED, ( -- )) { + SAVE_STACK(); + RELOAD_STACK(); + } + """ + + output = """ + TARGET(BALANCED) { + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BALANCED); + _PyFrame_SetStackPointer(frame, stack_pointer); + stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + """ + self.run_cases_test(input, output) + + def test_stack_reload_only(self): + + input = """ + inst(BALANCED, ( -- )) { + RELOAD_STACK(); + } + """ + + output = """ + TARGET(BALANCED) { + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BALANCED); + _PyFrame_SetStackPointer(frame, stack_pointer); + stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + """ + with self.assertRaises(SyntaxError): + self.run_cases_test(input, output) + + def test_stack_save_only(self): + + input = """ + inst(BALANCED, ( -- )) { + SAVE_STACK(); + } + """ + + output = """ + TARGET(BALANCED) { + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BALANCED); + _PyFrame_SetStackPointer(frame, stack_pointer); + stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + """ + with self.assertRaises(SyntaxError): + self.run_cases_test(input, output) + class TestGeneratedAbstractCases(unittest.TestCase): def setUp(self) -> None: @@ -1232,7 +1425,7 @@ def run_cases_test(self, input: str, input2: str, expected: str): def test_overridden_abstract(self): input = """ pure op(OP, (--)) { - spam(); + SPAM(); } """ input2 = """ @@ -1251,22 +1444,23 @@ def test_overridden_abstract(self): def test_overridden_abstract_args(self): input = """ pure op(OP, (arg1 -- out)) { - spam(); + out = SPAM(arg1); } op(OP2, (arg1 -- out)) { - eggs(); + out = EGGS(arg1); } """ input2 = """ op(OP, (arg1 -- out)) { - eggs(); + out = EGGS(arg1); } """ output = """ case OP: { _Py_UopsSymbol *arg1; _Py_UopsSymbol *out; - eggs(); + arg1 = stack_pointer[-1]; + out = EGGS(arg1); stack_pointer[-1] = out; break; } @@ -1283,7 +1477,7 @@ def test_overridden_abstract_args(self): def test_no_overridden_case(self): input = """ pure op(OP, (arg1 -- out)) { - spam(); + out = SPAM(arg1); } pure op(OP2, (arg1 -- out)) { @@ -1292,6 +1486,7 @@ def test_no_overridden_case(self): """ input2 = """ pure op(OP2, (arg1 -- out)) { + out = NULL; } """ output = """ @@ -1303,8 +1498,8 @@ def test_no_overridden_case(self): } case OP2: { - _Py_UopsSymbol *arg1; _Py_UopsSymbol *out; + out = NULL; stack_pointer[-1] = out; break; } @@ -1314,7 +1509,7 @@ def test_no_overridden_case(self): def test_missing_override_failure(self): input = """ pure op(OP, (arg1 -- out)) { - spam(); + SPAM(); } """ input2 = """ diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 2a326684460b99..1b06816214e7d6 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -785,8 +785,6 @@ def get_events(self, func, tool, recorders): def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): events = self.get_events(func, tool, recorders) - if events != expected: - print(events, file = sys.stderr) self.assertEqual(events, expected) def check_balanced(self, func, recorders): diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f251b79e00ebe7..a0edf17d747e77 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -149,7 +149,7 @@ dummy_func( op(_CHECK_PERIODIC, (--)) { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { int err = _Py_HandlePending(tstate); ERROR_IF(err != 0, error); @@ -207,10 +207,8 @@ dummy_func( } op(_MONITOR_RESUME, (--)) { - _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( tstate, oparg > 0, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); ERROR_IF(err, error); if (frame->instr_ptr != this_instr) { /* Instrumentation has jumped */ @@ -263,6 +261,7 @@ dummy_func( replicate(8) inst(STORE_FAST, (value --)) { SETLOCAL(oparg, value); + DEAD(value); } pseudo(STORE_FAST_MAYBE_NULL, (unused --)) = { @@ -273,6 +272,7 @@ dummy_func( uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); + DEAD(value1); value2 = PyStackRef_DUP(GETLOCAL(oparg2)); } @@ -280,7 +280,9 @@ dummy_func( uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); + DEAD(value1); SETLOCAL(oparg2, value2); + DEAD(value2); } pure inst(POP_TOP, (value --)) { @@ -305,12 +307,14 @@ dummy_func( DECREF_INPUTS(); } - pure inst(END_SEND, (receiver, value -- value)) { + pure inst(END_SEND, (receiver, value -- val)) { (void)receiver; + val = value; + DEAD(value); PyStackRef_CLOSE(receiver); } - tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- value)) { + tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) { PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); if (PyGen_Check(receiver_o) || PyCoro_CheckExact(receiver_o)) { int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); @@ -318,6 +322,8 @@ dummy_func( ERROR_NO_POP(); } } + val = value; + DEAD(value); PyStackRef_CLOSE(receiver); } @@ -332,6 +338,7 @@ dummy_func( assert(PyStackRef_BoolCheck(value)); res = PyStackRef_Is(value, PyStackRef_False) ? PyStackRef_True : PyStackRef_False; + DEAD(value); } family(TO_BOOL, INLINE_CACHE_ENTRIES_TO_BOOL) = { @@ -375,6 +382,7 @@ dummy_func( STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value_o)) { assert(_Py_IsImmortalLoose(value_o)); + DEAD(value); res = PyStackRef_False; } else { @@ -394,6 +402,7 @@ dummy_func( inst(TO_BOOL_NONE, (unused/1, unused/2, value -- res)) { // This one is a bit weird, because we expect *some* failures: EXIT_IF(!PyStackRef_Is(value, PyStackRef_None)); + DEAD(value); STAT_INC(TO_BOOL, hit); res = PyStackRef_False; } @@ -404,6 +413,7 @@ dummy_func( STAT_INC(TO_BOOL, hit); if (value_o == &_Py_STR(empty)) { assert(_Py_IsImmortalLoose(value_o)); + DEAD(value); res = PyStackRef_False; } else { @@ -466,6 +476,7 @@ dummy_func( PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -478,6 +489,7 @@ dummy_func( PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -489,7 +501,8 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free);; + _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -528,6 +541,7 @@ dummy_func( ((PyFloatObject *)right_o)->ob_fval; PyObject *res_o; DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -541,6 +555,7 @@ dummy_func( ((PyFloatObject *)right_o)->ob_fval; PyObject *res_o; DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -554,6 +569,7 @@ dummy_func( ((PyFloatObject *)right_o)->ob_fval; PyObject *res_o; DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -580,6 +596,7 @@ dummy_func( PyObject *res_o = PyUnicode_Concat(left_o, right_o); _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -620,10 +637,12 @@ dummy_func( */ assert(Py_REFCNT(left_o) >= 2); _Py_DECREF_NO_DEALLOC(left_o); + DEAD(left); PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); PyUnicode_Append(&temp, right_o); *target_local = PyStackRef_FromPyObjectSteal(temp); _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + DEAD(right); ERROR_IF(PyStackRef_IsNull(*target_local), error); #if TIER_ONE // The STORE_FAST is already done. This is done here in tier one, @@ -645,6 +664,7 @@ dummy_func( }; specializing op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) { + assert(frame->stackpointer == NULL); #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; @@ -736,6 +756,7 @@ dummy_func( assert(res_o != NULL); Py_INCREF(res_o); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(list_st); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -755,6 +776,7 @@ dummy_func( STAT_INC(BINARY_SUBSCR, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(str_st); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -775,6 +797,7 @@ dummy_func( assert(res_o != NULL); Py_INCREF(res_o); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(tuple_st); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -815,9 +838,9 @@ dummy_func( PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; PyObject *getitem = ht->_spec_cache.getitem; new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); - SYNC_SP(); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; + INPUTS_DEAD(); frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR); } @@ -829,8 +852,9 @@ dummy_func( _PUSH_FRAME; inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { - ERROR_IF(_PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), - PyStackRef_AsPyObjectSteal(v)) < 0, error); + int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), + PyStackRef_AsPyObjectSteal(v)); + ERROR_IF(err < 0, error); } inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { @@ -885,6 +909,7 @@ dummy_func( assert(old_value != NULL); Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(list_st); } @@ -928,25 +953,14 @@ dummy_func( } tier1 inst(RAISE_VARARGS, (args[oparg] -- )) { - PyObject *cause = NULL, *exc = NULL; - switch (oparg) { - case 2: - cause = PyStackRef_AsPyObjectSteal(args[1]); - _Py_FALLTHROUGH; - case 1: - exc = PyStackRef_AsPyObjectSteal(args[0]); - _Py_FALLTHROUGH; - case 0: - if (do_raise(tstate, exc, cause)) { - assert(oparg == 0); - monitor_reraise(tstate, frame, this_instr); - goto exception_unwind; - } - break; - default: - _PyErr_SetString(tstate, PyExc_SystemError, - "bad RAISE_VARARGS oparg"); - break; + assert(oparg < 3); + PyObject *cause = oparg == 2 ? PyStackRef_AsPyObjectSteal(args[1]) : NULL; + PyObject *exc = oparg > 0 ? PyStackRef_AsPyObjectSteal(args[0]) : NULL; + int err = do_raise(tstate, exc, cause); + if (err) { + assert(oparg == 0); + monitor_reraise(tstate, frame, this_instr); + goto exception_unwind; } ERROR_IF(true, error); } @@ -969,17 +983,18 @@ dummy_func( #if TIER_ONE assert(frame != &entry_frame); #endif - SYNC_SP(); - _PyFrame_SetStackPointer(frame, stack_pointer); + _PyStackRef temp = retval; + DEAD(retval); + SAVE_STACK(); assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; _PyEval_FrameClearAndPop(tstate, dying); - LOAD_SP(); + RELOAD_STACK(); LOAD_IP(frame->return_offset); - res = retval; + res = temp; LLTRACE_RESUME_FRAME(); } @@ -987,7 +1002,7 @@ dummy_func( int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); - if (err) ERROR_NO_POP(); + ERROR_IF(err, error); } macro(INSTRUMENTED_RETURN_VALUE) = @@ -1111,7 +1126,8 @@ dummy_func( JUMPBY(oparg); } else { - ERROR_NO_POP(); + DECREF_INPUTS(); + ERROR_IF(true, error); } } PyStackRef_CLOSE(v); @@ -1127,6 +1143,7 @@ dummy_func( STAT_INC(SEND, hit); gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, v); + DEAD(v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; @@ -1153,8 +1170,9 @@ dummy_func( assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; - SYNC_SP(); - _PyFrame_SetStackPointer(frame, stack_pointer); + _PyStackRef temp = retval; + DEAD(retval); + SAVE_STACK(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); @@ -1171,19 +1189,19 @@ dummy_func( _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); #endif + RELOAD_STACK(); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - LOAD_SP(); - value = retval; + value = temp; LLTRACE_RESUME_FRAME(); } tier1 op(_YIELD_VALUE_EVENT, (val -- val)) { - SAVE_SP(); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_YIELD, frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); - LOAD_SP(); - if (err) ERROR_NO_POP(); + if (err) { + ERROR_NO_POP(); + } if (frame->instr_ptr != this_instr) { next_instr = frame->instr_ptr; DISPATCH(); @@ -1202,7 +1220,7 @@ dummy_func( } tier1 inst(RERAISE, (values[oparg], exc_st -- values[oparg])) { - PyObject *exc = PyStackRef_AsPyObjectBorrow(exc_st); + PyObject *exc = PyStackRef_AsPyObjectSteal(exc_st); assert(oparg >= 0 && oparg <= 2); if (oparg) { @@ -1213,11 +1231,11 @@ dummy_func( } else { _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); + Py_DECREF(exc); ERROR_NO_POP(); } } assert(exc && PyExceptionInstance_Check(exc)); - Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); monitor_reraise(tstate, frame, this_instr); goto exception_unwind; @@ -1227,7 +1245,8 @@ dummy_func( PyObject *exc = PyStackRef_AsPyObjectBorrow(exc_st); assert(exc && PyExceptionInstance_Check(exc)); - if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { + int matches = PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration); + if (matches) { DECREF_INPUTS(); } else { @@ -1245,9 +1264,9 @@ dummy_func( int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); if (matches) { + none = PyStackRef_None; value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value); DECREF_INPUTS(); - none = PyStackRef_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); @@ -1258,21 +1277,22 @@ dummy_func( inst(LOAD_COMMON_CONSTANT, ( -- value)) { // Keep in sync with _common_constants in opcode.py - switch(oparg) { - case CONSTANT_ASSERTIONERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_AssertionError); - break; - case CONSTANT_NOTIMPLEMENTEDERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_NotImplementedError); - break; - default: - Py_FatalError("bad LOAD_COMMON_CONSTANT oparg"); + // If we ever have more than two constants, use a lookup table + PyObject *val; + if (oparg == CONSTANT_ASSERTIONERROR) { + val = PyExc_AssertionError; + } + else { + assert(oparg == CONSTANT_NOTIMPLEMENTEDERROR); + val = PyExc_NotImplementedError; } + value = PyStackRef_FromPyObjectImmortal(val); } inst(LOAD_BUILD_CLASS, ( -- bc)) { PyObject *bc_o; - ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o) < 0, error); + int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); + ERROR_IF(err < 0, error); if (bc_o == NULL) { _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); @@ -1291,10 +1311,12 @@ dummy_func( DECREF_INPUTS(); ERROR_IF(true, error); } - if (PyDict_CheckExact(ns)) + if (PyDict_CheckExact(ns)) { err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); - else + } + else { err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + } DECREF_INPUTS(); ERROR_IF(err, error); } @@ -1460,9 +1482,8 @@ dummy_func( PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *v_o; int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &v_o); - if (err < 0) { - ERROR_NO_POP(); - } + DECREF_INPUTS(); + ERROR_IF(err < 0, error); if (v_o == NULL) { if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) @@ -1483,10 +1504,12 @@ dummy_func( else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &v_o) < 0, error); + int err = PyMapping_GetOptionalItem(GLOBALS(), name, &v_o); + ERROR_IF(err < 0, error); if (v_o == NULL) { /* namespace 2: builtins */ - ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0, error); + int err = PyMapping_GetOptionalItem(BUILTINS(), name, &v_o); + ERROR_IF(err < 0, error); if (v_o == NULL) { _PyEval_FormatExcCheckArg( tstate, PyExc_NameError, @@ -1496,7 +1519,6 @@ dummy_func( } } } - DECREF_INPUTS(); v = PyStackRef_FromPyObjectSteal(v_o); } @@ -1691,12 +1713,14 @@ dummy_func( inst(BUILD_TUPLE, (values[oparg] -- tup)) { PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); + INPUTS_DEAD(); ERROR_IF(tup_o == NULL, error); tup = PyStackRef_FromPyObjectSteal(tup_o); } inst(BUILD_LIST, (values[oparg] -- list)) { PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); + INPUTS_DEAD(); ERROR_IF(list_o == NULL, error); list = PyStackRef_FromPyObjectSteal(list_o); } @@ -1743,6 +1767,7 @@ dummy_func( } PyStackRef_CLOSE(values[i]); } + DEAD(values); if (err != 0) { Py_DECREF(set_o); ERROR_IF(true, error); @@ -1767,7 +1792,6 @@ dummy_func( } inst(SETUP_ANNOTATIONS, (--)) { - int err; PyObject *ann_dict; if (LOCALS() == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -1775,7 +1799,8 @@ dummy_func( ERROR_IF(true, error); } /* check if __annotations__ in locals()... */ - ERROR_IF(PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict) < 0, error); + int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); + ERROR_IF(err < 0, error); if (ann_dict == NULL) { ann_dict = PyDict_New(); ERROR_IF(ann_dict == NULL, error); @@ -1869,7 +1894,10 @@ dummy_func( int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, global_super, arg); - ERROR_IF(err, error); + if (err) { + DECREF_INPUTS(); + ERROR_IF(true, error); + } } // we make no attempt to optimize here; specializations should // handle any case whose performance we care about @@ -1940,6 +1968,7 @@ dummy_func( } if (method_found) { self_or_null = self_st; // transfer ownership + DEAD(self_st); } else { PyStackRef_CLOSE(self_st); self_or_null = PyStackRef_NULL; @@ -1991,6 +2020,7 @@ dummy_func( */ assert(attr_o != NULL); // No errors on this branch self_or_null = owner; // Transfer ownership + DEAD(owner); } else { /* meth is not an unbound method (but a regular attr, or @@ -2009,6 +2039,8 @@ dummy_func( attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); DECREF_INPUTS(); ERROR_IF(attr_o == NULL, error); + /* We need to define self_or_null on all paths */ + self_or_null = PyStackRef_NULL; } attr = PyStackRef_FromPyObjectSteal(attr_o); } @@ -2172,6 +2204,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame); new_frame->localsplus[0] = owner; + DEAD(owner); } macro(LOAD_ATTR_PROPERTY) = @@ -2206,6 +2239,7 @@ dummy_func( // Manipulate stack directly because we exit with DISPATCH_INLINED(). STACK_SHRINK(1); new_frame->localsplus[0] = owner; + DEAD(owner); new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name); frame->return_offset = (uint16_t)(next_instr - this_instr); DISPATCH_INLINED(new_frame); @@ -2351,7 +2385,9 @@ dummy_func( // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left_o, _PyFloat_ExactDealloc); + DEAD(left); _Py_DECREF_SPECIALIZED(right_o, _PyFloat_ExactDealloc); + DEAD(right); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. } @@ -2371,7 +2407,9 @@ dummy_func( // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + DEAD(left); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); + DEAD(right); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. } @@ -2385,7 +2423,9 @@ dummy_func( int eq = _PyUnicode_Equal(left_o, right_o); assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); + DEAD(left); _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + DEAD(right); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); @@ -2607,6 +2647,7 @@ dummy_func( replaced op(_POP_JUMP_IF_FALSE, (cond -- )) { assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_Is(cond, PyStackRef_False); + DEAD(cond); #if ENABLE_SPECIALIZATION this_instr[1].cache = (this_instr[1].cache << 1) | flag; #endif @@ -2616,6 +2657,7 @@ dummy_func( replaced op(_POP_JUMP_IF_TRUE, (cond -- )) { assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_Is(cond, PyStackRef_True); + DEAD(cond); #if ENABLE_SPECIALIZATION this_instr[1].cache = (this_instr[1].cache << 1) | flag; #endif @@ -2625,6 +2667,7 @@ dummy_func( op(_IS_NONE, (value -- b)) { if (PyStackRef_Is(value, PyStackRef_None)) { b = PyStackRef_True; + DEAD(value); } else { b = PyStackRef_False; @@ -2716,13 +2759,16 @@ dummy_func( ERROR_NO_POP(); } iter = iterable; + DEAD(iterable); } else if (PyGen_CheckExact(iterable_o)) { iter = iterable; + DEAD(iterable); } else { /* `iterable` is not a generator. */ iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); + DEAD(iterable); if (PyStackRef_IsNull(iter)) { ERROR_NO_POP(); } @@ -2760,7 +2806,6 @@ dummy_func( PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); if (next_o == NULL) { - next = PyStackRef_NULL; if (_PyErr_Occurred(tstate)) { int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); if (!matches) { @@ -3076,7 +3121,7 @@ dummy_func( NOP, }; - inst(PUSH_EXC_INFO, (new_exc -- prev_exc, new_exc)) { + inst(PUSH_EXC_INFO, (exc -- prev_exc, new_exc)) { _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { @@ -3085,8 +3130,10 @@ dummy_func( else { prev_exc = PyStackRef_None; } - assert(PyStackRef_ExceptionInstanceCheck(new_exc)); - exc_info->exc_value = PyStackRef_AsPyObjectNew(new_exc); + assert(PyStackRef_ExceptionInstanceCheck(exc)); + exc_info->exc_value = PyStackRef_AsPyObjectNew(exc); + new_exc = exc; + DEAD(exc); } op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) { @@ -3109,6 +3156,7 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; + DEAD(owner); } macro(LOAD_ATTR_METHOD_WITH_VALUES) = @@ -3126,6 +3174,7 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; + DEAD(owner); } macro(LOAD_ATTR_METHOD_NO_DICT) = @@ -3178,6 +3227,7 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; + DEAD(owner); } macro(LOAD_ATTR_METHOD_LAZY_DICT) = @@ -3212,11 +3262,11 @@ dummy_func( CALL_NON_PY_GENERAL, }; - specializing op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null[1], args[oparg] -- callable, self_or_null[1], args[oparg])) { + specializing op(_SPECIALIZE_CALL, (counter/1, callable[1], self_or_null[1], args[oparg] -- callable[1], self_or_null[1], args[oparg])) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; - _Py_Specialize_Call(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + _Py_Specialize_Call(callable[0], next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CALL); @@ -3224,23 +3274,21 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ } - op(_MAYBE_EXPAND_METHOD, (callable, self_or_null[1], args[oparg] -- func, maybe_self[1], args[oparg])) { - if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_MAYBE_EXPAND_METHOD, (callable[1], self_or_null[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) { + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *self = ((PyMethodObject *)callable_o)->im_self; maybe_self[0] = PyStackRef_FromPyObjectNew(self); PyObject *method = ((PyMethodObject *)callable_o)->im_func; - func = PyStackRef_FromPyObjectNew(method); - PyStackRef_CLOSE(callable); - } - else { - func = callable; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); } } // When calling Python, inline the call using DISPATCH_INLINED(). - op(_DO_CALL, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_DO_CALL, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; @@ -3256,11 +3304,11 @@ dummy_func( int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, total_args, NULL, frame ); // Manipulate stack directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 2); + SYNC_SP(); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { @@ -3272,10 +3320,11 @@ dummy_func( /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(true, error); } PyObject *res_o = PyObject_Vectorcall( @@ -3301,17 +3350,18 @@ dummy_func( } } assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } - op(_MONITOR_CALL, (func, maybe_self[1], args[oparg] -- func, maybe_self[1], args[oparg])) { + op(_MONITOR_CALL, (func[1], maybe_self[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) { int is_meth = !PyStackRef_IsNull(maybe_self[0]); - PyObject *function = PyStackRef_AsPyObjectBorrow(func); + PyObject *function = PyStackRef_AsPyObjectBorrow(func[0]); PyObject *arg0; if (is_meth) { arg0 = PyStackRef_AsPyObjectBorrow(maybe_self[0]); @@ -3322,6 +3372,7 @@ dummy_func( else { arg0 = &_PyInstrumentation_MISSING; } + SYNC_SP(); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, function, arg0 @@ -3332,8 +3383,8 @@ dummy_func( macro(CALL) = _SPECIALIZE_CALL + unused/2 + _MAYBE_EXPAND_METHOD + _DO_CALL + _CHECK_PERIODIC; macro(INSTRUMENTED_CALL) = unused/3 + _MAYBE_EXPAND_METHOD + _MONITOR_CALL + _DO_CALL + _CHECK_PERIODIC; - op(_PY_FRAME_GENERAL, (callable, self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_PY_FRAME_GENERAL, (callable[1], self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; @@ -3344,20 +3395,21 @@ dummy_func( assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, args, total_args, NULL, frame ); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. + // The frame has stolen all the arguments from the stack. + INPUTS_DEAD(); SYNC_SP(); - if (new_frame == NULL) { + if (temp == NULL) { ERROR_NO_POP(); } + new_frame = temp; } - op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null[1], unused[oparg] -- callable, self_or_null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_FUNCTION_VERSION, (func_version/2, callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(!PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; EXIT_IF(func->func_version != func_version); @@ -3371,8 +3423,8 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - op(_CHECK_METHOD_VERSION, (func_version/2, callable, null[1], unused[oparg] -- callable, null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_METHOD_VERSION, (func_version/2, callable[1], null[1], unused[oparg] -- callable[1], null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(Py_TYPE(callable_o) != &PyMethod_Type); PyObject *func = ((PyMethodObject *)callable_o)->im_func; @@ -3381,15 +3433,16 @@ dummy_func( EXIT_IF(!PyStackRef_IsNull(null[0])); } - op(_EXPAND_METHOD, (callable, null[1], unused[oparg] -- method, self[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - + op(_EXPAND_METHOD, (callable[1], null[1], unused[oparg] -- method[1], self[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyStackRef_IsNull(null[0])); + DEAD(null); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(temp); } macro(CALL_BOUND_METHOD_GENERAL) = @@ -3402,17 +3455,17 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - op(_CHECK_IS_NOT_PY_CALLABLE, (callable, unused[1], unused[oparg] -- callable, unused[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_IS_NOT_PY_CALLABLE, (callable[1], unused[1], unused[oparg] -- callable[1], unused[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(PyFunction_Check(callable_o)); EXIT_IF(Py_TYPE(callable_o) == &PyMethod_Type); } - op(_CALL_NON_PY_GENERAL, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_NON_PY_GENERAL, (callable[1], self_or_null[1], args[oparg] -- res)) { #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3431,10 +3484,11 @@ dummy_func( NULL); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3446,59 +3500,64 @@ dummy_func( _CALL_NON_PY_GENERAL + _CHECK_PERIODIC; - op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null[1], unused[oparg] -- callable, null[1], unused[oparg])) { + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], null[1], unused[oparg] -- callable[1], null[1], unused[oparg])) { EXIT_IF(!PyStackRef_IsNull(null[0])); - EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable)) != &PyMethod_Type); + EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type); } - op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null[1], unused[oparg] -- func, self[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], null[1], unused[oparg] -- func[1], self[1], unused[oparg])) { + DEAD(null); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); STAT_INC(CALL, hit); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - func = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + PyStackRef_CLOSE(temp); } op(_CHECK_PEP_523, (--)) { DEOPT_IF(tstate->interp->eval_frame); } - op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null[1], unused[oparg] -- callable, self_or_null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_FUNCTION_EXACT_ARGS, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; EXIT_IF(code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0]))); } - op(_CHECK_STACK_SPACE, (callable, self_or_null[1], unused[oparg] -- callable, self_or_null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_STACK_SPACE, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize)); DEOPT_IF(tstate->py_recursion_remaining <= 1); } - replicate(5) pure op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { + replicate(5) pure op(_INIT_CALL_PY_EXACT_ARGS, (callable[1], self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { first_non_self_local[i] = args[i]; } + INPUTS_DEAD(); } op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- )) { // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; + DEAD(new_frame); SYNC_SP(); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -3534,7 +3593,9 @@ dummy_func( assert(oparg == 1); DEOPT_IF(!PyStackRef_IsNull(null)); + DEAD(null); DEOPT_IF(callable_o != (PyObject *)&PyType_Type); + DEAD(callable); STAT_INC(CALL, hit); res = PyStackRef_FromPyObjectSteal(Py_NewRef(Py_TYPE(arg_o))); PyStackRef_CLOSE(arg); @@ -3549,6 +3610,8 @@ dummy_func( DEOPT_IF(callable_o != (PyObject *)&PyUnicode_Type); STAT_INC(CALL, hit); res = PyStackRef_FromPyObjectSteal(PyObject_Str(arg_o)); + DEAD(null); + DEAD(callable); PyStackRef_CLOSE(arg); ERROR_IF(PyStackRef_IsNull(res), error); } @@ -3568,6 +3631,8 @@ dummy_func( DEOPT_IF(callable_o != (PyObject *)&PyTuple_Type); STAT_INC(CALL, hit); res = PyStackRef_FromPyObjectSteal(PySequence_Tuple(arg_o)); + DEAD(null); + DEAD(callable); PyStackRef_CLOSE(arg); ERROR_IF(PyStackRef_IsNull(res), error); } @@ -3578,9 +3643,9 @@ dummy_func( _CALL_TUPLE_1 + _CHECK_PERIODIC; - op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, null, args[oparg] -- self, init, args[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - DEOPT_IF(!PyStackRef_IsNull(null)); + op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable[1], null[1], args[oparg] -- init[1], self[1], args[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + DEOPT_IF(!PyStackRef_IsNull(null[0])); DEOPT_IF(!PyType_Check(callable_o)); PyTypeObject *tp = (PyTypeObject *)callable_o; DEOPT_IF(tp->tp_version_tag != type_version); @@ -3590,23 +3655,26 @@ dummy_func( PyCodeObject *code = (PyCodeObject *)init_func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)); STAT_INC(CALL, hit); - self = PyStackRef_FromPyObjectSteal(_PyType_NewManagedObject(tp)); - if (PyStackRef_IsNull(self)) { + PyObject *self_o = _PyType_NewManagedObject(tp); + if (self_o == NULL) { ERROR_NO_POP(); } - PyStackRef_CLOSE(callable); - init = PyStackRef_FromPyObjectNew(init_func); + self[0] = PyStackRef_FromPyObjectSteal(self_o); + _PyStackRef temp = callable[0]; + init[0] = PyStackRef_FromPyObjectNew(init_func); + PyStackRef_CLOSE(temp); } - op(_CREATE_INIT_FRAME, (self, init, args[oparg] -- init_frame: _PyInterpreterFrame *)) { + op(_CREATE_INIT_FRAME, (init[1], self[1], args[oparg] -- init_frame: _PyInterpreterFrame *)) { _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK); /* Push self onto stack of shim */ - shim->localsplus[0] = PyStackRef_DUP(self); - args[-1] = self; + shim->localsplus[0] = PyStackRef_DUP(self[0]); + DEAD(init); + DEAD(self); init_frame = _PyEvalFramePushAndInit( - tstate, init, NULL, args-1, oparg+1, NULL, shim); + tstate, init[0], NULL, args-1, oparg+1, NULL, shim); SYNC_SP(); if (init_frame == NULL) { _PyEval_FrameClearAndPop(tstate, shim); @@ -3634,16 +3702,18 @@ dummy_func( Py_TYPE(PyStackRef_AsPyObjectBorrow(should_be_none))->tp_name); ERROR_NO_POP(); } + DEAD(should_be_none); } - op(_CALL_BUILTIN_CLASS, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_BUILTIN_CLASS, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; total_args++; } + DEAD(self_or_null); DEOPT_IF(!PyType_Check(callable_o)); PyTypeObject *tp = (PyTypeObject *)callable_o; DEOPT_IF(tp->tp_vectorcall == NULL); @@ -3659,7 +3729,7 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3670,9 +3740,9 @@ dummy_func( _CALL_BUILTIN_CLASS + _CHECK_PERIODIC; - op(_CALL_BUILTIN_O, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_BUILTIN_O, (callable[1], self_or_null[1], args[oparg] -- res)) { /* Builtin METH_O functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3693,7 +3763,9 @@ dummy_func( assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(arg); - PyStackRef_CLOSE(callable); + DEAD(args); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3704,15 +3776,16 @@ dummy_func( _CALL_BUILTIN_O + _CHECK_PERIODIC; - op(_CALL_BUILTIN_FAST, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_BUILTIN_FAST, (callable[1], self_or_null[1], args[oparg] -- res)) { /* Builtin METH_FASTCALL functions, without keywords */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; total_args++; } + DEAD(self_or_null); DEOPT_IF(!PyCFunction_CheckExact(callable_o)); DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL); STAT_INC(CALL, hit); @@ -3734,7 +3807,7 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3745,9 +3818,9 @@ dummy_func( _CALL_BUILTIN_FAST + _CHECK_PERIODIC; - op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable[1], self_or_null[1], args[oparg] -- res)) { /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3776,7 +3849,8 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3787,9 +3861,9 @@ dummy_func( _CALL_BUILTIN_FAST_WITH_KEYWORDS + _CHECK_PERIODIC; - inst(CALL_LEN, (unused/1, unused/2, callable, self_or_null[1], args[oparg] -- res)) { + inst(CALL_LEN, (unused/1, unused/2, callable[1], self_or_null[1], args[oparg] -- res)) { /* len(o) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3811,14 +3885,14 @@ dummy_func( if (res_o == NULL) { GOTO_ERROR(error); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(arg_stackref); res = PyStackRef_FromPyObjectSteal(res_o); } - inst(CALL_ISINSTANCE, (unused/1, unused/2, callable, self_or_null[1], args[oparg] -- res)) { + inst(CALL_ISINSTANCE, (unused/1, unused/2, callable[1], self_or_null[1], args[oparg] -- res)) { /* isinstance(o, o2) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3839,7 +3913,7 @@ dummy_func( assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(inst_stackref); PyStackRef_CLOSE(cls_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); } // This is secretly a super-instruction @@ -3865,8 +3939,8 @@ dummy_func( #endif } - op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_METHOD_DESCRIPTOR_O, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3895,7 +3969,9 @@ dummy_func( assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); PyStackRef_CLOSE(arg_stackref); - PyStackRef_CLOSE(callable); + DEAD(args); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3906,8 +3982,8 @@ dummy_func( _CALL_METHOD_DESCRIPTOR_O + _CHECK_PERIODIC; - op(_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3923,14 +3999,14 @@ dummy_func( EXIT_IF(!Py_IS_TYPE(self, d_type)); STAT_INC(CALL, hit); int nargs = total_args - 1; - PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { DECREF_INPUTS(); ERROR_IF(true, error); } + PyCFunctionFastWithKeywords cfunc = + (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -3939,7 +4015,8 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3950,9 +4027,9 @@ dummy_func( _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS + _CHECK_PERIODIC; - op(_CALL_METHOD_DESCRIPTOR_NOARGS, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_METHOD_DESCRIPTOR_NOARGS, (callable[1], self_or_null[1], args[oparg] -- res)) { assert(oparg == 0 || oparg == 1); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3976,7 +4053,9 @@ dummy_func( _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); - PyStackRef_CLOSE(callable); + DEAD(args); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3987,8 +4066,8 @@ dummy_func( _CALL_METHOD_DESCRIPTOR_NOARGS + _CHECK_PERIODIC; - op(_CALL_METHOD_DESCRIPTOR_FAST, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_METHOD_DESCRIPTOR_FAST, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -4003,8 +4082,6 @@ dummy_func( PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); EXIT_IF(!Py_IS_TYPE(self, method->d_common.d_type)); STAT_INC(CALL, hit); - PyCFunctionFast cfunc = - (PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); @@ -4012,6 +4089,8 @@ dummy_func( DECREF_INPUTS(); ERROR_IF(true, error); } + PyCFunctionFast cfunc = + (PyCFunctionFast)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -4020,7 +4099,8 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4052,8 +4132,22 @@ dummy_func( GO_TO_INSTRUCTION(CALL_KW); } - op(_DO_CALL_KW, (callable, self_or_null[1], args[oparg], kwnames -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- func[1], maybe_self[1], args[oparg], kwnames_out)) { + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; + maybe_self[0] = PyStackRef_FromPyObjectNew(self); + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); + } + kwnames_out = kwnames_in; + DEAD(kwnames_in); + } + + op(_DO_CALL_KW, (callable[1], self_or_null[1], args[oparg], kwnames -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); // oparg counts all of the args, but *not* self: @@ -4062,17 +4156,6 @@ dummy_func( args--; total_args++; } - else if (Py_TYPE(callable_o) == &PyMethod_Type) { - args--; - total_args++; - PyObject *self = ((PyMethodObject *)callable_o)->im_self; - args[0] = PyStackRef_FromPyObjectNew(self); - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - args[-1] = PyStackRef_FromPyObjectNew(method); - PyStackRef_CLOSE(callable); - callable_o = method; - callable = args[-1]; - } int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); // Check if the call can be inlined or not if (Py_TYPE(callable_o) == &PyFunction_Type && @@ -4082,12 +4165,12 @@ dummy_func( int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); PyStackRef_CLOSE(kwnames); - // Manipulate stack directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 3); + // Sync stack explicitly since we leave using DISPATCH_INLINED(). + SYNC_SP(); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { @@ -4127,16 +4210,17 @@ dummy_func( } PyStackRef_CLOSE(kwnames); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } - op(_PY_FRAME_KW, (callable, self_or_null[1], args[oparg], kwnames -- new_frame: _PyInterpreterFrame*)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_PY_FRAME_KW, (callable[1], self_or_null[1], args[oparg], kwnames -- new_frame: _PyInterpreterFrame*)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; @@ -4150,7 +4234,7 @@ dummy_func( int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); PyStackRef_CLOSE(kwnames); @@ -4162,8 +4246,8 @@ dummy_func( } } - op(_CHECK_FUNCTION_VERSION_KW, (func_version/2, callable, self_or_null[1], unused[oparg], kwnames -- callable, self_or_null[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_FUNCTION_VERSION_KW, (func_version/2, callable[1], self_or_null[1], unused[oparg], kwnames -- callable[1], self_or_null[1], unused[oparg], kwnames)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(!PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; EXIT_IF(func->func_version != func_version); @@ -4177,8 +4261,8 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - op(_CHECK_METHOD_VERSION_KW, (func_version/2, callable, null[1], unused[oparg], kwnames -- callable, null[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_METHOD_VERSION_KW, (func_version/2, callable[1], null[1], unused[oparg], kwnames -- callable[1], null[1], unused[oparg], kwnames)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(Py_TYPE(callable_o) != &PyMethod_Type); PyObject *func = ((PyMethodObject *)callable_o)->im_func; @@ -4187,15 +4271,16 @@ dummy_func( EXIT_IF(!PyStackRef_IsNull(null[0])); } - op(_EXPAND_METHOD_KW, (callable, null[1], unused[oparg], kwnames -- method, self[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_EXPAND_METHOD_KW, (callable[1], null[1], unused[oparg], unused -- method[1], self[1], unused[oparg], unused)) { + _PyStackRef callable_s = callable[0]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); assert(PyStackRef_IsNull(null[0])); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(callable_s); } macro(CALL_KW_BOUND_METHOD) = @@ -4208,11 +4293,11 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - specializing op(_SPECIALIZE_CALL_KW, (counter/1, callable, self_or_null[1], args[oparg], kwnames -- callable, self_or_null[1], args[oparg], kwnames)) { + specializing op(_SPECIALIZE_CALL_KW, (counter/1, callable[1], self_or_null[1], args[oparg], kwnames -- callable[1], self_or_null[1], args[oparg], kwnames)) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; - _Py_Specialize_CallKw(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + _Py_Specialize_CallKw(callable[0], next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CALL_KW); @@ -4223,20 +4308,21 @@ dummy_func( macro(CALL_KW) = _SPECIALIZE_CALL_KW + unused/2 + + _MAYBE_EXPAND_METHOD_KW + _DO_CALL_KW; - op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable, unused[1], unused[oparg], kwnames -- callable, unused[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable[1], unused[1], unused[oparg], kwnames -- callable[1], unused[1], unused[oparg], kwnames)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(PyFunction_Check(callable_o)); EXIT_IF(Py_TYPE(callable_o) == &PyMethod_Type); } - op(_CALL_KW_NON_PY, (callable, self_or_null[1], args[oparg], kwnames -- res)) { + op(_CALL_KW_NON_PY, (callable[1], self_or_null[1], args[oparg], kwnames -- res)) { #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -4258,10 +4344,11 @@ dummy_func( PyStackRef_CLOSE(kwnames); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4277,7 +4364,29 @@ dummy_func( GO_TO_INSTRUCTION(CALL_FUNCTION_EX); } - inst(_DO_CALL_FUNCTION_EX, (func_st, unused, callargs_st, kwargs_st if (oparg & 1) -- result)) { + op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in if (oparg & 1) -- func, unused, tuple, kwargs_out if (oparg & 1))) { + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; + DEAD(callargs); + } + else { + int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); + if (err < 0) { + ERROR_NO_POP(); + } + PyObject *tuple_o = PySequence_Tuple(callargs_o); + if (tuple_o == NULL) { + ERROR_NO_POP(); + } + PyStackRef_CLOSE(callargs); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); + } + kwargs_out = kwargs_in; + DEAD(kwargs_in); + } + + op(_DO_CALL_FUNCTION_EX, (func_st, unused, callargs_st, kwargs_st if (oparg & 1) -- result)) { PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); @@ -4285,32 +4394,23 @@ dummy_func( // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - if (!PyTuple_CheckExact(callargs)) { - int err = check_args_iterable(tstate, func, callargs); - if (err < 0) { - ERROR_NO_POP(); - } - PyObject *tuple = PySequence_Tuple(callargs); - if (tuple == NULL) { - ERROR_NO_POP(); - } - PyStackRef_CLOSE(callargs_st); - callargs_st = PyStackRef_FromPyObjectSteal(tuple); - callargs = tuple; - } assert(PyTuple_CheckExact(callargs)); EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + PyObject *result_o; + assert(!_PyErr_Occurred(tstate)); if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, func, arg); - if (err) ERROR_NO_POP(); - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); + if (err) { + ERROR_NO_POP(); + } + result_o = PyObject_Call(func, callargs, kwargs); if (!PyFunction_Check(func) && !PyMethod_Check(func)) { - if (PyStackRef_IsNull(result)) { + if (result_o == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, this_instr, func, arg); @@ -4320,7 +4420,7 @@ dummy_func( tstate, PY_MONITORING_EVENT_C_RETURN, frame, this_instr, func, arg); if (err < 0) { - PyStackRef_CLEAR(result); + Py_CLEAR(result_o); } } } @@ -4337,8 +4437,9 @@ dummy_func( _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( tstate, func_st, locals, nargs, callargs, kwargs, frame); - // Need to manually shrink the stack since we exit with DISPATCH_INLINED. - STACK_SHRINK(oparg + 3); + // Need to sync the stack since we exit with DISPATCH_INLINED. + INPUTS_DEAD(); + SYNC_SP(); if (new_frame == NULL) { ERROR_NO_POP(); } @@ -4346,14 +4447,18 @@ dummy_func( frame->return_offset = 1; DISPATCH_INLINED(new_frame); } - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); + result_o = PyObject_Call(func, callargs, kwargs); } - DECREF_INPUTS(); - assert(PyStackRef_AsPyObjectBorrow(PEEK(2 + (oparg & 1))) == NULL); - ERROR_IF(PyStackRef_IsNull(result), error); + PyStackRef_XCLOSE(kwargs_st); + DEAD(kwargs_st); + PyStackRef_CLOSE(callargs_st); + PyStackRef_CLOSE(func_st); + ERROR_IF(result_o == NULL, error); + result = PyStackRef_FromPyObjectSteal(result_o); } macro(CALL_FUNCTION_EX) = + _MAKE_CALLARGS_A_TUPLE + _DO_CALL_FUNCTION_EX + _CHECK_PERIODIC; @@ -4365,59 +4470,33 @@ dummy_func( PyFunction_New(codeobj, GLOBALS()); PyStackRef_CLOSE(codeobj_st); - if (func_obj == NULL) { - ERROR_NO_POP(); - } + ERROR_IF(func_obj == NULL, error); _PyFunction_SetVersion( func_obj, ((PyCodeObject *)codeobj)->co_version); func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); } - inst(SET_FUNCTION_ATTRIBUTE, (attr_st, func_st -- func_st)) { - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); - PyObject *attr = PyStackRef_AsPyObjectBorrow(attr_st); - + inst(SET_FUNCTION_ATTRIBUTE, (attr_st, func_in -- func_out)) { + PyObject *func = PyStackRef_AsPyObjectBorrow(func_in); + PyObject *attr = PyStackRef_AsPyObjectSteal(attr_st); + func_out = func_in; + DEAD(func_in); assert(PyFunction_Check(func)); - PyFunctionObject *func_obj = (PyFunctionObject *)func; - switch(oparg) { - case MAKE_FUNCTION_CLOSURE: - assert(func_obj->func_closure == NULL); - func_obj->func_closure = attr; - break; - case MAKE_FUNCTION_ANNOTATIONS: - assert(func_obj->func_annotations == NULL); - func_obj->func_annotations = attr; - break; - case MAKE_FUNCTION_KWDEFAULTS: - assert(PyDict_CheckExact(attr)); - assert(func_obj->func_kwdefaults == NULL); - func_obj->func_kwdefaults = attr; - break; - case MAKE_FUNCTION_DEFAULTS: - assert(PyTuple_CheckExact(attr)); - assert(func_obj->func_defaults == NULL); - func_obj->func_defaults = attr; - break; - case MAKE_FUNCTION_ANNOTATE: - assert(PyCallable_Check(attr)); - assert(func_obj->func_annotate == NULL); - func_obj->func_annotate = attr; - break; - default: - Py_UNREACHABLE(); - } + size_t offset = _Py_FunctionAttributeOffsets[oparg]; + assert(offset != 0); + PyObject **ptr = (PyObject **)(((char *)func) + offset); + assert(*ptr == NULL); + *ptr = attr; } inst(RETURN_GENERATOR, (-- res)) { assert(PyStackRef_FunctionCheck(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - if (gen == NULL) { - ERROR_NO_POP(); - } + ERROR_IF(gen == NULL, error); assert(EMPTY()); - _PyFrame_SetStackPointer(frame, stack_pointer); + SAVE_STACK(); _PyInterpreterFrame *gen_frame = &gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); @@ -4425,12 +4504,12 @@ dummy_func( gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); - res = PyStackRef_FromPyObjectSteal((PyObject *)gen); _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); - LOAD_SP(); + RELOAD_STACK(); + res = PyStackRef_FromPyObjectSteal((PyObject *)gen); LLTRACE_RESUME_FRAME(); } @@ -4466,6 +4545,7 @@ dummy_func( } else { res = value; + DEAD(value); } } @@ -4509,8 +4589,12 @@ dummy_func( macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + _BINARY_OP; - pure inst(SWAP, (bottom, unused[oparg-2], top -- - top, unused[oparg-2], bottom)) { + pure inst(SWAP, (bottom_in, unused[oparg-2], top_in -- + top_out, unused[oparg-2], bottom_out)) { + bottom_out = bottom_in; + DEAD(bottom_in); + top_out = top_in; + DEAD(top_in); assert(oparg >= 2); } @@ -4521,10 +4605,8 @@ dummy_func( original_opcode = code->_co_monitoring->lines[(int)(this_instr - _PyCode_CODE(code))].original_opcode; next_instr = this_instr; } else { - _PyFrame_SetStackPointer(frame, stack_pointer); original_opcode = _Py_call_instrumentation_line( tstate, frame, this_instr, prev_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); if (original_opcode < 0) { next_instr = this_instr+1; goto error; @@ -4647,29 +4729,34 @@ dummy_func( ///////// Tier-2 only opcodes ///////// op (_GUARD_IS_TRUE_POP, (flag -- )) { + int is_true = PyStackRef_Is(flag, PyStackRef_True); + DEAD(flag); SYNC_SP(); - EXIT_IF(!PyStackRef_Is(flag, PyStackRef_True)); - assert(PyStackRef_Is(flag, PyStackRef_True)); + EXIT_IF(!is_true); } op (_GUARD_IS_FALSE_POP, (flag -- )) { + int is_false = PyStackRef_Is(flag, PyStackRef_False); + DEAD(flag); SYNC_SP(); - EXIT_IF(!PyStackRef_Is(flag, PyStackRef_False)); - assert(PyStackRef_Is(flag, PyStackRef_False)); + EXIT_IF(!is_false); } op (_GUARD_IS_NONE_POP, (val -- )) { - SYNC_SP(); - if (!PyStackRef_Is(val, PyStackRef_None)) { + int is_none = PyStackRef_Is(val, PyStackRef_None); + if (!is_none) { PyStackRef_CLOSE(val); + SYNC_SP(); EXIT_IF(1); } + DEAD(val); } op (_GUARD_IS_NOT_NONE_POP, (val -- )) { - SYNC_SP(); - EXIT_IF(PyStackRef_Is(val, PyStackRef_None)); + int is_none = PyStackRef_Is(val, PyStackRef_None); PyStackRef_CLOSE(val); + SYNC_SP(); + EXIT_IF(is_none); } op(_JUMP_TO_TOP, (--)) { @@ -4782,6 +4869,7 @@ dummy_func( op(_INTERNAL_INCREMENT_OPT_COUNTER, (opt --)) { _PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt); exe->count++; + DEAD(opt); } tier2 op(_DYNAMIC_EXIT, (exit_p/4 --)) { diff --git a/Python/ceval.c b/Python/ceval.c index 6e62939adb3745..ba5c70b25f0a89 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -274,7 +274,6 @@ static void monitor_throw(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); -static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg); static int get_exception_handler(PyCodeObject *, int, int*, int*, int*); static _PyInterpreterFrame * _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, _PyStackRef func, @@ -394,6 +393,13 @@ const _Py_SpecialMethod _Py_SpecialMethods[] = { } }; +const size_t _Py_FunctionAttributeOffsets[] = { + [MAKE_FUNCTION_CLOSURE] = offsetof(PyFunctionObject, func_closure), + [MAKE_FUNCTION_ANNOTATIONS] = offsetof(PyFunctionObject, func_annotations), + [MAKE_FUNCTION_KWDEFAULTS] = offsetof(PyFunctionObject, func_kwdefaults), + [MAKE_FUNCTION_DEFAULTS] = offsetof(PyFunctionObject, func_defaults), + [MAKE_FUNCTION_ANNOTATE] = offsetof(PyFunctionObject, func_annotate), +}; // PEP 634: Structural Pattern Matching @@ -1036,6 +1042,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int uopcode = next_uop->opcode; #ifdef Py_DEBUG if (lltrace >= 3) { + dump_stack(frame, stack_pointer); if (next_uop->opcode == _START_EXECUTOR) { printf("%4d uop: ", 0); } @@ -1043,8 +1050,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int printf("%4d uop: ", (int)(next_uop - current_executor->trace)); } _PyUOpPrint(next_uop); - printf(" stack_level=%d\n", - (int)(stack_pointer - _PyFrame_Stackbase(frame))); + printf("\n"); } #endif next_uop++; @@ -2920,11 +2926,11 @@ _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right) return 0; } -static int -check_args_iterable(PyThreadState *tstate, PyObject *func, PyObject *args) +int +_Py_Check_ArgsIterable(PyThreadState *tstate, PyObject *func, PyObject *args) { if (Py_TYPE(args)->tp_iter == NULL && !PySequence_Check(args)) { - /* check_args_iterable() may be called with a live exception: + /* _Py_Check_ArgsIterable() may be called with a live exception: * clear it to prevent calling _PyObject_FunctionStr() with an * exception set. */ _PyErr_Clear(tstate); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 9e1540674d4219..e0e9cc156ed62f 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -108,6 +108,7 @@ do { \ /* Do interpreter dispatch accounting for tracing and instrumentation */ #define DISPATCH() \ { \ + assert(frame->stackpointer == NULL); \ NEXTOPARG(); \ PRE_DISPATCH_GOTO(); \ DISPATCH_GOTO(); \ diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1716d5d8e68827..7631ff75ecafd6 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -14,9 +14,11 @@ case _CHECK_PERIODIC: { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) JUMP_TO_ERROR(); } break; @@ -28,7 +30,9 @@ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); QSBR_QUIESCENT_STATE(tstate); \ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) JUMP_TO_ERROR(); } } @@ -62,10 +66,12 @@ oparg = CURRENT_OPARG(); _PyStackRef value_s = GETLOCAL(oparg); if (PyStackRef_IsNull(value_s)) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) ); + stack_pointer = _PyFrame_GetStackPointer(frame); if (1) JUMP_TO_ERROR(); } value = PyStackRef_DUP(value_s); @@ -323,11 +329,13 @@ case _END_SEND: { _PyStackRef value; _PyStackRef receiver; + _PyStackRef val; value = stack_pointer[-1]; receiver = stack_pointer[-2]; (void)receiver; + val = value; PyStackRef_CLOSE(receiver); - stack_pointer[-2] = value; + stack_pointer[-2] = val; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -337,7 +345,9 @@ _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); @@ -360,7 +370,9 @@ _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (err < 0) JUMP_TO_ERROR(); res = err ? PyStackRef_True : PyStackRef_False; @@ -469,7 +481,9 @@ _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); @@ -568,7 +582,7 @@ STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free);; + _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -775,7 +789,9 @@ container = stack_pointer[-2]; PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_GetItem(container_o, sub_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(container); PyStackRef_CLOSE(sub); if (res_o == NULL) JUMP_TO_ERROR(); @@ -794,8 +810,10 @@ stop = stack_pointer[-1]; start = stack_pointer[-2]; container = stack_pointer[-3]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), PyStackRef_AsPyObjectSteal(stop)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyObject *res_o; // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -803,8 +821,14 @@ res_o = NULL; } else { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(slice); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } PyStackRef_CLOSE(container); if (res_o == NULL) JUMP_TO_ERROR(); @@ -824,15 +848,23 @@ start = stack_pointer[-2]; container = stack_pointer[-3]; v = stack_pointer[-4]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), PyStackRef_AsPyObjectSteal(stop)); + stack_pointer = _PyFrame_GetStackPointer(frame); int err; if (slice == NULL) { err = 1; } else { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(slice); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } PyStackRef_CLOSE(v); PyStackRef_CLOSE(container); @@ -976,9 +1008,13 @@ } STAT_INC(BINARY_SUBSCR, hit); PyObject *res_o; + _PyFrame_SetStackPointer(frame, stack_pointer); int rc = PyDict_GetItemRef(dict, sub, &res_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (rc == 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetKeyError(sub); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(dict_st); PyStackRef_CLOSE(sub_st); @@ -1031,13 +1067,11 @@ PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; PyObject *getitem = ht->_spec_cache.getitem; new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR); - stack_pointer[0].bits = (uintptr_t)new_frame; - stack_pointer += 1; + stack_pointer[-2].bits = (uintptr_t)new_frame; + stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; } @@ -1048,8 +1082,9 @@ oparg = CURRENT_OPARG(); v = stack_pointer[-1]; list = stack_pointer[-2 - (oparg-1)]; - if (_PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), - PyStackRef_AsPyObjectSteal(v)) < 0) JUMP_TO_ERROR(); + int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), + PyStackRef_AsPyObjectSteal(v)); + if (err < 0) JUMP_TO_ERROR(); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -1061,8 +1096,10 @@ oparg = CURRENT_OPARG(); v = stack_pointer[-1]; set = stack_pointer[-2 - (oparg-1)]; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PySet_Add(PyStackRef_AsPyObjectBorrow(set), PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); if (err) JUMP_TO_ERROR(); stack_pointer += -1; @@ -1078,7 +1115,9 @@ container = stack_pointer[-2]; v = stack_pointer[-3]; /* container[sub] = v */ + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectBorrow(sub), PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); PyStackRef_CLOSE(container); PyStackRef_CLOSE(sub); @@ -1141,9 +1180,11 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(STORE_SUBSCR, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, PyStackRef_AsPyObjectSteal(sub), PyStackRef_AsPyObjectSteal(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(dict_st); if (err) JUMP_TO_ERROR(); stack_pointer += -3; @@ -1157,8 +1198,10 @@ sub = stack_pointer[-1]; container = stack_pointer[-2]; /* del container[sub] */ + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_DelItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectBorrow(sub)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(container); PyStackRef_CLOSE(sub); if (err) JUMP_TO_ERROR(); @@ -1173,7 +1216,9 @@ oparg = CURRENT_OPARG(); value = stack_pointer[-1]; assert(oparg <= MAX_INTRINSIC_1); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); @@ -1191,7 +1236,9 @@ assert(oparg <= MAX_INTRINSIC_2); PyObject *value1 = PyStackRef_AsPyObjectBorrow(value1_st); PyObject *value2 = PyStackRef_AsPyObjectBorrow(value2_st); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyIntrinsics_BinaryFunctions[oparg].func(tstate, value2, value1); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value2_st); PyStackRef_CLOSE(value1_st); if (res_o == NULL) JUMP_TO_ERROR(); @@ -1209,6 +1256,7 @@ #if TIER_ONE assert(frame != &entry_frame); #endif + _PyStackRef temp = retval; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1218,9 +1266,9 @@ _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; _PyEval_FrameClearAndPop(tstate, dying); - LOAD_SP(); + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(frame->return_offset); - res = retval; + res = temp; LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; @@ -1240,22 +1288,30 @@ getter = type->tp_as_async->am_aiter; } if (getter == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(obj); if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); iter_o = (*getter)(obj_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(obj); if (iter_o == NULL) JUMP_TO_ERROR(); if (Py_TYPE(iter_o)->tp_as_async == NULL || Py_TYPE(iter_o)->tp_as_async->am_anext == NULL) { + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, "'async for' received an object from __aiter__ " "that does not implement __anext__: %.100s", Py_TYPE(iter_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(iter_o); if (true) JUMP_TO_ERROR(); } @@ -1268,7 +1324,9 @@ _PyStackRef aiter; _PyStackRef awaitable; aiter = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *awaitable_o = _PyEval_GetANext(PyStackRef_AsPyObjectBorrow(aiter)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (awaitable_o == NULL) { JUMP_TO_ERROR(); } @@ -1284,7 +1342,9 @@ _PyStackRef iter; oparg = CURRENT_OPARG(); iterable = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); if (iter_o == NULL) JUMP_TO_ERROR(); iter = PyStackRef_FromPyObjectSteal(iter_o); @@ -1339,6 +1399,7 @@ assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; + _PyStackRef temp = retval; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1352,15 +1413,15 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); #endif + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - LOAD_SP(); - value = retval; + value = temp; LLTRACE_RESUME_FRAME(); stack_pointer[0] = value; stack_pointer += 1; @@ -1372,9 +1433,11 @@ _PyStackRef exc_value; exc_value = stack_pointer[-1]; _PyErr_StackItem *exc_info = tstate->exc_info; + _PyFrame_SetStackPointer(frame, stack_pointer); Py_XSETREF(exc_info->exc_value, PyStackRef_Is(exc_value, PyStackRef_None) ? NULL : PyStackRef_AsPyObjectSteal(exc_value)); + stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -1384,16 +1447,16 @@ _PyStackRef value; oparg = CURRENT_OPARG(); // Keep in sync with _common_constants in opcode.py - switch(oparg) { - case CONSTANT_ASSERTIONERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_AssertionError); - break; - case CONSTANT_NOTIMPLEMENTEDERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_NotImplementedError); - break; - default: - Py_FatalError("bad LOAD_COMMON_CONSTANT oparg"); + // If we ever have more than two constants, use a lookup table + PyObject *val; + if (oparg == CONSTANT_ASSERTIONERROR) { + val = PyExc_AssertionError; + } + else { + assert(oparg == CONSTANT_NOTIMPLEMENTEDERROR); + val = PyExc_NotImplementedError; } + value = PyStackRef_FromPyObjectImmortal(val); stack_pointer[0] = value; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -1403,10 +1466,15 @@ case _LOAD_BUILD_CLASS: { _PyStackRef bc; PyObject *bc_o; - if (PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o) < 0) JUMP_TO_ERROR(); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) JUMP_TO_ERROR(); if (bc_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) JUMP_TO_ERROR(); } bc = PyStackRef_FromPyObjectSteal(bc_o); @@ -1424,15 +1492,23 @@ PyObject *ns = LOCALS(); int err; if (ns == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); if (true) JUMP_TO_ERROR(); } - if (PyDict_CheckExact(ns)) - err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); - else - err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + if (PyDict_CheckExact(ns)) { + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + } PyStackRef_CLOSE(v); if (err) JUMP_TO_ERROR(); stack_pointer += -1; @@ -1446,16 +1522,22 @@ PyObject *ns = LOCALS(); int err; if (ns == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals when deleting %R", name); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_DelItem(ns, name); + stack_pointer = _PyFrame_GetStackPointer(frame); // Can't use ERROR_IF here. if (err != 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_ERROR(); } break; @@ -1468,7 +1550,9 @@ seq = stack_pointer[-1]; output = &stack_pointer[-1]; _PyStackRef *top = output + oparg; + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(seq); if (res == 0) JUMP_TO_ERROR(); stack_pointer += -1 + oparg; @@ -1494,10 +1578,10 @@ } STAT_INC(UNPACK_SEQUENCE, hit); val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); - stack_pointer[0] = val0; val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); - stack_pointer[-1] = val1; PyStackRef_CLOSE(seq); + stack_pointer[-1] = val1; + stack_pointer[0] = val0; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); break; @@ -1562,7 +1646,9 @@ seq = stack_pointer[-1]; right = &stack_pointer[(oparg & 0xFF)]; _PyStackRef *top = right + (oparg >> 8); + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(seq); if (res == 0) JUMP_TO_ERROR(); stack_pointer += (oparg & 0xFF) + (oparg >> 8); @@ -1577,8 +1663,10 @@ owner = stack_pointer[-1]; v = stack_pointer[-2]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); PyStackRef_CLOSE(owner); if (err) JUMP_TO_ERROR(); @@ -1592,7 +1680,9 @@ oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(owner); if (err) JUMP_TO_ERROR(); stack_pointer += -1; @@ -1605,7 +1695,9 @@ oparg = CURRENT_OPARG(); v = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); if (err) JUMP_TO_ERROR(); stack_pointer += -1; @@ -1616,14 +1708,18 @@ case _DELETE_GLOBAL: { oparg = CURRENT_OPARG(); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_Pop(GLOBALS(), name, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); // Can't use ERROR_IF here. if (err < 0) { JUMP_TO_ERROR(); } if (err == 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_ERROR(); } break; @@ -1633,8 +1729,10 @@ _PyStackRef locals; PyObject *l = LOCALS(); if (l == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_SystemError, "no locals found"); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) JUMP_TO_ERROR(); } locals = PyStackRef_FromPyObjectNew(l); @@ -1650,7 +1748,9 @@ _PyStackRef v; oparg = CURRENT_OPARG(); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *v_o = _PyEval_LoadName(tstate, frame, name); + stack_pointer = _PyFrame_GetStackPointer(frame); if (v_o == NULL) JUMP_TO_ERROR(); v = PyStackRef_FromPyObjectSteal(v_o); stack_pointer[0] = v; @@ -1665,7 +1765,9 @@ oparg = CURRENT_OPARG(); res = &stack_pointer[0]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); + stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(*res)) JUMP_TO_ERROR(); null = PyStackRef_NULL; if (oparg & 1) stack_pointer[1] = null; @@ -1754,10 +1856,12 @@ oparg = CURRENT_OPARG(); _PyStackRef v = GETLOCAL(oparg); if (PyStackRef_IsNull(v)) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) ); + stack_pointer = _PyFrame_GetStackPointer(frame); if (1) JUMP_TO_ERROR(); } SETLOCAL(oparg, PyStackRef_NULL); @@ -1784,7 +1888,9 @@ // Fortunately we don't need its superpower. PyObject *oldobj = PyCell_SwapTakeRef((PyCellObject *)cell, NULL); if (oldobj == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_ERROR(); } Py_DECREF(oldobj); @@ -1802,7 +1908,9 @@ assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyMapping_GetOptionalItem(class_dict, name, &value_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { JUMP_TO_ERROR(); } @@ -1810,7 +1918,9 @@ PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); value_o = PyCell_GetRef(cell); if (value_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_ERROR(); } } @@ -1826,7 +1936,9 @@ PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); PyObject *value_o = PyCell_GetRef(cell); if (value_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) JUMP_TO_ERROR(); } value = PyStackRef_FromPyObjectSteal(value_o); @@ -1841,7 +1953,9 @@ oparg = CURRENT_OPARG(); v = stack_pointer[-1]; PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); + _PyFrame_SetStackPointer(frame, stack_pointer); PyCell_SetTakeRef(cell, PyStackRef_AsPyObjectSteal(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -1924,16 +2038,22 @@ list_st = stack_pointer[-2 - (oparg-1)]; PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); PyObject *iterable = PyStackRef_AsPyObjectBorrow(iterable_st); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); if (none_val == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_TypeError); + stack_pointer = _PyFrame_GetStackPointer(frame); if (matches && (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Clear(tstate); _PyErr_Format(tstate, PyExc_TypeError, "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(iterable_st); if (true) JUMP_TO_ERROR(); @@ -1951,8 +2071,10 @@ oparg = CURRENT_OPARG(); iterable = stack_pointer[-1]; set = stack_pointer[-2 - (oparg-1)]; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PySet_Update(PyStackRef_AsPyObjectBorrow(set), PyStackRef_AsPyObjectBorrow(iterable)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); if (err < 0) JUMP_TO_ERROR(); stack_pointer += -1; @@ -1965,7 +2087,9 @@ _PyStackRef set; oparg = CURRENT_OPARG(); values = &stack_pointer[-oparg]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *set_o = PySet_New(NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); if (set_o == NULL) { for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(values[_i]); @@ -1975,7 +2099,9 @@ int err = 0; for (int i = 0; i < oparg; i++) { if (err == 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(values[i]); } @@ -2002,10 +2128,12 @@ } if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *map_o = _PyDict_FromItems( values_o, 2, values_o+1, 2, oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(values_o); for (int _i = oparg*2; --_i >= 0;) { PyStackRef_CLOSE(values[_i]); @@ -2019,20 +2147,28 @@ } case _SETUP_ANNOTATIONS: { - int err; PyObject *ann_dict; if (LOCALS() == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals found when setting up annotations"); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) JUMP_TO_ERROR(); } /* check if __annotations__ in locals()... */ - if (PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict) < 0) JUMP_TO_ERROR(); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) JUMP_TO_ERROR(); if (ann_dict == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); ann_dict = PyDict_New(); + stack_pointer = _PyFrame_GetStackPointer(frame); if (ann_dict == NULL) JUMP_TO_ERROR(); + _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), ann_dict); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(ann_dict); if (err) JUMP_TO_ERROR(); } @@ -2050,13 +2186,19 @@ dict = stack_pointer[-2 - (oparg - 1)]; PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict); PyObject *update_o = PyStackRef_AsPyObjectBorrow(update); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_Update(dict_o, update_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_AttributeError); + stack_pointer = _PyFrame_GetStackPointer(frame); if (matches) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object is not a mapping", Py_TYPE(update_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(update); if (true) JUMP_TO_ERROR(); @@ -2078,9 +2220,13 @@ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict); PyObject *update_o = PyStackRef_AsPyObjectBorrow(update); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_MergeEx(dict_o, update_o, 2); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatKwargsError(tstate, callable_o, update_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(update); if (true) JUMP_TO_ERROR(); } @@ -2102,11 +2248,13 @@ assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_SetItem_Take2( (PyDictObject *)dict, PyStackRef_AsPyObjectSteal(key), PyStackRef_AsPyObjectSteal(value) ); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) JUMP_TO_ERROR(); stack_pointer += -2; assert(WITHIN_STACK_BOUNDS()); @@ -2138,7 +2286,9 @@ } STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(global_super_st); PyStackRef_CLOSE(class_st); PyStackRef_CLOSE(self_st); @@ -2176,8 +2326,10 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attr_o = _PySuper_Lookup(cls, self, name, Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(global_super_st); PyStackRef_CLOSE(class_st); if (attr_o == NULL) { @@ -2209,7 +2361,9 @@ if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ attr_o = NULL; + _PyFrame_SetStackPointer(frame, stack_pointer); int is_meth = _PyObject_GetMethod(PyStackRef_AsPyObjectBorrow(owner), name, &attr_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (is_meth) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. @@ -2232,9 +2386,13 @@ } else { /* Classic, pushes one value. */ + _PyFrame_SetStackPointer(frame, stack_pointer); attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(owner); if (attr_o == NULL) JUMP_TO_ERROR(); + /* We need to define self_or_null on all paths */ + self_or_null = PyStackRef_NULL; } attr = PyStackRef_FromPyObjectSteal(attr_o); stack_pointer[-1] = attr; @@ -2440,8 +2598,8 @@ STAT_INC(LOAD_ATTR, hit); null = PyStackRef_NULL; attr = PyStackRef_FromPyObjectNew(attr_o); - stack_pointer[-1] = attr; PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; break; } @@ -2462,8 +2620,8 @@ STAT_INC(LOAD_ATTR, hit); null = PyStackRef_NULL; attr = PyStackRef_FromPyObjectNew(attr_o); - stack_pointer[-1] = attr; PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; stack_pointer[0] = null; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -2499,9 +2657,9 @@ STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; null = PyStackRef_NULL; PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; break; } @@ -2515,9 +2673,9 @@ STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; null = PyStackRef_NULL; PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; stack_pointer[0] = null; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -2640,7 +2798,9 @@ } old_value = ep->me_value; PyDict_WatchEvent event = old_value == NULL ? PyDict_EVENT_ADDED : PyDict_EVENT_MODIFIED; + _PyFrame_SetStackPointer(frame, stack_pointer); _PyDict_NotifyEvent(tstate->interp, event, dict, name, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); ep->me_value = PyStackRef_AsPyObjectSteal(value); // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, // when dict only holds the strong reference to value in ep->me_value. @@ -2680,21 +2840,29 @@ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert((oparg >> 5) <= Py_GE); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_RichCompare(left_o, right_o, oparg >> 5); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res_o == NULL) JUMP_TO_ERROR(); if (oparg & 16) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int res_bool = PyObject_IsTrue(res_o); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(res_o); if (res_bool < 0) JUMP_TO_ERROR(); res = res_bool ? PyStackRef_True : PyStackRef_False; } else { res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); } - stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[0] = res; + stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); break; } @@ -2814,7 +2982,9 @@ left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + _PyFrame_SetStackPointer(frame, stack_pointer); int res = PySequence_Contains(right_o, left_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res < 0) JUMP_TO_ERROR(); @@ -2840,7 +3010,9 @@ } STAT_INC(CONTAINS_OP, hit); // Note: both set and frozenset use the same seq_contains method! + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PySet_Contains((PySetObject *)right_o, left_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res < 0) JUMP_TO_ERROR(); @@ -2865,7 +3037,9 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(CONTAINS_OP, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); int res = PyDict_Contains(right_o, left_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res < 0) JUMP_TO_ERROR(); @@ -2885,7 +3059,9 @@ exc_value_st = stack_pointer[-2]; PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); PyObject *match_type = PyStackRef_AsPyObjectBorrow(match_type_st); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyEval_CheckExceptStarTypeValid(tstate, match_type); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { PyStackRef_CLOSE(exc_value_st); PyStackRef_CLOSE(match_type_st); @@ -2893,15 +3069,23 @@ } PyObject *match_o = NULL; PyObject *rest_o = NULL; + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, &match_o, &rest_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(exc_value_st); PyStackRef_CLOSE(match_type_st); if (res < 0) JUMP_TO_ERROR(); assert((match_o == NULL) == (rest_o == NULL)); if (match_o == NULL) JUMP_TO_ERROR(); if (!Py_IsNone(match_o)) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); PyErr_SetHandledException(match_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } rest = PyStackRef_FromPyObjectSteal(rest_o); match = PyStackRef_FromPyObjectSteal(match_o); @@ -2919,12 +3103,16 @@ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyExceptionInstance_Check(left_o)); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyEval_CheckExceptTypeValid(tstate, right_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { PyStackRef_CLOSE(right); if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); int res = PyErr_GivenExceptionMatches(left_o, right_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(right); b = res ? PyStackRef_True : PyStackRef_False; stack_pointer[-1] = b; @@ -2939,9 +3127,11 @@ fromlist = stack_pointer[-1]; level = stack_pointer[-2]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_ImportName(tstate, frame, name, PyStackRef_AsPyObjectBorrow(fromlist), PyStackRef_AsPyObjectBorrow(level)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(level); PyStackRef_CLOSE(fromlist); if (res_o == NULL) JUMP_TO_ERROR(); @@ -2958,7 +3148,9 @@ oparg = CURRENT_OPARG(); from = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name); + stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; @@ -2991,7 +3183,9 @@ _PyStackRef len; obj = stack_pointer[-1]; // PUSH(len(TOS)) + _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(PyStackRef_AsPyObjectBorrow(obj)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (len_i < 0) JUMP_TO_ERROR(); PyObject *len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) JUMP_TO_ERROR(); @@ -3014,10 +3208,12 @@ // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(PyStackRef_AsPyObjectBorrow(names))); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attrs_o = _PyEval_MatchClass(tstate, PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(type), oparg, PyStackRef_AsPyObjectBorrow(names)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(subject); PyStackRef_CLOSE(type); PyStackRef_CLOSE(names); @@ -3067,8 +3263,10 @@ keys = stack_pointer[-1]; subject = stack_pointer[-2]; // On successful match, PUSH(values). Otherwise, PUSH(None). + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *values_or_none_o = _PyEval_MatchKeys(tstate, PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(keys)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (values_or_none_o == NULL) JUMP_TO_ERROR(); values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); stack_pointer[0] = values_or_none; @@ -3082,7 +3280,9 @@ _PyStackRef iter; iterable = stack_pointer[-1]; /* before: [obj]; after [getiter(obj)] */ + _PyFrame_SetStackPointer(frame, stack_pointer); iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable))); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); if (PyStackRef_IsNull(iter)) JUMP_TO_ERROR(); stack_pointer[-1] = iter; @@ -3100,23 +3300,29 @@ if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { /* and it is used in a 'yield from' expression of a regular generator. */ + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_TypeError, "cannot 'yield from' a coroutine object " "in a non-coroutine generator"); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_ERROR(); } iter = iterable; } - else if (PyGen_CheckExact(iterable_o)) { - iter = iterable; - } else { - /* `iterable` is not a generator. */ - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); - if (PyStackRef_IsNull(iter)) { - JUMP_TO_ERROR(); + if (PyGen_CheckExact(iterable_o)) { + iter = iterable; + } + else { + /* `iterable` is not a generator. */ + _PyFrame_SetStackPointer(frame, stack_pointer); + iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyStackRef_IsNull(iter)) { + JUMP_TO_ERROR(); + } + PyStackRef_CLOSE(iterable); } - PyStackRef_CLOSE(iterable); } stack_pointer[-1] = iter; break; @@ -3130,15 +3336,21 @@ iter = stack_pointer[-1]; /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (next_o == NULL) { if (_PyErr_Occurred(tstate)) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); if (!matches) { JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_MonitorRaise(tstate, frame, frame->instr_ptr); _PyErr_Clear(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); } /* iterator ended normally */ /* The translator sets the deopt target just past the matching END_FOR */ @@ -3337,19 +3549,30 @@ PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner); PyObject *name = _Py_SpecialMethods[oparg].name; PyObject *self_or_null_o; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); attr = PyStackRef_FromPyObjectSteal(_PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(attr)) { if (!_PyErr_Occurred(tstate)) { + stack_pointer[0] = attr; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, _Py_SpecialMethods[oparg].error, Py_TYPE(owner_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); } } if (PyStackRef_IsNull(attr)) JUMP_TO_ERROR(); self_or_null = PyStackRef_FromPyObjectSteal(self_or_null_o); - stack_pointer[-1] = attr; - stack_pointer[0] = self_or_null; - stack_pointer += 1; + stack_pointer[0] = attr; + stack_pointer[1] = self_or_null; + stack_pointer += 2; assert(WITHIN_STACK_BOUNDS()); break; } @@ -3389,8 +3612,10 @@ (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(res)) JUMP_TO_ERROR(); stack_pointer[0] = res; stack_pointer += 1; @@ -3399,9 +3624,10 @@ } case _PUSH_EXC_INFO: { - _PyStackRef new_exc; + _PyStackRef exc; _PyStackRef prev_exc; - new_exc = stack_pointer[-1]; + _PyStackRef new_exc; + exc = stack_pointer[-1]; _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = PyStackRef_FromPyObjectSteal(exc_info->exc_value); @@ -3409,8 +3635,9 @@ else { prev_exc = PyStackRef_None; } - assert(PyStackRef_ExceptionInstanceCheck(new_exc)); - exc_info->exc_value = PyStackRef_AsPyObjectNew(new_exc); + assert(PyStackRef_ExceptionInstanceCheck(exc)); + exc_info->exc_value = PyStackRef_AsPyObjectNew(exc); + new_exc = exc; stack_pointer[-1] = prev_exc; stack_pointer[0] = new_exc; stack_pointer += 1; @@ -3456,8 +3683,8 @@ assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; self = owner; + stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -3477,8 +3704,8 @@ assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; self = owner; + stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -3542,8 +3769,8 @@ assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; self = owner; + stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -3553,25 +3780,23 @@ case _MAYBE_EXPAND_METHOD: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; - _PyStackRef func; + _PyStackRef *callable; + _PyStackRef *func; _PyStackRef *maybe_self; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; + func = &stack_pointer[-2 - oparg]; maybe_self = &stack_pointer[-1 - oparg]; - if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *self = ((PyMethodObject *)callable_o)->im_self; maybe_self[0] = PyStackRef_FromPyObjectNew(self); PyObject *method = ((PyMethodObject *)callable_o)->im_func; - func = PyStackRef_FromPyObjectNew(method); - stack_pointer[-2 - oparg] = func; - PyStackRef_CLOSE(callable); - } - else { - func = callable; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); } break; } @@ -3583,13 +3808,13 @@ case _PY_FRAME_GENERAL: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3599,17 +3824,19 @@ assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, args, total_args, NULL, frame ); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. + stack_pointer = _PyFrame_GetStackPointer(frame); + // The frame has stolen all the arguments from the stack. stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); - if (new_frame == NULL) { + if (temp == NULL) { JUMP_TO_ERROR(); } + new_frame = temp; stack_pointer[0].bits = (uintptr_t)new_frame; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -3617,11 +3844,11 @@ } case _CHECK_FUNCTION_VERSION: { - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)CURRENT_OPERAND(); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); if (!PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -3636,12 +3863,12 @@ case _CHECK_METHOD_VERSION: { _PyStackRef *null; - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)CURRENT_OPERAND(); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); if (Py_TYPE(callable_o) != &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -3664,29 +3891,30 @@ case _EXPAND_METHOD: { _PyStackRef *null; - _PyStackRef callable; - _PyStackRef method; + _PyStackRef *callable; + _PyStackRef *method; _PyStackRef *self; oparg = CURRENT_OPARG(); null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; + method = &stack_pointer[-2 - oparg]; self = &stack_pointer[-1 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyStackRef_IsNull(null[0])); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - stack_pointer[-2 - oparg] = method; - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(temp); break; } case _CHECK_IS_NOT_PY_CALLABLE: { - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); if (PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -3701,16 +3929,16 @@ case _CALL_NON_PY_GENERAL: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -3719,20 +3947,22 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); } if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } @@ -3746,15 +3976,15 @@ case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { _PyStackRef *null; - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; if (!PyStackRef_IsNull(null[0])) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - if (Py_TYPE(PyStackRef_AsPyObjectBorrow(callable)) != &PyMethod_Type) { + if (Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } @@ -3762,18 +3992,21 @@ } case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { - _PyStackRef callable; - _PyStackRef func; + _PyStackRef *null; + _PyStackRef *callable; + _PyStackRef *func; _PyStackRef *self; oparg = CURRENT_OPARG(); - callable = stack_pointer[-2 - oparg]; + null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + func = &stack_pointer[-2 - oparg]; self = &stack_pointer[-1 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); STAT_INC(CALL, hit); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - func = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - stack_pointer[-2 - oparg] = func; - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + PyStackRef_CLOSE(temp); break; } @@ -3787,11 +4020,11 @@ case _CHECK_FUNCTION_EXACT_ARGS: { _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; @@ -3803,10 +4036,10 @@ } case _CHECK_STACK_SPACE: { - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { @@ -3823,16 +4056,16 @@ case _INIT_CALL_PY_EXACT_ARGS_0: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = 0; assert(oparg == CURRENT_OPARG()); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -3847,16 +4080,16 @@ case _INIT_CALL_PY_EXACT_ARGS_1: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = 1; assert(oparg == CURRENT_OPARG()); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -3871,16 +4104,16 @@ case _INIT_CALL_PY_EXACT_ARGS_2: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = 2; assert(oparg == CURRENT_OPARG()); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -3895,16 +4128,16 @@ case _INIT_CALL_PY_EXACT_ARGS_3: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = 3; assert(oparg == CURRENT_OPARG()); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -3919,16 +4152,16 @@ case _INIT_CALL_PY_EXACT_ARGS_4: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = 4; assert(oparg == CURRENT_OPARG()); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -3943,15 +4176,15 @@ case _INIT_CALL_PY_EXACT_ARGS: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -3969,12 +4202,13 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -4032,7 +4266,9 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PyObject_Str(arg_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(arg); if (PyStackRef_IsNull(res)) JUMP_TO_ERROR(); stack_pointer[-3] = res; @@ -4062,7 +4298,9 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PySequence_Tuple(arg_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(arg); if (PyStackRef_IsNull(res)) JUMP_TO_ERROR(); stack_pointer[-3] = res; @@ -4073,17 +4311,19 @@ case _CHECK_AND_ALLOCATE_OBJECT: { _PyStackRef *args; - _PyStackRef null; - _PyStackRef callable; - _PyStackRef self; - _PyStackRef init; + _PyStackRef *null; + _PyStackRef *callable; + _PyStackRef *init; + _PyStackRef *self; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; - null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + init = &stack_pointer[-2 - oparg]; + self = &stack_pointer[-1 - oparg]; uint32_t type_version = (uint32_t)CURRENT_OPERAND(); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - if (!PyStackRef_IsNull(null)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + if (!PyStackRef_IsNull(null[0])) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } @@ -4105,35 +4345,39 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); - self = PyStackRef_FromPyObjectSteal(_PyType_NewManagedObject(tp)); - if (PyStackRef_IsNull(self)) { + PyObject *self_o = _PyType_NewManagedObject(tp); + if (self_o == NULL) { JUMP_TO_ERROR(); } - PyStackRef_CLOSE(callable); - init = PyStackRef_FromPyObjectNew(init_func); - stack_pointer[-1 - oparg] = init; - stack_pointer[-2 - oparg] = self; + self[0] = PyStackRef_FromPyObjectSteal(self_o); + _PyStackRef temp = callable[0]; + init[0] = PyStackRef_FromPyObjectNew(init_func); + PyStackRef_CLOSE(temp); break; } case _CREATE_INIT_FRAME: { _PyStackRef *args; - _PyStackRef init; - _PyStackRef self; + _PyStackRef *self; + _PyStackRef *init; _PyInterpreterFrame *init_frame; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; - init = stack_pointer[-1 - oparg]; - self = stack_pointer[-2 - oparg]; + self = &stack_pointer[-1 - oparg]; + init = &stack_pointer[-2 - oparg]; + _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); + stack_pointer = _PyFrame_GetStackPointer(frame); assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK); /* Push self onto stack of shim */ - shim->localsplus[0] = PyStackRef_DUP(self); - args[-1] = self; + shim->localsplus[0] = PyStackRef_DUP(self[0]); + _PyFrame_SetStackPointer(frame, stack_pointer); init_frame = _PyEvalFramePushAndInit( - tstate, init, NULL, args-1, oparg+1, NULL, shim); - stack_pointer += -2 - oparg; + tstate, init[0], NULL, args-1, oparg+1, NULL, shim); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer[-2 - oparg].bits = (uintptr_t)init_frame; + stack_pointer += -1 - oparg; assert(WITHIN_STACK_BOUNDS()); if (init_frame == NULL) { _PyEval_FrameClearAndPop(tstate, shim); @@ -4144,9 +4388,6 @@ * We don't check recursion depth here, * as it will be checked after start_frame */ tstate->py_recursion_remaining--; - stack_pointer[0].bits = (uintptr_t)init_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); break; } @@ -4155,9 +4396,11 @@ should_be_none = stack_pointer[-1]; assert(STACK_LEVEL() == 2); if (!PyStackRef_Is(should_be_none, PyStackRef_None)) { + _PyFrame_SetStackPointer(frame, stack_pointer); PyErr_Format(PyExc_TypeError, "__init__() should return None, not '%.200s'", Py_TYPE(PyStackRef_AsPyObjectBorrow(should_be_none))->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_ERROR(); } stack_pointer += -1; @@ -4168,13 +4411,13 @@ case _CALL_BUILTIN_CLASS: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4192,20 +4435,22 @@ STAT_INC(CALL, hit); STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); } if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4217,14 +4462,14 @@ case _CALL_BUILTIN_O: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* Builtin METH_O functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4251,11 +4496,13 @@ PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); _PyStackRef arg = args[0]; _Py_EnterRecursiveCallTstateUnchecked(tstate); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable_o), PyStackRef_AsPyObjectBorrow(arg)); + stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(arg); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4267,14 +4514,14 @@ case _CALL_BUILTIN_FAST: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL functions, without keywords */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4293,24 +4540,26 @@ /* res = func(self, args, nargs) */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); } if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)( PyCFunction_GET_SELF(callable_o), args_o, total_args); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4322,14 +4571,14 @@ case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4345,26 +4594,30 @@ } STAT_INC(CALL, hit); /* res = func(self, args, nargs, kwnames) */ + _PyFrame_SetStackPointer(frame, stack_pointer); PyCFunctionFastWithKeywords cfunc = (PyCFunctionFastWithKeywords)(void(*)(void)) PyCFunction_GET_FUNCTION(callable_o); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); } if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4376,14 +4629,14 @@ case _CALL_LEN: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* len(o) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4401,7 +4654,9 @@ STAT_INC(CALL, hit); _PyStackRef arg_stackref = args[0]; PyObject *arg = PyStackRef_AsPyObjectBorrow(arg_stackref); + _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (len_i < 0) { JUMP_TO_ERROR(); } @@ -4410,7 +4665,7 @@ if (res_o == NULL) { GOTO_ERROR(error); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(arg_stackref); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4422,14 +4677,14 @@ case _CALL_ISINSTANCE: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* isinstance(o, o2) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4447,7 +4702,9 @@ STAT_INC(CALL, hit); _PyStackRef cls_stackref = args[1]; _PyStackRef inst_stackref = args[0]; + _PyFrame_SetStackPointer(frame, stack_pointer); int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (retval < 0) { JUMP_TO_ERROR(); } @@ -4455,7 +4712,7 @@ assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(inst_stackref); PyStackRef_CLOSE(cls_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -4502,13 +4759,13 @@ case _CALL_METHOD_DESCRIPTOR_O: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4543,14 +4800,16 @@ STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; _Py_EnterRecursiveCallTstateUnchecked(tstate); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, PyStackRef_AsPyObjectBorrow(self_stackref), PyStackRef_AsPyObjectBorrow(arg_stackref)); + stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); PyStackRef_CLOSE(arg_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4562,13 +4821,13 @@ case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4592,25 +4851,27 @@ } STAT_INC(CALL, hit); int nargs = total_args - 1; - PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); } if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFastWithKeywords cfunc = + (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4622,14 +4883,14 @@ case _CALL_METHOD_DESCRIPTOR_NOARGS: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; assert(oparg == 0 || oparg == 1); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4663,11 +4924,13 @@ STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; _Py_EnterRecursiveCallTstateUnchecked(tstate); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, self, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4679,13 +4942,13 @@ case _CALL_METHOD_DESCRIPTOR_FAST: { _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4708,26 +4971,28 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); - PyCFunctionFast cfunc = - (PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); } if (true) JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFast cfunc = + (PyCFunctionFast)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Clear the stack of the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -4738,20 +5003,49 @@ /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 because it is instrumented */ + case _MAYBE_EXPAND_METHOD_KW: { + _PyStackRef kwnames_in; + _PyStackRef *args; + _PyStackRef *self_or_null; + _PyStackRef *callable; + _PyStackRef *func; + _PyStackRef *maybe_self; + _PyStackRef kwnames_out; + oparg = CURRENT_OPARG(); + kwnames_in = stack_pointer[-1]; + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; + maybe_self[0] = PyStackRef_FromPyObjectNew(self); + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); + } + kwnames_out = kwnames_in; + stack_pointer[-1] = kwnames_out; + break; + } + /* _DO_CALL_KW is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ case _PY_FRAME_KW: { _PyStackRef kwnames; _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyInterpreterFrame *new_frame; oparg = CURRENT_OPARG(); kwnames = stack_pointer[-1]; args = &stack_pointer[-1 - oparg]; self_or_null = &stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -4763,30 +5057,30 @@ assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyFrame_SetStackPointer(frame, stack_pointer); new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(kwnames); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. - stack_pointer += -3 - oparg; + stack_pointer[-3 - oparg].bits = (uintptr_t)new_frame; + stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); if (new_frame == NULL) { JUMP_TO_ERROR(); } - stack_pointer[0].bits = (uintptr_t)new_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); break; } case _CHECK_FUNCTION_VERSION_KW: { - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); - callable = stack_pointer[-3 - oparg]; + callable = &stack_pointer[-3 - oparg]; uint32_t func_version = (uint32_t)CURRENT_OPERAND(); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); if (!PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -4801,12 +5095,12 @@ case _CHECK_METHOD_VERSION_KW: { _PyStackRef *null; - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); null = &stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; + callable = &stack_pointer[-3 - oparg]; uint32_t func_version = (uint32_t)CURRENT_OPERAND(); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); if (Py_TYPE(callable_o) != &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -4828,33 +5122,31 @@ } case _EXPAND_METHOD_KW: { - _PyStackRef kwnames; _PyStackRef *null; - _PyStackRef callable; - _PyStackRef method; + _PyStackRef *callable; + _PyStackRef *method; _PyStackRef *self; oparg = CURRENT_OPARG(); - kwnames = stack_pointer[-1]; null = &stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; + callable = &stack_pointer[-3 - oparg]; + method = &stack_pointer[-3 - oparg]; self = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + _PyStackRef callable_s = callable[0]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); assert(PyStackRef_IsNull(null[0])); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - stack_pointer[-3 - oparg] = method; - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); - stack_pointer[-1] = kwnames; + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(callable_s); break; } case _CHECK_IS_NOT_PY_CALLABLE_KW: { - _PyStackRef callable; + _PyStackRef *callable; oparg = CURRENT_OPARG(); - callable = stack_pointer[-3 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); if (PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -4870,17 +5162,17 @@ _PyStackRef kwnames; _PyStackRef *args; _PyStackRef *self_or_null; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef res; oparg = CURRENT_OPARG(); kwnames = stack_pointer[-1]; args = &stack_pointer[-1 - oparg]; self_or_null = &stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; + callable = &stack_pointer[-3 - oparg]; #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -4889,7 +5181,7 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -4899,17 +5191,19 @@ } PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(kwnames); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-3 - oparg] = res; @@ -4920,19 +5214,55 @@ /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 because it is instrumented */ - /* __DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ + case _MAKE_CALLARGS_A_TUPLE: { + _PyStackRef kwargs_in = PyStackRef_NULL; + _PyStackRef callargs; + _PyStackRef func; + _PyStackRef tuple; + _PyStackRef kwargs_out = PyStackRef_NULL; + oparg = CURRENT_OPARG(); + if (oparg & 1) { kwargs_in = stack_pointer[-(oparg & 1)]; } + callargs = stack_pointer[-1 - (oparg & 1)]; + func = stack_pointer[-3 - (oparg & 1)]; + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *tuple_o = PySequence_Tuple(callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (tuple_o == NULL) { + JUMP_TO_ERROR(); + } + PyStackRef_CLOSE(callargs); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); + } + kwargs_out = kwargs_in; + stack_pointer[-1 - (oparg & 1)] = tuple; + if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_out; + break; + } + + /* _DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ case _MAKE_FUNCTION: { _PyStackRef codeobj_st; _PyStackRef func; codeobj_st = stack_pointer[-1]; PyObject *codeobj = PyStackRef_AsPyObjectBorrow(codeobj_st); + _PyFrame_SetStackPointer(frame, stack_pointer); PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(codeobj_st); - if (func_obj == NULL) { - JUMP_TO_ERROR(); - } + if (func_obj == NULL) JUMP_TO_ERROR(); _PyFunction_SetVersion( func_obj, ((PyCodeObject *)codeobj)->co_version); func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); @@ -4941,43 +5271,22 @@ } case _SET_FUNCTION_ATTRIBUTE: { - _PyStackRef func_st; + _PyStackRef func_in; _PyStackRef attr_st; + _PyStackRef func_out; oparg = CURRENT_OPARG(); - func_st = stack_pointer[-1]; + func_in = stack_pointer[-1]; attr_st = stack_pointer[-2]; - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); - PyObject *attr = PyStackRef_AsPyObjectBorrow(attr_st); + PyObject *func = PyStackRef_AsPyObjectBorrow(func_in); + PyObject *attr = PyStackRef_AsPyObjectSteal(attr_st); + func_out = func_in; assert(PyFunction_Check(func)); - PyFunctionObject *func_obj = (PyFunctionObject *)func; - switch(oparg) { - case MAKE_FUNCTION_CLOSURE: - assert(func_obj->func_closure == NULL); - func_obj->func_closure = attr; - break; - case MAKE_FUNCTION_ANNOTATIONS: - assert(func_obj->func_annotations == NULL); - func_obj->func_annotations = attr; - break; - case MAKE_FUNCTION_KWDEFAULTS: - assert(PyDict_CheckExact(attr)); - assert(func_obj->func_kwdefaults == NULL); - func_obj->func_kwdefaults = attr; - break; - case MAKE_FUNCTION_DEFAULTS: - assert(PyTuple_CheckExact(attr)); - assert(func_obj->func_defaults == NULL); - func_obj->func_defaults = attr; - break; - case MAKE_FUNCTION_ANNOTATE: - assert(PyCallable_Check(attr)); - assert(func_obj->func_annotate == NULL); - func_obj->func_annotate = attr; - break; - default: - Py_UNREACHABLE(); - } - stack_pointer[-2] = func_st; + size_t offset = _Py_FunctionAttributeOffsets[oparg]; + assert(offset != 0); + PyObject **ptr = (PyObject **)(((char *)func) + offset); + assert(*ptr == NULL); + *ptr = attr; + stack_pointer[-2] = func_out; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -4987,10 +5296,10 @@ _PyStackRef res; assert(PyStackRef_FunctionCheck(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + _PyFrame_SetStackPointer(frame, stack_pointer); PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - if (gen == NULL) { - JUMP_TO_ERROR(); - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (gen == NULL) JUMP_TO_ERROR(); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *gen_frame = &gen->gi_iframe; @@ -5000,12 +5309,12 @@ gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); - res = PyStackRef_FromPyObjectSteal((PyObject *)gen); _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); - LOAD_SP(); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal((PyObject *)gen); LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; @@ -5045,7 +5354,9 @@ conversion_func conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = _PyEval_ConversionFuncs[oparg]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (result_o == NULL) JUMP_TO_ERROR(); result = PyStackRef_FromPyObjectSteal(result_o); @@ -5061,7 +5372,9 @@ /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value_o)) { + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PyObject_Format(value_o, NULL)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (PyStackRef_IsNull(res)) JUMP_TO_ERROR(); } @@ -5078,7 +5391,9 @@ _PyStackRef res; fmt_spec = stack_pointer[-1]; value = stack_pointer[-2]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Format(PyStackRef_AsPyObjectBorrow(value), PyStackRef_AsPyObjectBorrow(fmt_spec)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); PyStackRef_CLOSE(fmt_spec); if (res_o == NULL) JUMP_TO_ERROR(); @@ -5112,7 +5427,9 @@ PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs); PyObject *rhs_o = PyStackRef_AsPyObjectBorrow(rhs); assert(_PyEval_BinaryOps[oparg]); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_BinaryOps[oparg](lhs_o, rhs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(lhs); PyStackRef_CLOSE(rhs); if (res_o == NULL) JUMP_TO_ERROR(); @@ -5124,14 +5441,18 @@ } case _SWAP: { - _PyStackRef top; - _PyStackRef bottom; + _PyStackRef top_in; + _PyStackRef bottom_in; + _PyStackRef top_out; + _PyStackRef bottom_out; oparg = CURRENT_OPARG(); - top = stack_pointer[-1]; - bottom = stack_pointer[-2 - (oparg-2)]; + top_in = stack_pointer[-1]; + bottom_in = stack_pointer[-2 - (oparg-2)]; + bottom_out = bottom_in; + top_out = top_in; assert(oparg >= 2); - stack_pointer[-2 - (oparg-2)] = top; - stack_pointer[-1] = bottom; + stack_pointer[-2 - (oparg-2)] = top_out; + stack_pointer[-1] = bottom_out; break; } @@ -5154,54 +5475,58 @@ case _GUARD_IS_TRUE_POP: { _PyStackRef flag; flag = stack_pointer[-1]; + int is_true = PyStackRef_Is(flag, PyStackRef_True); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); - if (!PyStackRef_Is(flag, PyStackRef_True)) { + if (!is_true) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - assert(PyStackRef_Is(flag, PyStackRef_True)); break; } case _GUARD_IS_FALSE_POP: { _PyStackRef flag; flag = stack_pointer[-1]; + int is_false = PyStackRef_Is(flag, PyStackRef_False); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); - if (!PyStackRef_Is(flag, PyStackRef_False)) { + if (!is_false) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - assert(PyStackRef_Is(flag, PyStackRef_False)); break; } case _GUARD_IS_NONE_POP: { _PyStackRef val; val = stack_pointer[-1]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - if (!PyStackRef_Is(val, PyStackRef_None)) { + int is_none = PyStackRef_Is(val, PyStackRef_None); + if (!is_none) { PyStackRef_CLOSE(val); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); if (1) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); break; } case _GUARD_IS_NOT_NONE_POP: { _PyStackRef val; val = stack_pointer[-1]; + int is_none = PyStackRef_Is(val, PyStackRef_None); + PyStackRef_CLOSE(val); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); - if (PyStackRef_Is(val, PyStackRef_None)) { + if (is_none) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - PyStackRef_CLOSE(val); break; } @@ -5249,12 +5574,14 @@ #if defined(Py_DEBUG) && !defined(_Py_JIT) OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); if (lltrace >= 2) { + _PyFrame_SetStackPointer(frame, stack_pointer); printf("SIDE EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyCode_CODE(code)), _PyOpcode_OpName[target->op.code]); + stack_pointer = _PyFrame_GetStackPointer(frame); } #endif if (exit->executor && !exit->executor->vm_data.valid) { @@ -5275,7 +5602,9 @@ } else { int chain_depth = current_executor->vm_data.chain_depth + 1; + _PyFrame_SetStackPointer(frame, stack_pointer); int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, chain_depth); + stack_pointer = _PyFrame_GetStackPointer(frame); if (optimized <= 0) { exit->temperature = restart_backoff_counter(temperature); if (optimized < 0) { @@ -5337,8 +5666,8 @@ _PyStackRef null; PyObject *ptr = (PyObject *)CURRENT_OPERAND(); value = PyStackRef_FromPyObjectNew(ptr); - stack_pointer[0] = value; null = PyStackRef_NULL; + stack_pointer[0] = value; stack_pointer[1] = null; stack_pointer += 2; assert(WITHIN_STACK_BOUNDS()); @@ -5387,12 +5716,14 @@ #if defined(Py_DEBUG) && !defined(_Py_JIT) OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); if (lltrace >= 2) { + _PyFrame_SetStackPointer(frame, stack_pointer); printf("DYNAMIC EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); printf(", exit %u, temp %d, target %d -> %s]\n", exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))), _PyOpcode_OpName[target->op.code]); + stack_pointer = _PyFrame_GetStackPointer(frame); } #endif _PyExecutorObject *executor; @@ -5406,7 +5737,9 @@ exit->temperature = advance_backoff_counter(exit->temperature); GOTO_TIER_ONE(target); } + _PyFrame_SetStackPointer(frame, stack_pointer); int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, 0); + stack_pointer = _PyFrame_GetStackPointer(frame); if (optimized <= 0) { exit->temperature = restart_backoff_counter(exit->temperature); if (optimized < 0) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9de7554d4dfd55..a9c127784edc83 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -20,15 +20,17 @@ _PyStackRef rhs; _PyStackRef res; // _SPECIALIZE_BINARY_OP - rhs = stack_pointer[-1]; - lhs = stack_pointer[-2]; { + rhs = stack_pointer[-1]; + lhs = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, LOCALS_ARRAY); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(BINARY_OP); @@ -42,7 +44,9 @@ PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs); PyObject *rhs_o = PyStackRef_AsPyObjectBorrow(rhs); assert(_PyEval_BinaryOps[oparg]); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_BinaryOps[oparg](lhs_o, rhs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(lhs); PyStackRef_CLOSE(rhs); if (res_o == NULL) goto pop_2_error; @@ -63,9 +67,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_FLOAT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); @@ -99,9 +103,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_INT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); @@ -134,9 +138,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_UNICODE - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP); @@ -168,9 +172,9 @@ _PyStackRef left; _PyStackRef right; // _GUARD_BOTH_UNICODE - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP); @@ -230,9 +234,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_FLOAT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); @@ -266,9 +270,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_INT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); @@ -301,9 +305,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_FLOAT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); @@ -337,9 +341,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_INT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); @@ -353,7 +357,7 @@ STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free);; + _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } @@ -379,12 +383,14 @@ #endif /* ENABLE_SPECIALIZATION */ } // _BINARY_SLICE - stop = stack_pointer[-1]; - start = stack_pointer[-2]; - container = stack_pointer[-3]; { + stop = stack_pointer[-1]; + start = stack_pointer[-2]; + container = stack_pointer[-3]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), PyStackRef_AsPyObjectSteal(stop)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyObject *res_o; // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -392,8 +398,14 @@ res_o = NULL; } else { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(slice); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } PyStackRef_CLOSE(container); if (res_o == NULL) goto pop_3_error; @@ -416,15 +428,18 @@ _PyStackRef sub; _PyStackRef res; // _SPECIALIZE_BINARY_SUBSCR - sub = stack_pointer[-1]; - container = stack_pointer[-2]; { + sub = stack_pointer[-1]; + container = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; + assert(frame->stackpointer == NULL); #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_BinarySubscr(container, sub, next_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(BINARY_SUBSCR); @@ -435,7 +450,9 @@ { PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_GetItem(container_o, sub_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(container); PyStackRef_CLOSE(sub); if (res_o == NULL) goto pop_2_error; @@ -463,9 +480,13 @@ DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); PyObject *res_o; + _PyFrame_SetStackPointer(frame, stack_pointer); int rc = PyDict_GetItemRef(dict, sub, &res_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (rc == 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetKeyError(sub); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(dict_st); PyStackRef_CLOSE(sub_st); @@ -492,8 +513,8 @@ DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); } // _BINARY_SUBSCR_CHECK_FUNC - container = stack_pointer[-2]; { + container = stack_pointer[-2]; PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; @@ -508,14 +529,12 @@ STAT_INC(BINARY_SUBSCR, hit); } // _BINARY_SUBSCR_INIT_CALL - sub = stack_pointer[-1]; { + sub = stack_pointer[-1]; PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; PyObject *getitem = ht->_spec_cache.getitem; new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR); @@ -525,10 +544,13 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -671,10 +693,12 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *map_o = _PyDict_FromItems( values_o, 2, values_o+1, 2, oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(values_o); for (int _i = oparg*2; --_i >= 0;) { PyStackRef_CLOSE(values[_i]); @@ -698,7 +722,9 @@ _PyStackRef *values; _PyStackRef set; values = &stack_pointer[-oparg]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *set_o = PySet_New(NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); if (set_o == NULL) { for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(values[_i]); @@ -712,7 +738,9 @@ int err = 0; for (int i = 0; i < oparg; i++) { if (err == 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(values[i]); } @@ -832,22 +860,24 @@ PREDICTED(CALL); _Py_CODEUNIT *this_instr = next_instr - 4; (void)this_instr; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; - _PyStackRef func; + _PyStackRef *func; _PyStackRef *maybe_self; _PyStackRef res; // _SPECIALIZE_CALL - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; - _Py_Specialize_Call(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_Specialize_Call(callable[0], next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CALL); @@ -856,27 +886,26 @@ } /* Skip 2 cache entries */ // _MAYBE_EXPAND_METHOD - args = &stack_pointer[-oparg]; { + args = &stack_pointer[-oparg]; + func = &stack_pointer[-2 - oparg]; maybe_self = &stack_pointer[-1 - oparg]; - if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *self = ((PyMethodObject *)callable_o)->im_self; maybe_self[0] = PyStackRef_FromPyObjectNew(self); PyObject *method = ((PyMethodObject *)callable_o)->im_func; - func = PyStackRef_FromPyObjectNew(method); - stack_pointer[-2 - oparg] = func; - PyStackRef_CLOSE(callable); - } - else { - func = callable; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); } } // _DO_CALL - self_or_null = maybe_self; - callable = func; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -890,12 +919,15 @@ { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, total_args, NULL, frame ); + stack_pointer = _PyFrame_GetStackPointer(frame); // Manipulate stack directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 2); + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { @@ -907,7 +939,7 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } @@ -917,30 +949,36 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); if (res_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); } else { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { Py_CLEAR(res_o); } } } assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } @@ -954,15 +992,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -976,11 +1016,11 @@ next_instr += 4; INSTRUCTION_STATS(CALL_ALLOC_AND_ENTER_INIT); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; - _PyStackRef null; + _PyStackRef *callable; + _PyStackRef *null; _PyStackRef *args; - _PyStackRef self; - _PyStackRef init; + _PyStackRef *init; + _PyStackRef *self; _PyInterpreterFrame *init_frame; _PyInterpreterFrame *new_frame; /* Skip 1 cache entry */ @@ -989,13 +1029,15 @@ DEOPT_IF(tstate->interp->eval_frame, CALL); } // _CHECK_AND_ALLOCATE_OBJECT - args = &stack_pointer[-oparg]; - null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + args = &stack_pointer[-oparg]; + null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + init = &stack_pointer[-2 - oparg]; + self = &stack_pointer[-1 - oparg]; uint32_t type_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - DEOPT_IF(!PyStackRef_IsNull(null), CALL); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); DEOPT_IF(!PyType_Check(callable_o), CALL); PyTypeObject *tp = (PyTypeObject *)callable_o; DEOPT_IF(tp->tp_version_tag != type_version, CALL); @@ -1005,25 +1047,33 @@ PyCodeObject *code = (PyCodeObject *)init_func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize), CALL); STAT_INC(CALL, hit); - self = PyStackRef_FromPyObjectSteal(_PyType_NewManagedObject(tp)); - if (PyStackRef_IsNull(self)) { + PyObject *self_o = _PyType_NewManagedObject(tp); + if (self_o == NULL) { goto error; } - PyStackRef_CLOSE(callable); - init = PyStackRef_FromPyObjectNew(init_func); - stack_pointer[-1 - oparg] = init; + self[0] = PyStackRef_FromPyObjectSteal(self_o); + _PyStackRef temp = callable[0]; + init[0] = PyStackRef_FromPyObjectNew(init_func); + PyStackRef_CLOSE(temp); } // _CREATE_INIT_FRAME { + args = &stack_pointer[-oparg]; + self = &stack_pointer[-1 - oparg]; + init = &stack_pointer[-2 - oparg]; + _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); + stack_pointer = _PyFrame_GetStackPointer(frame); assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK); /* Push self onto stack of shim */ - shim->localsplus[0] = PyStackRef_DUP(self); - args[-1] = self; + shim->localsplus[0] = PyStackRef_DUP(self[0]); + _PyFrame_SetStackPointer(frame, stack_pointer); init_frame = _PyEvalFramePushAndInit( - tstate, init, NULL, args-1, oparg+1, NULL, shim); - stack_pointer += -2 - oparg; + tstate, init[0], NULL, args-1, oparg+1, NULL, shim); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer[-2 - oparg].bits = (uintptr_t)init_frame; + stack_pointer += -1 - oparg; assert(WITHIN_STACK_BOUNDS()); if (init_frame == NULL) { _PyEval_FrameClearAndPop(tstate, shim); @@ -1036,15 +1086,18 @@ tstate->py_recursion_remaining--; } // _PUSH_FRAME - new_frame = init_frame; { + new_frame = init_frame; // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -1058,9 +1111,9 @@ next_instr += 4; INSTRUCTION_STATS(CALL_BOUND_METHOD_EXACT_ARGS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *null; - _PyStackRef func; + _PyStackRef *func; _PyStackRef *self; _PyStackRef *self_or_null; _PyStackRef *args; @@ -1071,36 +1124,37 @@ DEOPT_IF(tstate->interp->eval_frame, CALL); } // _CHECK_CALL_BOUND_METHOD_EXACT_ARGS - null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); - DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable)) != &PyMethod_Type, CALL); + DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type, CALL); } // _INIT_CALL_BOUND_METHOD_EXACT_ARGS { + func = &stack_pointer[-2 - oparg]; self = &stack_pointer[-1 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); STAT_INC(CALL, hit); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - func = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - stack_pointer[-2 - oparg] = func; - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + PyStackRef_CLOSE(temp); } // flush // _CHECK_FUNCTION_VERSION - callable = stack_pointer[-2 - oparg]; { + callable = &stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(!PyFunction_Check(callable_o), CALL); PyFunctionObject *func = (PyFunctionObject *)callable_o; DEOPT_IF(func->func_version != func_version, CALL); } // _CHECK_FUNCTION_EXACT_ARGS - self_or_null = &stack_pointer[-1 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + self_or_null = &stack_pointer[-1 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; @@ -1108,18 +1162,18 @@ } // _CHECK_STACK_SPACE { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); } // _INIT_CALL_PY_EXACT_ARGS - args = &stack_pointer[-oparg]; { + args = &stack_pointer[-oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -1140,12 +1194,13 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -1159,9 +1214,9 @@ next_instr += 4; INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *null; - _PyStackRef method; + _PyStackRef *method; _PyStackRef *self; _PyStackRef *self_or_null; _PyStackRef *args; @@ -1172,11 +1227,11 @@ DEOPT_IF(tstate->interp->eval_frame, CALL); } // _CHECK_METHOD_VERSION - null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(Py_TYPE(callable_o) != &PyMethod_Type, CALL); PyObject *func = ((PyMethodObject *)callable_o)->im_func; DEOPT_IF(!PyFunction_Check(func), CALL); @@ -1185,23 +1240,24 @@ } // _EXPAND_METHOD { + method = &stack_pointer[-2 - oparg]; self = &stack_pointer[-1 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyStackRef_IsNull(null[0])); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - stack_pointer[-2 - oparg] = method; - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(temp); } // flush // _PY_FRAME_GENERAL - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -1211,17 +1267,19 @@ assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, args, total_args, NULL, frame ); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. + stack_pointer = _PyFrame_GetStackPointer(frame); + // The frame has stolen all the arguments from the stack. stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); - if (new_frame == NULL) { + if (temp == NULL) { goto error; } + new_frame = temp; } // _SAVE_RETURN_OFFSET { @@ -1237,10 +1295,11 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -1254,18 +1313,18 @@ next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_CLASS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_BUILTIN_CLASS - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -1277,7 +1336,7 @@ STAT_INC(CALL, hit); STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -1288,13 +1347,15 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -1305,15 +1366,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -1327,19 +1390,19 @@ next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_FAST); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_BUILTIN_FAST - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL functions, without keywords */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -1352,7 +1415,7 @@ /* res = func(self, args, nargs) */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -1363,17 +1426,19 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)( PyCFunction_GET_SELF(callable_o), args_o, total_args); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -1384,15 +1449,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -1406,19 +1473,19 @@ next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_FAST_WITH_KEYWORDS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_BUILTIN_FAST_WITH_KEYWORDS - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -1428,12 +1495,14 @@ DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS), CALL); STAT_INC(CALL, hit); /* res = func(self, args, nargs, kwnames) */ + _PyFrame_SetStackPointer(frame, stack_pointer); PyCFunctionFastWithKeywords cfunc = (PyCFunctionFastWithKeywords)(void(*)(void)) PyCFunction_GET_FUNCTION(callable_o); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -1444,14 +1513,16 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -1462,15 +1533,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -1484,19 +1557,19 @@ next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_O); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_BUILTIN_O - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* Builtin METH_O functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -1511,11 +1584,13 @@ PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); _PyStackRef arg = args[0]; _Py_EnterRecursiveCallTstateUnchecked(tstate); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable_o), PyStackRef_AsPyObjectBorrow(arg)); + stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(arg); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -1526,15 +1601,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -1550,56 +1627,89 @@ PREDICTED(CALL_FUNCTION_EX); _Py_CODEUNIT *this_instr = next_instr - 1; (void)this_instr; + _PyStackRef func; + _PyStackRef callargs; + _PyStackRef kwargs_in = PyStackRef_NULL; + _PyStackRef tuple; + _PyStackRef kwargs_out = PyStackRef_NULL; _PyStackRef func_st; _PyStackRef callargs_st; _PyStackRef kwargs_st = PyStackRef_NULL; _PyStackRef result; - // __DO_CALL_FUNCTION_EX - if (oparg & 1) { kwargs_st = stack_pointer[-(oparg & 1)]; } - callargs_st = stack_pointer[-1 - (oparg & 1)]; - func_st = stack_pointer[-3 - (oparg & 1)]; + // _MAKE_CALLARGS_A_TUPLE { - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); - PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); - PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); - // DICT_MERGE is called before this opcode if there are kwargs. - // It converts all dict subtypes in kwargs into regular dicts. - assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - if (!PyTuple_CheckExact(callargs)) { - int err = check_args_iterable(tstate, func, callargs); + if (oparg & 1) { kwargs_in = stack_pointer[-(oparg & 1)]; } + callargs = stack_pointer[-1 - (oparg & 1)]; + func = stack_pointer[-3 - (oparg & 1)]; + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { goto error; } - PyObject *tuple = PySequence_Tuple(callargs); - if (tuple == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *tuple_o = PySequence_Tuple(callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (tuple_o == NULL) { goto error; } - PyStackRef_CLOSE(callargs_st); - callargs_st = PyStackRef_FromPyObjectSteal(tuple); - callargs = tuple; + PyStackRef_CLOSE(callargs); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); } + kwargs_out = kwargs_in; + } + // _DO_CALL_FUNCTION_EX + { + kwargs_st = kwargs_out; + callargs_st = tuple; + func_st = func; + PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); + PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); + PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); + // DICT_MERGE is called before this opcode if there are kwargs. + // It converts all dict subtypes in kwargs into regular dicts. + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); assert(PyTuple_CheckExact(callargs)); EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + PyObject *result_o; + assert(!_PyErr_Occurred(tstate)); if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; + stack_pointer[-1 - (oparg & 1)] = callargs_st; + if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, func, arg); - if (err) goto error; - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { + goto error; + } + _PyFrame_SetStackPointer(frame, stack_pointer); + result_o = PyObject_Call(func, callargs, kwargs); + stack_pointer = _PyFrame_GetStackPointer(frame); if (!PyFunction_Check(func) && !PyMethod_Check(func)) { - if (PyStackRef_IsNull(result)) { + if (result_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, this_instr, func, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); } else { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, this_instr, func, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { - PyStackRef_CLEAR(result); + Py_CLEAR(result_o); } } } @@ -1612,11 +1722,16 @@ Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); + stack_pointer[-1 - (oparg & 1)] = callargs_st; + if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; + _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( tstate, func_st, locals, nargs, callargs, kwargs, frame); - // Need to manually shrink the stack since we exit with DISPATCH_INLINED. - STACK_SHRINK(oparg + 3); + stack_pointer = _PyFrame_GetStackPointer(frame); + // Need to sync the stack since we exit with DISPATCH_INLINED. + stack_pointer += -3 - (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); if (new_frame == NULL) { goto error; } @@ -1624,30 +1739,38 @@ frame->return_offset = 1; DISPATCH_INLINED(new_frame); } - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); + stack_pointer[-1 - (oparg & 1)] = callargs_st; + if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; + _PyFrame_SetStackPointer(frame, stack_pointer); + result_o = PyObject_Call(func, callargs, kwargs); + stack_pointer = _PyFrame_GetStackPointer(frame); } - PyStackRef_CLOSE(func_st); - PyStackRef_CLOSE(callargs_st); + _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(kwargs_st); - assert(PyStackRef_AsPyObjectBorrow(PEEK(2 + (oparg & 1))) == NULL); - if (PyStackRef_IsNull(result)) { + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(callargs_st); + PyStackRef_CLOSE(func_st); + if (result_o == NULL) { stack_pointer += -3 - (oparg & 1); assert(WITHIN_STACK_BOUNDS()); goto error; } + result = PyStackRef_FromPyObjectSteal(result_o); } // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-3 - (oparg & 1)] = result; + stack_pointer += -2 - (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-3 - (oparg & 1)] = result; - stack_pointer += -2 - (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 2 + (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-3 - (oparg & 1)] = result; @@ -1664,7 +1787,9 @@ _PyStackRef res; value = stack_pointer[-1]; assert(oparg <= MAX_INTRINSIC_1); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (res_o == NULL) goto pop_1_error; res = PyStackRef_FromPyObjectSteal(res_o); @@ -1684,7 +1809,9 @@ assert(oparg <= MAX_INTRINSIC_2); PyObject *value1 = PyStackRef_AsPyObjectBorrow(value1_st); PyObject *value2 = PyStackRef_AsPyObjectBorrow(value2_st); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyIntrinsics_BinaryFunctions[oparg].func(tstate, value2, value1); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value2_st); PyStackRef_CLOSE(value1_st); if (res_o == NULL) goto pop_2_error; @@ -1700,7 +1827,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL_ISINSTANCE); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; @@ -1708,9 +1835,9 @@ /* Skip 2 cache entries */ args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* isinstance(o, o2) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -1722,7 +1849,9 @@ STAT_INC(CALL, hit); _PyStackRef cls_stackref = args[1]; _PyStackRef inst_stackref = args[0]; + _PyFrame_SetStackPointer(frame, stack_pointer); int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (retval < 0) { goto error; } @@ -1730,7 +1859,7 @@ assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(inst_stackref); PyStackRef_CLOSE(cls_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -1744,21 +1873,27 @@ PREDICTED(CALL_KW); _Py_CODEUNIT *this_instr = next_instr - 4; (void)this_instr; - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef kwnames; + _PyStackRef kwnames_in; + _PyStackRef *func; + _PyStackRef *maybe_self; + _PyStackRef kwnames_out; _PyStackRef res; // _SPECIALIZE_CALL_KW - self_or_null = &stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; { + self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; - _Py_Specialize_CallKw(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_Specialize_CallKw(callable[0], next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CALL_KW); @@ -1766,11 +1901,30 @@ #endif /* ENABLE_SPECIALIZATION */ } /* Skip 2 cache entries */ + // _MAYBE_EXPAND_METHOD_KW + { + kwnames_in = stack_pointer[-1]; + args = &stack_pointer[-1 - oparg]; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; + maybe_self[0] = PyStackRef_FromPyObjectNew(self); + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); + } + kwnames_out = kwnames_in; + } // _DO_CALL_KW - kwnames = stack_pointer[-1]; - args = &stack_pointer[-1 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + kwnames = kwnames_out; + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); // oparg counts all of the args, but *not* self: int total_args = oparg; @@ -1778,17 +1932,6 @@ args--; total_args++; } - else if (Py_TYPE(callable_o) == &PyMethod_Type) { - args--; - total_args++; - PyObject *self = ((PyMethodObject *)callable_o)->im_self; - args[0] = PyStackRef_FromPyObjectNew(self); - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - args[-1] = PyStackRef_FromPyObjectNew(method); - PyStackRef_CLOSE(callable); - callable_o = method; - callable = args[-1]; - } int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); // Check if the call can be inlined or not if (Py_TYPE(callable_o) == &PyFunction_Type && @@ -1797,13 +1940,17 @@ { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + stack_pointer[-1] = kwnames; + _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(kwnames); - // Manipulate stack directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 3); + // Sync stack explicitly since we leave using DISPATCH_INLINED(). + stack_pointer += -3 - oparg; + assert(WITHIN_STACK_BOUNDS()); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { @@ -1816,7 +1963,7 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -1828,23 +1975,30 @@ goto error; } } + stack_pointer[-1] = kwnames; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames_o); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); if (opcode == INSTRUMENTED_CALL_KW) { PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); if (res_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); } else { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { Py_CLEAR(res_o); } @@ -1852,7 +2006,7 @@ } PyStackRef_CLOSE(kwnames); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } @@ -1874,10 +2028,10 @@ next_instr += 4; INSTRUCTION_STATS(CALL_KW_BOUND_METHOD); static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *null; _PyStackRef kwnames; - _PyStackRef method; + _PyStackRef *method; _PyStackRef *self; _PyStackRef *self_or_null; _PyStackRef *args; @@ -1888,11 +2042,11 @@ DEOPT_IF(tstate->interp->eval_frame, CALL_KW); } // _CHECK_METHOD_VERSION_KW - null = &stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; { + null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(Py_TYPE(callable_o) != &PyMethod_Type, CALL_KW); PyObject *func = ((PyMethodObject *)callable_o)->im_func; DEOPT_IF(!PyFunction_Check(func), CALL_KW); @@ -1900,26 +2054,26 @@ DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL_KW); } // _EXPAND_METHOD_KW - kwnames = stack_pointer[-1]; { + method = &stack_pointer[-3 - oparg]; self = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + _PyStackRef callable_s = callable[0]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); assert(PyStackRef_IsNull(null[0])); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - stack_pointer[-3 - oparg] = method; - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(callable_s); } // flush // _PY_FRAME_KW - kwnames = stack_pointer[-1]; - args = &stack_pointer[-1 - oparg]; - self_or_null = &stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + kwnames = stack_pointer[-1]; + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -1931,14 +2085,17 @@ assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyFrame_SetStackPointer(frame, stack_pointer); new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(kwnames); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. - stack_pointer += -3 - oparg; + stack_pointer[-3 - oparg].bits = (uintptr_t)new_frame; + stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); if (new_frame == NULL) { goto error; @@ -1958,10 +2115,13 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -1975,7 +2135,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL_KW_NON_PY); static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef kwnames; _PyStackRef *self_or_null; _PyStackRef *args; @@ -1983,21 +2143,21 @@ /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CHECK_IS_NOT_PY_CALLABLE_KW - callable = stack_pointer[-3 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(PyFunction_Check(callable_o), CALL_KW); DEOPT_IF(Py_TYPE(callable_o) == &PyMethod_Type, CALL_KW); } // _CALL_KW_NON_PY - kwnames = stack_pointer[-1]; - args = &stack_pointer[-1 - oparg]; - self_or_null = &stack_pointer[-2 - oparg]; { + kwnames = stack_pointer[-1]; + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -2006,7 +2166,7 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -2020,17 +2180,19 @@ } PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(kwnames); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -3 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -2041,15 +2203,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-3 - oparg] = res; + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-3 - oparg] = res; - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 2 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-3 - oparg] = res; @@ -2063,7 +2227,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL_KW_PY); static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef kwnames; _PyStackRef *args; @@ -2074,20 +2238,20 @@ DEOPT_IF(tstate->interp->eval_frame, CALL_KW); } // _CHECK_FUNCTION_VERSION_KW - callable = stack_pointer[-3 - oparg]; { + callable = &stack_pointer[-3 - oparg]; uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(!PyFunction_Check(callable_o), CALL_KW); PyFunctionObject *func = (PyFunctionObject *)callable_o; DEOPT_IF(func->func_version != func_version, CALL_KW); } // _PY_FRAME_KW - kwnames = stack_pointer[-1]; - args = &stack_pointer[-1 - oparg]; - self_or_null = &stack_pointer[-2 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + kwnames = stack_pointer[-1]; + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -2099,14 +2263,17 @@ assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyFrame_SetStackPointer(frame, stack_pointer); new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(kwnames); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. - stack_pointer += -3 - oparg; + stack_pointer[-3 - oparg].bits = (uintptr_t)new_frame; + stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); if (new_frame == NULL) { goto error; @@ -2126,10 +2293,13 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -2143,7 +2313,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL_LEN); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; @@ -2151,9 +2321,9 @@ /* Skip 2 cache entries */ args = &stack_pointer[-oparg]; self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = &stack_pointer[-2 - oparg]; /* len(o) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -2165,7 +2335,9 @@ STAT_INC(CALL, hit); _PyStackRef arg_stackref = args[0]; PyObject *arg = PyStackRef_AsPyObjectBorrow(arg_stackref); + _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (len_i < 0) { goto error; } @@ -2174,7 +2346,7 @@ if (res_o == NULL) { GOTO_ERROR(error); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(arg_stackref); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2 - oparg] = res; @@ -2224,18 +2396,18 @@ next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_METHOD_DESCRIPTOR_FAST - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -2249,12 +2421,10 @@ PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); - PyCFunctionFast cfunc = - (PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -2265,14 +2435,18 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFast cfunc = + (PyCFunctionFast)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Clear the stack of the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -2283,15 +2457,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -2305,18 +2481,18 @@ next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -2331,11 +2507,9 @@ DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); STAT_INC(CALL, hit); int nargs = total_args - 1; - PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -2346,14 +2520,18 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFastWithKeywords cfunc = + (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -2364,15 +2542,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -2386,19 +2566,19 @@ next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_NOARGS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_METHOD_DESCRIPTOR_NOARGS - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; assert(oparg == 0 || oparg == 1); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -2417,11 +2597,13 @@ STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; _Py_EnterRecursiveCallTstateUnchecked(tstate); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, self, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -2432,15 +2614,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -2454,18 +2638,18 @@ next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_O); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_METHOD_DESCRIPTOR_O - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -2485,14 +2669,16 @@ STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; _Py_EnterRecursiveCallTstateUnchecked(tstate); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, PyStackRef_AsPyObjectBorrow(self_stackref), PyStackRef_AsPyObjectBorrow(arg_stackref)); + stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); PyStackRef_CLOSE(arg_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); if (res_o == NULL) { stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); @@ -2503,15 +2689,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -2525,27 +2713,27 @@ next_instr += 4; INSTRUCTION_STATS(CALL_NON_PY_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CHECK_IS_NOT_PY_CALLABLE - callable = stack_pointer[-2 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(PyFunction_Check(callable_o), CALL); DEOPT_IF(Py_TYPE(callable_o) == &PyMethod_Type, CALL); } // _CALL_NON_PY_GENERAL - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; { + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; @@ -2554,7 +2742,7 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(self_or_null[0]); for (int _i = oparg; --_i >= 0;) { PyStackRef_CLOSE(args[_i]); @@ -2565,13 +2753,15 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } @@ -2585,15 +2775,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -2607,7 +2799,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL_PY_EXACT_ARGS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyInterpreterFrame *new_frame; @@ -2617,18 +2809,18 @@ DEOPT_IF(tstate->interp->eval_frame, CALL); } // _CHECK_FUNCTION_VERSION - callable = stack_pointer[-2 - oparg]; { + callable = &stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(!PyFunction_Check(callable_o), CALL); PyFunctionObject *func = (PyFunctionObject *)callable_o; DEOPT_IF(func->func_version != func_version, CALL); } // _CHECK_FUNCTION_EXACT_ARGS - self_or_null = &stack_pointer[-1 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + self_or_null = &stack_pointer[-1 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; @@ -2636,18 +2828,18 @@ } // _CHECK_STACK_SPACE { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); } // _INIT_CALL_PY_EXACT_ARGS - args = &stack_pointer[-oparg]; { + args = &stack_pointer[-oparg]; int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { @@ -2668,12 +2860,13 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -2687,7 +2880,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL_PY_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; _PyInterpreterFrame *new_frame; @@ -2697,19 +2890,19 @@ DEOPT_IF(tstate->interp->eval_frame, CALL); } // _CHECK_FUNCTION_VERSION - callable = stack_pointer[-2 - oparg]; { + callable = &stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); DEOPT_IF(!PyFunction_Check(callable_o), CALL); PyFunctionObject *func = (PyFunctionObject *)callable_o; DEOPT_IF(func->func_version != func_version, CALL); } // _PY_FRAME_GENERAL - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -2719,17 +2912,19 @@ assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, args, total_args, NULL, frame ); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. + stack_pointer = _PyFrame_GetStackPointer(frame); + // The frame has stolen all the arguments from the stack. stack_pointer += -2 - oparg; assert(WITHIN_STACK_BOUNDS()); - if (new_frame == NULL) { + if (temp == NULL) { goto error; } + new_frame = temp; } // _SAVE_RETURN_OFFSET { @@ -2745,10 +2940,11 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -2769,27 +2965,36 @@ /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_STR_1 - arg = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; { + arg = stack_pointer[-1]; + null = stack_pointer[-2]; + callable = stack_pointer[-3]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); assert(oparg == 1); DEOPT_IF(!PyStackRef_IsNull(null), CALL); DEOPT_IF(callable_o != (PyObject *)&PyUnicode_Type, CALL); STAT_INC(CALL, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PyObject_Str(arg_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(arg); if (PyStackRef_IsNull(res)) goto pop_3_error; } // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-3] = res; + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) goto pop_2_error; + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-3] = res; @@ -2810,27 +3015,36 @@ /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_TUPLE_1 - arg = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; { + arg = stack_pointer[-1]; + null = stack_pointer[-2]; + callable = stack_pointer[-3]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); assert(oparg == 1); DEOPT_IF(!PyStackRef_IsNull(null), CALL); DEOPT_IF(callable_o != (PyObject *)&PyTuple_Type, CALL); STAT_INC(CALL, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PySequence_Tuple(arg_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(arg); if (PyStackRef_IsNull(res)) goto pop_3_error; } // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-3] = res; + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) goto pop_2_error; + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-3] = res; @@ -2879,7 +3093,9 @@ exc_value_st = stack_pointer[-2]; PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); PyObject *match_type = PyStackRef_AsPyObjectBorrow(match_type_st); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyEval_CheckExceptStarTypeValid(tstate, match_type); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { PyStackRef_CLOSE(exc_value_st); PyStackRef_CLOSE(match_type_st); @@ -2887,15 +3103,23 @@ } PyObject *match_o = NULL; PyObject *rest_o = NULL; + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, &match_o, &rest_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(exc_value_st); PyStackRef_CLOSE(match_type_st); if (res < 0) goto pop_2_error; assert((match_o == NULL) == (rest_o == NULL)); if (match_o == NULL) goto pop_2_error; if (!Py_IsNone(match_o)) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); PyErr_SetHandledException(match_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } rest = PyStackRef_FromPyObjectSteal(rest_o); match = PyStackRef_FromPyObjectSteal(match_o); @@ -2916,12 +3140,16 @@ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyExceptionInstance_Check(left_o)); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyEval_CheckExceptTypeValid(tstate, right_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { PyStackRef_CLOSE(right); if (true) goto pop_1_error; } + _PyFrame_SetStackPointer(frame, stack_pointer); int res = PyErr_GivenExceptionMatches(left_o, right_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(right); b = res ? PyStackRef_True : PyStackRef_False; stack_pointer[-1] = b; @@ -2944,21 +3172,25 @@ PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); if (matches) { + none = PyStackRef_None; value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value); - stack_pointer[-2] = value; PyStackRef_CLOSE(sub_iter_st); PyStackRef_CLOSE(last_sent_val_st); PyStackRef_CLOSE(exc_value_st); - none = PyStackRef_None; } else { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); goto exception_unwind; } stack_pointer[-3] = none; + stack_pointer[-2] = value; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -2975,15 +3207,17 @@ _PyStackRef right; _PyStackRef res; // _SPECIALIZE_COMPARE_OP - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_CompareOp(left, right, next_instr, oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(COMPARE_OP); @@ -2995,22 +3229,30 @@ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert((oparg >> 5) <= Py_GE); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_RichCompare(left_o, right_o, oparg >> 5); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res_o == NULL) goto pop_2_error; if (oparg & 16) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int res_bool = PyObject_IsTrue(res_o); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(res_o); - if (res_bool < 0) goto pop_2_error; + if (res_bool < 0) goto error; res = res_bool ? PyStackRef_True : PyStackRef_False; } else { res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); } } - stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[0] = res; + stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } @@ -3024,9 +3266,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_FLOAT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyFloat_CheckExact(left_o), COMPARE_OP); @@ -3062,9 +3304,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_INT - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyLong_CheckExact(left_o), COMPARE_OP); @@ -3104,9 +3346,9 @@ _PyStackRef right; _PyStackRef res; // _GUARD_BOTH_UNICODE - right = stack_pointer[-1]; - left = stack_pointer[-2]; { + right = stack_pointer[-1]; + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyUnicode_CheckExact(left_o), COMPARE_OP); @@ -3145,14 +3387,16 @@ _PyStackRef right; _PyStackRef b; // _SPECIALIZE_CONTAINS_OP - right = stack_pointer[-1]; { + right = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_ContainsOp(right, next_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CONTAINS_OP); @@ -3160,11 +3404,13 @@ #endif /* ENABLE_SPECIALIZATION */ } // _CONTAINS_OP - left = stack_pointer[-2]; { + left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + _PyFrame_SetStackPointer(frame, stack_pointer); int res = PySequence_Contains(right_o, left_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res < 0) goto pop_2_error; @@ -3191,7 +3437,9 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); DEOPT_IF(!PyDict_CheckExact(right_o), CONTAINS_OP); STAT_INC(CONTAINS_OP, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); int res = PyDict_Contains(right_o, left_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res < 0) goto pop_2_error; @@ -3218,7 +3466,9 @@ DEOPT_IF(!(PySet_CheckExact(right_o) || PyFrozenSet_CheckExact(right_o)), CONTAINS_OP); STAT_INC(CONTAINS_OP, hit); // Note: both set and frozenset use the same seq_contains method! + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PySet_Contains((PySetObject *)right_o, left_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(left); PyStackRef_CLOSE(right); if (res < 0) goto pop_2_error; @@ -3239,7 +3489,9 @@ conversion_func conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = _PyEval_ConversionFuncs[oparg]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (result_o == NULL) goto pop_1_error; result = PyStackRef_FromPyObjectSteal(result_o); @@ -3287,7 +3539,9 @@ _PyStackRef owner; owner = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(owner); if (err) goto pop_1_error; stack_pointer += -1; @@ -3304,7 +3558,9 @@ // Fortunately we don't need its superpower. PyObject *oldobj = PyCell_SwapTakeRef((PyCellObject *)cell, NULL); if (oldobj == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); goto error; } Py_DECREF(oldobj); @@ -3317,10 +3573,12 @@ INSTRUCTION_STATS(DELETE_FAST); _PyStackRef v = GETLOCAL(oparg); if (PyStackRef_IsNull(v)) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) ); + stack_pointer = _PyFrame_GetStackPointer(frame); if (1) goto error; } SETLOCAL(oparg, PyStackRef_NULL); @@ -3332,14 +3590,18 @@ next_instr += 1; INSTRUCTION_STATS(DELETE_GLOBAL); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_Pop(GLOBALS(), name, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); // Can't use ERROR_IF here. if (err < 0) { goto error; } if (err == 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); goto error; } DISPATCH(); @@ -3353,16 +3615,22 @@ PyObject *ns = LOCALS(); int err; if (ns == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals when deleting %R", name); + stack_pointer = _PyFrame_GetStackPointer(frame); goto error; } + _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_DelItem(ns, name); + stack_pointer = _PyFrame_GetStackPointer(frame); // Can't use ERROR_IF here. if (err != 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); goto error; } DISPATCH(); @@ -3377,8 +3645,10 @@ sub = stack_pointer[-1]; container = stack_pointer[-2]; /* del container[sub] */ + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_DelItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectBorrow(sub)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(container); PyStackRef_CLOSE(sub); if (err) goto pop_2_error; @@ -3400,9 +3670,13 @@ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict); PyObject *update_o = PyStackRef_AsPyObjectBorrow(update); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_MergeEx(dict_o, update_o, 2); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatKwargsError(tstate, callable_o, update_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(update); if (true) goto pop_1_error; } @@ -3422,13 +3696,19 @@ dict = stack_pointer[-2 - (oparg - 1)]; PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict); PyObject *update_o = PyStackRef_AsPyObjectBorrow(update); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_Update(dict_o, update_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_AttributeError); + stack_pointer = _PyFrame_GetStackPointer(frame); if (matches) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object is not a mapping", Py_TYPE(update_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(update); if (true) goto pop_1_error; @@ -3450,14 +3730,19 @@ awaitable_st = stack_pointer[-2]; PyObject *exc = PyStackRef_AsPyObjectBorrow(exc_st); assert(exc && PyExceptionInstance_Check(exc)); - if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { + _PyFrame_SetStackPointer(frame, stack_pointer); + int matches = PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (matches) { PyStackRef_CLOSE(awaitable_st); PyStackRef_CLOSE(exc_st); } else { Py_INCREF(exc); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetRaisedException(tstate, exc); monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); goto exception_unwind; } stack_pointer += -2; @@ -3483,11 +3768,13 @@ INSTRUCTION_STATS(END_SEND); _PyStackRef receiver; _PyStackRef value; + _PyStackRef val; value = stack_pointer[-1]; receiver = stack_pointer[-2]; (void)receiver; + val = value; PyStackRef_CLOSE(receiver); - stack_pointer[-2] = value; + stack_pointer[-2] = val; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -3534,9 +3821,11 @@ should_be_none = stack_pointer[-1]; assert(STACK_LEVEL() == 2); if (!PyStackRef_Is(should_be_none, PyStackRef_None)) { + _PyFrame_SetStackPointer(frame, stack_pointer); PyErr_Format(PyExc_TypeError, "__init__() should return None, not '%.200s'", Py_TYPE(PyStackRef_AsPyObjectBorrow(should_be_none))->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); goto error; } stack_pointer += -1; @@ -3566,7 +3855,9 @@ /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value_o)) { + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PyObject_Format(value_o, NULL)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (PyStackRef_IsNull(res)) goto pop_1_error; } @@ -3586,7 +3877,9 @@ _PyStackRef res; fmt_spec = stack_pointer[-1]; value = stack_pointer[-2]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Format(PyStackRef_AsPyObjectBorrow(value), PyStackRef_AsPyObjectBorrow(fmt_spec)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); PyStackRef_CLOSE(fmt_spec); if (res_o == NULL) goto pop_2_error; @@ -3607,14 +3900,16 @@ _PyStackRef iter; _PyStackRef next; // _SPECIALIZE_FOR_ITER - iter = stack_pointer[-1]; { + iter = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_ForIter(iter, next_instr, oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(FOR_ITER); @@ -3625,16 +3920,21 @@ { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (next_o == NULL) { - next = PyStackRef_NULL; if (_PyErr_Occurred(tstate)) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); if (!matches) { goto error; } + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_MonitorRaise(tstate, frame, this_instr); _PyErr_Clear(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); } /* iterator ended normally */ assert(next_instr[oparg].op.code == END_FOR || @@ -3668,8 +3968,8 @@ DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); } // _FOR_ITER_GEN_FRAME - iter = stack_pointer[-1]; { + iter = stack_pointer[-1]; PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); @@ -3684,15 +3984,16 @@ frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg); } // _PUSH_FRAME - new_frame = gen_frame; { + new_frame = gen_frame; // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -3710,8 +4011,8 @@ _PyStackRef next; /* Skip 1 cache entry */ // _ITER_CHECK_LIST - iter = stack_pointer[-1]; { + iter = stack_pointer[-1]; DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyListIter_Type, FOR_ITER); } // _ITER_JUMP_LIST @@ -3745,8 +4046,8 @@ assert(seq); assert(it->it_index < PyList_GET_SIZE(seq)); next = PyStackRef_FromPyObjectNew(PyList_GET_ITEM(seq, it->it_index++)); - stack_pointer[0] = next; } + stack_pointer[0] = next; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -3761,8 +4062,8 @@ _PyStackRef next; /* Skip 1 cache entry */ // _ITER_CHECK_RANGE - iter = stack_pointer[-1]; { + iter = stack_pointer[-1]; _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); } @@ -3806,8 +4107,8 @@ _PyStackRef next; /* Skip 1 cache entry */ // _ITER_CHECK_TUPLE - iter = stack_pointer[-1]; { + iter = stack_pointer[-1]; DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyTupleIter_Type, FOR_ITER); } // _ITER_JUMP_TUPLE @@ -3838,8 +4139,8 @@ assert(seq); assert(it->it_index < PyTuple_GET_SIZE(seq)); next = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq, it->it_index++)); - stack_pointer[0] = next; } + stack_pointer[0] = next; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -3860,24 +4161,32 @@ getter = type->tp_as_async->am_aiter; } if (getter == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(obj); if (true) goto pop_1_error; } + _PyFrame_SetStackPointer(frame, stack_pointer); iter_o = (*getter)(obj_o); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(obj); if (iter_o == NULL) goto pop_1_error; if (Py_TYPE(iter_o)->tp_as_async == NULL || Py_TYPE(iter_o)->tp_as_async->am_anext == NULL) { + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, "'async for' received an object from __aiter__ " "that does not implement __anext__: %.100s", Py_TYPE(iter_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(iter_o); - if (true) goto pop_1_error; + if (true) goto error; } iter = PyStackRef_FromPyObjectSteal(iter_o); stack_pointer[-1] = iter; @@ -3891,7 +4200,9 @@ _PyStackRef aiter; _PyStackRef awaitable; aiter = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *awaitable_o = _PyEval_GetANext(PyStackRef_AsPyObjectBorrow(aiter)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (awaitable_o == NULL) { goto error; } @@ -3909,7 +4220,9 @@ _PyStackRef iterable; _PyStackRef iter; iterable = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); if (iter_o == NULL) goto pop_1_error; iter = PyStackRef_FromPyObjectSteal(iter_o); @@ -3925,7 +4238,9 @@ _PyStackRef iter; iterable = stack_pointer[-1]; /* before: [obj]; after [getiter(obj)] */ + _PyFrame_SetStackPointer(frame, stack_pointer); iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable))); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); if (PyStackRef_IsNull(iter)) goto pop_1_error; stack_pointer[-1] = iter; @@ -3940,7 +4255,9 @@ _PyStackRef len; obj = stack_pointer[-1]; // PUSH(len(TOS)) + _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(PyStackRef_AsPyObjectBorrow(obj)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (len_i < 0) goto error; PyObject *len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; @@ -3965,23 +4282,29 @@ if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { /* and it is used in a 'yield from' expression of a regular generator. */ + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_TypeError, "cannot 'yield from' a coroutine object " "in a non-coroutine generator"); + stack_pointer = _PyFrame_GetStackPointer(frame); goto error; } iter = iterable; } - else if (PyGen_CheckExact(iterable_o)) { - iter = iterable; - } else { - /* `iterable` is not a generator. */ - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); - if (PyStackRef_IsNull(iter)) { - goto error; + if (PyGen_CheckExact(iterable_o)) { + iter = iterable; + } + else { + /* `iterable` is not a generator. */ + _PyFrame_SetStackPointer(frame, stack_pointer); + iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyStackRef_IsNull(iter)) { + goto error; + } + PyStackRef_CLOSE(iterable); } - PyStackRef_CLOSE(iterable); } stack_pointer[-1] = iter; DISPATCH(); @@ -3995,7 +4318,9 @@ _PyStackRef res; from = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name); + stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) goto error; res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; @@ -4014,9 +4339,11 @@ fromlist = stack_pointer[-1]; level = stack_pointer[-2]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_ImportName(tstate, frame, name, PyStackRef_AsPyObjectBorrow(fromlist), PyStackRef_AsPyObjectBorrow(level)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(level); PyStackRef_CLOSE(fromlist); if (res_o == NULL) goto pop_2_error; @@ -4032,57 +4359,62 @@ (void)this_instr; next_instr += 4; INSTRUCTION_STATS(INSTRUMENTED_CALL); - _PyStackRef callable; + _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; - _PyStackRef func; + _PyStackRef *func; _PyStackRef *maybe_self; _PyStackRef res; /* Skip 3 cache entries */ // _MAYBE_EXPAND_METHOD - args = &stack_pointer[-oparg]; - self_or_null = &stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; { + args = &stack_pointer[-oparg]; + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + func = &stack_pointer[-2 - oparg]; maybe_self = &stack_pointer[-1 - oparg]; - if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *self = ((PyMethodObject *)callable_o)->im_self; maybe_self[0] = PyStackRef_FromPyObjectNew(self); PyObject *method = ((PyMethodObject *)callable_o)->im_func; - func = PyStackRef_FromPyObjectNew(method); - stack_pointer[-2 - oparg] = func; - PyStackRef_CLOSE(callable); - } - else { - func = callable; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); } } // _MONITOR_CALL { + args = &stack_pointer[-oparg]; + maybe_self = &stack_pointer[-1 - oparg]; + func = &stack_pointer[-2 - oparg]; int is_meth = !PyStackRef_IsNull(maybe_self[0]); - PyObject *function = PyStackRef_AsPyObjectBorrow(func); + PyObject *function = PyStackRef_AsPyObjectBorrow(func[0]); PyObject *arg0; if (is_meth) { arg0 = PyStackRef_AsPyObjectBorrow(maybe_self[0]); } - else if (oparg) { - arg0 = PyStackRef_AsPyObjectBorrow(args[0]); - } else { - arg0 = &_PyInstrumentation_MISSING; + if (oparg) { + arg0 = PyStackRef_AsPyObjectBorrow(args[0]); + } + else { + arg0 = &_PyInstrumentation_MISSING; + } } + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, function, arg0 ); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) goto error; } // _DO_CALL - self_or_null = maybe_self; - callable = func; { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + self_or_null = maybe_self; + callable = func; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -4096,12 +4428,15 @@ { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, total_args, NULL, frame ); + stack_pointer = _PyFrame_GetStackPointer(frame); // Manipulate stack directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 2); + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { @@ -4113,7 +4448,7 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } @@ -4123,30 +4458,36 @@ goto error; } } + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); if (res_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); } else { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { Py_CLEAR(res_o); } } } assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } @@ -4160,15 +4501,17 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); - if (err != 0) { - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); } } stack_pointer[-2 - oparg] = res; @@ -4198,9 +4541,11 @@ PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3)); PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(PEEK(total_args + 1)); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, function, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) goto error; PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); GO_TO_INSTRUCTION(CALL_KW); @@ -4218,7 +4563,9 @@ /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyStackRef_GenCheck(receiver)) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { goto error; } @@ -4236,17 +4583,21 @@ INSTRUCTION_STATS(INSTRUMENTED_END_SEND); _PyStackRef receiver; _PyStackRef value; + _PyStackRef val; value = stack_pointer[-1]; receiver = stack_pointer[-2]; PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); if (PyGen_Check(receiver_o) || PyCoro_CheckExact(receiver_o)) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { goto error; } } + val = value; PyStackRef_CLOSE(receiver); - stack_pointer[-2] = value; + stack_pointer[-2] = val; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -4261,19 +4612,25 @@ _Py_CODEUNIT *target; _PyStackRef iter_stackref = TOP(); PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + stack_pointer = _PyFrame_GetStackPointer(frame); if (next != NULL) { PUSH(PyStackRef_FromPyObjectSteal(next)); target = next_instr; } else { if (_PyErr_Occurred(tstate)) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); if (!matches) { goto error; } + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_MonitorRaise(tstate, frame, this_instr); _PyErr_Clear(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); } /* iterator ended normally */ assert(next_instr[oparg].op.code == END_FOR || @@ -4292,8 +4649,10 @@ (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_INSTRUCTION); + _PyFrame_SetStackPointer(frame, stack_pointer); int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); if (next_opcode < 0) goto error; next_instr = this_instr; if (_PyOpcode_Caches[next_opcode]) { @@ -4313,9 +4672,11 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) goto error; } } @@ -4380,6 +4741,8 @@ // don't want to specialize instrumented instructions PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { @@ -4473,7 +4836,9 @@ uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK; uintptr_t code_version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version); if (code_version != global_version) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { goto error; } @@ -4488,7 +4853,9 @@ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); QSBR_QUIESCENT_STATE(tstate); \ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) goto error; } } @@ -4520,22 +4887,29 @@ // _LOAD_CONST { value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); - stack_pointer[0] = value; } // _RETURN_VALUE_EVENT - val = value; { + val = value; + stack_pointer[0] = val; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) goto error; } // _RETURN_VALUE - retval = val; { + retval = val; #if TIER_ONE assert(frame != &entry_frame); #endif + _PyStackRef temp = retval; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); @@ -4543,9 +4917,9 @@ _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; _PyEval_FrameClearAndPop(tstate, dying); - LOAD_SP(); + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(frame->return_offset); - res = retval; + res = temp; LLTRACE_RESUME_FRAME(); } stack_pointer[0] = res; @@ -4563,19 +4937,22 @@ _PyStackRef retval; _PyStackRef res; // _RETURN_VALUE_EVENT - val = stack_pointer[-1]; { + val = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) goto error; } // _RETURN_VALUE - retval = val; { + retval = val; #if TIER_ONE assert(frame != &entry_frame); #endif + _PyStackRef temp = retval; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -4585,9 +4962,9 @@ _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; _PyEval_FrameClearAndPop(tstate, dying); - LOAD_SP(); + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(frame->return_offset); - res = retval; + res = temp; LLTRACE_RESUME_FRAME(); } stack_pointer[0] = res; @@ -4605,22 +4982,24 @@ _PyStackRef retval; _PyStackRef value; // _YIELD_VALUE_EVENT - val = stack_pointer[-1]; { - SAVE_SP(); + val = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_YIELD, frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); - LOAD_SP(); - if (err) goto error; + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { + goto error; + } if (frame->instr_ptr != this_instr) { next_instr = frame->instr_ptr; DISPATCH(); } } // _YIELD_VALUE - retval = val; { + retval = val; // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -4632,6 +5011,7 @@ assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; + _PyStackRef temp = retval; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -4645,15 +5025,15 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); #endif + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - LOAD_SP(); - value = retval; + value = temp; LLTRACE_RESUME_FRAME(); } stack_pointer[0] = value; @@ -4675,6 +5055,8 @@ assert(!_PyErr_Occurred(tstate)); tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; return PyStackRef_AsPyObjectSteal(retval); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); } TARGET(IS_OP) { @@ -4710,9 +5092,11 @@ // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) goto error; } } @@ -4733,7 +5117,9 @@ start--; } _PyExecutorObject *executor; + _PyFrame_SetStackPointer(frame, stack_pointer); int optimized = _PyOptimizer_Optimize(frame, start, stack_pointer, &executor, 0); + stack_pointer = _PyFrame_GetStackPointer(frame); if (optimized < 0) goto error; if (optimized) { assert(tstate->previous_executor == NULL); @@ -4782,8 +5168,9 @@ _PyStackRef v; v = stack_pointer[-1]; list = stack_pointer[-2 - (oparg-1)]; - if (_PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), - PyStackRef_AsPyObjectSteal(v)) < 0) goto pop_1_error; + int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), + PyStackRef_AsPyObjectSteal(v)); + if (err < 0) goto pop_1_error; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -4799,16 +5186,22 @@ list_st = stack_pointer[-2 - (oparg-1)]; PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); PyObject *iterable = PyStackRef_AsPyObjectBorrow(iterable_st); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); if (none_val == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_TypeError); + stack_pointer = _PyFrame_GetStackPointer(frame); if (matches && (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Clear(tstate); _PyErr_Format(tstate, PyExc_TypeError, "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); } PyStackRef_CLOSE(iterable_st); if (true) goto pop_1_error; @@ -4831,15 +5224,17 @@ _PyStackRef attr; _PyStackRef self_or_null = PyStackRef_NULL; // _SPECIALIZE_LOAD_ATTR - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_LoadAttr(owner, next_instr, name); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(LOAD_ATTR); @@ -4854,7 +5249,9 @@ if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ attr_o = NULL; + _PyFrame_SetStackPointer(frame, stack_pointer); int is_meth = _PyObject_GetMethod(PyStackRef_AsPyObjectBorrow(owner), name, &attr_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (is_meth) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. @@ -4877,9 +5274,13 @@ } else { /* Classic, pushes one value. */ + _PyFrame_SetStackPointer(frame, stack_pointer); attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(owner); if (attr_o == NULL) goto pop_1_error; + /* We need to define self_or_null on all paths */ + self_or_null = PyStackRef_NULL; } attr = PyStackRef_FromPyObjectSteal(attr_o); } @@ -4900,8 +5301,8 @@ _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ // _CHECK_ATTR_CLASS - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); DEOPT_IF(!PyType_Check(owner_o), LOAD_ATTR); @@ -4915,10 +5316,10 @@ STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; null = PyStackRef_NULL; PyStackRef_CLOSE(owner); } + stack_pointer[-1] = attr; if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); assert(WITHIN_STACK_BOUNDS()); @@ -4935,8 +5336,8 @@ _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ // _CHECK_ATTR_CLASS - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); DEOPT_IF(!PyType_Check(owner_o), LOAD_ATTR); @@ -4956,10 +5357,10 @@ STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; null = PyStackRef_NULL; PyStackRef_CLOSE(owner); } + stack_pointer[-1] = attr; if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); assert(WITHIN_STACK_BOUNDS()); @@ -5012,8 +5413,8 @@ _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5057,8 +5458,8 @@ _PyStackRef self = PyStackRef_NULL; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5081,9 +5482,9 @@ assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; self = owner; } + stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -5100,8 +5501,8 @@ _PyStackRef self = PyStackRef_NULL; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5117,9 +5518,9 @@ assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; self = owner; } + stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -5136,8 +5537,8 @@ _PyStackRef self = PyStackRef_NULL; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5165,9 +5566,9 @@ assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; self = owner; } + stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -5184,8 +5585,8 @@ _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ // _CHECK_ATTR_MODULE - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t dict_version = read_u32(&this_instr[2].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); DEOPT_IF(!PyModule_CheckExact(owner_o), LOAD_ATTR); @@ -5226,8 +5627,8 @@ _PyStackRef attr; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5243,8 +5644,8 @@ assert(descr != NULL); PyStackRef_CLOSE(owner); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; } + stack_pointer[-1] = attr; DISPATCH(); } @@ -5257,8 +5658,8 @@ _PyStackRef attr; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5285,8 +5686,8 @@ assert(descr != NULL); PyStackRef_CLOSE(owner); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[-1] = attr; } + stack_pointer[-1] = attr; DISPATCH(); } @@ -5303,8 +5704,8 @@ DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); } // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5340,12 +5741,13 @@ // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -5364,8 +5766,8 @@ _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5381,10 +5783,10 @@ STAT_INC(LOAD_ATTR, hit); null = PyStackRef_NULL; attr = PyStackRef_FromPyObjectNew(attr_o); - stack_pointer[-1] = attr; PyStackRef_CLOSE(owner); } /* Skip 5 cache entries */ + stack_pointer[-1] = attr; if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); assert(WITHIN_STACK_BOUNDS()); @@ -5401,8 +5803,8 @@ _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -5449,10 +5851,15 @@ INSTRUCTION_STATS(LOAD_BUILD_CLASS); _PyStackRef bc; PyObject *bc_o; - if (PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o) < 0) goto error; + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) goto error; if (bc_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) goto error; } bc = PyStackRef_FromPyObjectSteal(bc_o); @@ -5468,16 +5875,16 @@ INSTRUCTION_STATS(LOAD_COMMON_CONSTANT); _PyStackRef value; // Keep in sync with _common_constants in opcode.py - switch(oparg) { - case CONSTANT_ASSERTIONERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_AssertionError); - break; - case CONSTANT_NOTIMPLEMENTEDERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_NotImplementedError); - break; - default: - Py_FatalError("bad LOAD_COMMON_CONSTANT oparg"); + // If we ever have more than two constants, use a lookup table + PyObject *val; + if (oparg == CONSTANT_ASSERTIONERROR) { + val = PyExc_AssertionError; + } + else { + assert(oparg == CONSTANT_NOTIMPLEMENTEDERROR); + val = PyExc_NotImplementedError; } + value = PyStackRef_FromPyObjectImmortal(val); stack_pointer[0] = value; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -5504,7 +5911,9 @@ PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); PyObject *value_o = PyCell_GetRef(cell); if (value_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) goto error; } value = PyStackRef_FromPyObjectSteal(value_o); @@ -5548,10 +5957,12 @@ _PyStackRef value; _PyStackRef value_s = GETLOCAL(oparg); if (PyStackRef_IsNull(value_s)) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) ); + stack_pointer = _PyFrame_GetStackPointer(frame); if (1) goto error; } value = PyStackRef_DUP(value_s); @@ -5591,7 +6002,9 @@ assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyMapping_GetOptionalItem(class_dict, name, &value_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { goto error; } @@ -5599,7 +6012,9 @@ PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); value_o = PyCell_GetRef(cell); if (value_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); goto error; } } @@ -5618,23 +6033,30 @@ mod_or_class_dict = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *v_o; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &v_o); - if (err < 0) { - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(mod_or_class_dict); + if (err < 0) goto pop_1_error; if (v_o == NULL) { if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); v_o = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), (PyDictObject *)BUILTINS(), name); + stack_pointer = _PyFrame_GetStackPointer(frame); if (v_o == NULL) { if (!_PyErr_Occurred(tstate)) { /* _PyDict_LoadGlobal() returns NULL without raising * an exception if the key doesn't exist */ + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); } goto error; } @@ -5642,20 +6064,31 @@ else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - if (PyMapping_GetOptionalItem(GLOBALS(), name, &v_o) < 0) goto pop_1_error; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(GLOBALS(), name, &v_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) goto error; if (v_o == NULL) { /* namespace 2: builtins */ - if (PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0) goto pop_1_error; + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(BUILTINS(), name, &v_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) goto error; if (v_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcCheckArg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); - if (true) goto pop_1_error; + stack_pointer = _PyFrame_GetStackPointer(frame); + if (true) goto error; } } } + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); } - PyStackRef_CLOSE(mod_or_class_dict); v = PyStackRef_FromPyObjectSteal(v_o); stack_pointer[-1] = v; DISPATCH(); @@ -5678,7 +6111,9 @@ if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(LOAD_GLOBAL); @@ -5692,7 +6127,9 @@ { res = &stack_pointer[0]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); + stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(*res)) goto error; null = PyStackRef_NULL; } @@ -5788,8 +6225,10 @@ _PyStackRef locals; PyObject *l = LOCALS(); if (l == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_SystemError, "no locals found"); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) goto error; } locals = PyStackRef_FromPyObjectNew(l); @@ -5805,7 +6244,9 @@ INSTRUCTION_STATS(LOAD_NAME); _PyStackRef v; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *v_o = _PyEval_LoadName(tstate, frame, name); + stack_pointer = _PyFrame_GetStackPointer(frame); if (v_o == NULL) goto error; v = PyStackRef_FromPyObjectSteal(v_o); stack_pointer[0] = v; @@ -5826,19 +6267,35 @@ PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner); PyObject *name = _Py_SpecialMethods[oparg].name; PyObject *self_or_null_o; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); attr = PyStackRef_FromPyObjectSteal(_PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(attr)) { if (!_PyErr_Occurred(tstate)) { + stack_pointer[0] = attr; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, _Py_SpecialMethods[oparg].error, Py_TYPE(owner_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); } } - if (PyStackRef_IsNull(attr)) goto pop_1_error; + if (PyStackRef_IsNull(attr)) { + stack_pointer[0] = attr; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + goto error; + } self_or_null = PyStackRef_FromPyObjectSteal(self_or_null_o); - stack_pointer[-1] = attr; - stack_pointer[0] = self_or_null; - stack_pointer += 1; + stack_pointer[0] = attr; + stack_pointer[1] = self_or_null; + stack_pointer += 2; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } @@ -5856,16 +6313,18 @@ _PyStackRef attr; _PyStackRef null = PyStackRef_NULL; // _SPECIALIZE_LOAD_SUPER_ATTR - class_st = stack_pointer[-2]; - global_super_st = stack_pointer[-3]; { + class_st = stack_pointer[-2]; + global_super_st = stack_pointer[-3]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION int load_method = oparg & 1; if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_LoadSuperAttr(global_super_st, class_st, next_instr, load_method); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(LOAD_SUPER_ATTR); @@ -5873,33 +6332,46 @@ #endif /* ENABLE_SPECIALIZATION */ } // _LOAD_SUPER_ATTR - self_st = stack_pointer[-1]; { + self_st = stack_pointer[-1]; PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, global_super, arg); - if (err) goto pop_3_error; + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { + PyStackRef_CLOSE(global_super_st); + PyStackRef_CLOSE(class_st); + PyStackRef_CLOSE(self_st); + if (true) goto pop_3_error; + } } // we make no attempt to optimize here; specializations should // handle any case whose performance we care about PyObject *stack[] = {class, self}; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; if (super == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, this_instr, global_super, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); } else { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, this_instr, global_super, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { Py_CLEAR(super); } @@ -5910,14 +6382,18 @@ PyStackRef_CLOSE(self_st); if (super == NULL) goto pop_3_error; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); attr = PyStackRef_FromPyObjectSteal(PyObject_GetAttr(super, name)); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(super); - if (PyStackRef_IsNull(attr)) goto pop_3_error; + if (PyStackRef_IsNull(attr)) goto error; null = PyStackRef_NULL; } - stack_pointer[-3] = attr; - if (oparg & 1) stack_pointer[-2] = null; - stack_pointer += -2 + (oparg & 1); + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } @@ -5943,7 +6419,9 @@ DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(global_super_st); PyStackRef_CLOSE(class_st); PyStackRef_CLOSE(self_st); @@ -5979,8 +6457,10 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attr_o = _PySuper_Lookup(cls, self, name, Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(global_super_st); PyStackRef_CLOSE(class_st); if (attr_o == NULL) { @@ -6024,12 +6504,12 @@ _PyStackRef func; codeobj_st = stack_pointer[-1]; PyObject *codeobj = PyStackRef_AsPyObjectBorrow(codeobj_st); + _PyFrame_SetStackPointer(frame, stack_pointer); PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(codeobj_st); - if (func_obj == NULL) { - goto error; - } + if (func_obj == NULL) goto pop_1_error; _PyFunction_SetVersion( func_obj, ((PyCodeObject *)codeobj)->co_version); func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); @@ -6051,11 +6531,13 @@ assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_SetItem_Take2( (PyDictObject *)dict, PyStackRef_AsPyObjectSteal(key), PyStackRef_AsPyObjectSteal(value) ); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) goto pop_2_error; stack_pointer += -2; assert(WITHIN_STACK_BOUNDS()); @@ -6076,10 +6558,12 @@ // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(PyStackRef_AsPyObjectBorrow(names))); + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attrs_o = _PyEval_MatchClass(tstate, PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(type), oparg, PyStackRef_AsPyObjectBorrow(names)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(subject); PyStackRef_CLOSE(type); PyStackRef_CLOSE(names); @@ -6108,8 +6592,10 @@ keys = stack_pointer[-1]; subject = stack_pointer[-2]; // On successful match, PUSH(values). Otherwise, PUSH(None). + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *values_or_none_o = _PyEval_MatchKeys(tstate, PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(keys)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (values_or_none_o == NULL) goto error; values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); stack_pointer[0] = values_or_none; @@ -6162,9 +6648,11 @@ _PyStackRef exc_value; exc_value = stack_pointer[-1]; _PyErr_StackItem *exc_info = tstate->exc_info; + _PyFrame_SetStackPointer(frame, stack_pointer); Py_XSETREF(exc_info->exc_value, PyStackRef_Is(exc_value, PyStackRef_None) ? NULL : PyStackRef_AsPyObjectSteal(exc_value)); + stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -6199,8 +6687,8 @@ _PyStackRef cond; /* Skip 1 cache entry */ // _IS_NONE - value = stack_pointer[-1]; { + value = stack_pointer[-1]; if (PyStackRef_Is(value, PyStackRef_None)) { b = PyStackRef_True; } @@ -6210,8 +6698,8 @@ } } // _POP_JUMP_IF_TRUE - cond = b; { + cond = b; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_Is(cond, PyStackRef_True); #if ENABLE_SPECIALIZATION @@ -6234,8 +6722,8 @@ _PyStackRef cond; /* Skip 1 cache entry */ // _IS_NONE - value = stack_pointer[-1]; { + value = stack_pointer[-1]; if (PyStackRef_Is(value, PyStackRef_None)) { b = PyStackRef_True; } @@ -6245,8 +6733,8 @@ } } // _POP_JUMP_IF_FALSE - cond = b; { + cond = b; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_Is(cond, PyStackRef_False); #if ENABLE_SPECIALIZATION @@ -6294,9 +6782,10 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(PUSH_EXC_INFO); - _PyStackRef new_exc; + _PyStackRef exc; _PyStackRef prev_exc; - new_exc = stack_pointer[-1]; + _PyStackRef new_exc; + exc = stack_pointer[-1]; _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = PyStackRef_FromPyObjectSteal(exc_info->exc_value); @@ -6304,8 +6793,9 @@ else { prev_exc = PyStackRef_None; } - assert(PyStackRef_ExceptionInstanceCheck(new_exc)); - exc_info->exc_value = PyStackRef_AsPyObjectNew(new_exc); + assert(PyStackRef_ExceptionInstanceCheck(exc)); + exc_info->exc_value = PyStackRef_AsPyObjectNew(exc); + new_exc = exc; stack_pointer[-1] = prev_exc; stack_pointer[0] = new_exc; stack_pointer += 1; @@ -6332,31 +6822,22 @@ INSTRUCTION_STATS(RAISE_VARARGS); _PyStackRef *args; args = &stack_pointer[-oparg]; - PyObject *cause = NULL, *exc = NULL; - switch (oparg) { - case 2: - cause = PyStackRef_AsPyObjectSteal(args[1]); - _Py_FALLTHROUGH; - case 1: - exc = PyStackRef_AsPyObjectSteal(args[0]); - _Py_FALLTHROUGH; - case 0: - if (do_raise(tstate, exc, cause)) { - assert(oparg == 0); - monitor_reraise(tstate, frame, this_instr); - goto exception_unwind; - } - break; - default: - _PyErr_SetString(tstate, PyExc_SystemError, - "bad RAISE_VARARGS oparg"); - break; - } - if (true) { - stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); - goto error; + assert(oparg < 3); + PyObject *cause = oparg == 2 ? PyStackRef_AsPyObjectSteal(args[1]) : NULL; + PyObject *exc = oparg > 0 ? PyStackRef_AsPyObjectSteal(args[0]) : NULL; + stack_pointer += -oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = do_raise(tstate, exc, cause); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { + assert(oparg == 0); + _PyFrame_SetStackPointer(frame, stack_pointer); + monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); + goto exception_unwind; } + if (true) goto error; } TARGET(RERAISE) { @@ -6368,7 +6849,7 @@ _PyStackRef exc_st; exc_st = stack_pointer[-1]; values = &stack_pointer[-1 - oparg]; - PyObject *exc = PyStackRef_AsPyObjectBorrow(exc_st); + PyObject *exc = PyStackRef_AsPyObjectSteal(exc_st); assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]); @@ -6377,14 +6858,22 @@ assert(!_PyErr_Occurred(tstate)); } else { + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); + stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(exc); goto error; } } assert(exc && PyExceptionInstance_Check(exc)); - Py_INCREF(exc); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetRaisedException(tstate, exc); monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); goto exception_unwind; } @@ -6410,7 +6899,9 @@ uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK; uintptr_t code_version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version); if (code_version != global_version) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { goto error; } @@ -6433,7 +6924,9 @@ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); QSBR_QUIESCENT_STATE(tstate); \ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) goto error; } } @@ -6467,14 +6960,14 @@ // _LOAD_CONST { value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); - stack_pointer[0] = value; } // _RETURN_VALUE - retval = value; { + retval = value; #if TIER_ONE assert(frame != &entry_frame); #endif + _PyStackRef temp = retval; _PyFrame_SetStackPointer(frame, stack_pointer); assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); @@ -6482,9 +6975,9 @@ _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; _PyEval_FrameClearAndPop(tstate, dying); - LOAD_SP(); + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(frame->return_offset); - res = retval; + res = temp; LLTRACE_RESUME_FRAME(); } stack_pointer[0] = res; @@ -6500,10 +6993,10 @@ _PyStackRef res; assert(PyStackRef_FunctionCheck(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + _PyFrame_SetStackPointer(frame, stack_pointer); PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - if (gen == NULL) { - goto error; - } + stack_pointer = _PyFrame_GetStackPointer(frame); + if (gen == NULL) goto error; assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *gen_frame = &gen->gi_iframe; @@ -6513,12 +7006,12 @@ gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); - res = PyStackRef_FromPyObjectSteal((PyObject *)gen); _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); - LOAD_SP(); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal((PyObject *)gen); LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; @@ -6536,6 +7029,7 @@ #if TIER_ONE assert(frame != &entry_frame); #endif + _PyStackRef temp = retval; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -6545,9 +7039,9 @@ _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; _PyEval_FrameClearAndPop(tstate, dying); - LOAD_SP(); + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(frame->return_offset); - res = retval; + res = temp; LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; @@ -6566,14 +7060,16 @@ _PyStackRef v; _PyStackRef retval; // _SPECIALIZE_SEND - receiver = stack_pointer[-2]; { + receiver = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_Send(receiver, next_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(SEND); @@ -6581,8 +7077,8 @@ #endif /* ENABLE_SPECIALIZATION */ } // _SEND - v = stack_pointer[-1]; { + v = stack_pointer[-1]; PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); PyObject *retval_o; assert(frame != &entry_frame); @@ -6604,25 +7100,36 @@ DISPATCH_INLINED(gen_frame); } if (PyStackRef_Is(v, PyStackRef_None) && PyIter_Check(receiver_o)) { + _PyFrame_SetStackPointer(frame, stack_pointer); retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o); + stack_pointer = _PyFrame_GetStackPointer(frame); } else { + _PyFrame_SetStackPointer(frame, stack_pointer); retval_o = PyObject_CallMethodOneArg(receiver_o, &_Py_ID(send), PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); } if (retval_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); if (matches) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_MonitorRaise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); } + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyGen_FetchStopIterationValue(&retval_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (err == 0) { assert(retval_o != NULL); JUMPBY(oparg); } else { - goto error; + PyStackRef_CLOSE(v); + if (true) goto pop_1_error; } } PyStackRef_CLOSE(v); @@ -6647,9 +7154,9 @@ DEOPT_IF(tstate->interp->eval_frame, SEND); } // _SEND_GEN_FRAME - v = stack_pointer[-1]; - receiver = stack_pointer[-2]; { + v = stack_pointer[-1]; + receiver = stack_pointer[-2]; PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver); DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); @@ -6664,17 +7171,18 @@ gen_frame->previous = frame; } // _PUSH_FRAME - new_frame = gen_frame; { + new_frame = gen_frame; // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -6687,20 +7195,28 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(SETUP_ANNOTATIONS); - int err; PyObject *ann_dict; if (LOCALS() == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals found when setting up annotations"); + stack_pointer = _PyFrame_GetStackPointer(frame); if (true) goto error; } /* check if __annotations__ in locals()... */ - if (PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict) < 0) goto error; + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) goto error; if (ann_dict == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); ann_dict = PyDict_New(); + stack_pointer = _PyFrame_GetStackPointer(frame); if (ann_dict == NULL) goto error; + _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), ann_dict); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(ann_dict); if (err) goto error; } @@ -6718,8 +7234,10 @@ _PyStackRef v; v = stack_pointer[-1]; set = stack_pointer[-2 - (oparg-1)]; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PySet_Add(PyStackRef_AsPyObjectBorrow(set), PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); if (err) goto pop_1_error; stack_pointer += -1; @@ -6732,41 +7250,20 @@ next_instr += 1; INSTRUCTION_STATS(SET_FUNCTION_ATTRIBUTE); _PyStackRef attr_st; - _PyStackRef func_st; - func_st = stack_pointer[-1]; + _PyStackRef func_in; + _PyStackRef func_out; + func_in = stack_pointer[-1]; attr_st = stack_pointer[-2]; - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); - PyObject *attr = PyStackRef_AsPyObjectBorrow(attr_st); + PyObject *func = PyStackRef_AsPyObjectBorrow(func_in); + PyObject *attr = PyStackRef_AsPyObjectSteal(attr_st); + func_out = func_in; assert(PyFunction_Check(func)); - PyFunctionObject *func_obj = (PyFunctionObject *)func; - switch(oparg) { - case MAKE_FUNCTION_CLOSURE: - assert(func_obj->func_closure == NULL); - func_obj->func_closure = attr; - break; - case MAKE_FUNCTION_ANNOTATIONS: - assert(func_obj->func_annotations == NULL); - func_obj->func_annotations = attr; - break; - case MAKE_FUNCTION_KWDEFAULTS: - assert(PyDict_CheckExact(attr)); - assert(func_obj->func_kwdefaults == NULL); - func_obj->func_kwdefaults = attr; - break; - case MAKE_FUNCTION_DEFAULTS: - assert(PyTuple_CheckExact(attr)); - assert(func_obj->func_defaults == NULL); - func_obj->func_defaults = attr; - break; - case MAKE_FUNCTION_ANNOTATE: - assert(PyCallable_Check(attr)); - assert(func_obj->func_annotate == NULL); - func_obj->func_annotate = attr; - break; - default: - Py_UNREACHABLE(); - } - stack_pointer[-2] = func_st; + size_t offset = _Py_FunctionAttributeOffsets[oparg]; + assert(offset != 0); + PyObject **ptr = (PyObject **)(((char *)func) + offset); + assert(*ptr == NULL); + *ptr = attr; + stack_pointer[-2] = func_out; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -6780,8 +7277,10 @@ _PyStackRef iterable; iterable = stack_pointer[-1]; set = stack_pointer[-2 - (oparg-1)]; + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PySet_Update(PyStackRef_AsPyObjectBorrow(set), PyStackRef_AsPyObjectBorrow(iterable)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); if (err < 0) goto pop_1_error; stack_pointer += -1; @@ -6799,15 +7298,17 @@ _PyStackRef owner; _PyStackRef v; // _SPECIALIZE_STORE_ATTR - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_StoreAttr(owner, next_instr, name); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(STORE_ATTR); @@ -6816,11 +7317,13 @@ } /* Skip 3 cache entries */ // _STORE_ATTR - v = stack_pointer[-2]; { + v = stack_pointer[-2]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); PyStackRef_CLOSE(owner); if (err) goto pop_2_error; @@ -6839,8 +7342,8 @@ _PyStackRef value; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); @@ -6855,8 +7358,8 @@ DEOPT_IF(_PyObject_InlineValues(owner_o)->valid == 0, STORE_ATTR); } // _STORE_ATTR_INSTANCE_VALUE - value = stack_pointer[-2]; { + value = stack_pointer[-2]; uint16_t offset = read_u16(&this_instr[4].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); STAT_INC(STORE_ATTR, hit); @@ -6888,16 +7391,16 @@ _PyStackRef value; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); } // _STORE_ATTR_SLOT - value = stack_pointer[-2]; { + value = stack_pointer[-2]; uint16_t index = read_u16(&this_instr[4].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); char *addr = (char *)owner_o + index; @@ -6921,16 +7424,16 @@ _PyStackRef value; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); } // _STORE_ATTR_WITH_HINT - value = stack_pointer[-2]; { + value = stack_pointer[-2]; uint16_t hint = read_u16(&this_instr[4].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); @@ -6949,7 +7452,9 @@ } old_value = ep->me_value; PyDict_WatchEvent event = old_value == NULL ? PyDict_EVENT_ADDED : PyDict_EVENT_MODIFIED; + _PyFrame_SetStackPointer(frame, stack_pointer); _PyDict_NotifyEvent(tstate->interp, event, dict, name, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); ep->me_value = PyStackRef_AsPyObjectSteal(value); // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, // when dict only holds the strong reference to value in ep->me_value. @@ -6969,7 +7474,9 @@ _PyStackRef v; v = stack_pointer[-1]; PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); + _PyFrame_SetStackPointer(frame, stack_pointer); PyCell_SetTakeRef(cell, PyStackRef_AsPyObjectSteal(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -7026,7 +7533,9 @@ _PyStackRef v; v = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); if (err) goto pop_1_error; stack_pointer += -1; @@ -7044,15 +7553,23 @@ PyObject *ns = LOCALS(); int err; if (ns == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); if (true) goto pop_1_error; } - if (PyDict_CheckExact(ns)) - err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); - else - err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + if (PyDict_CheckExact(ns)) { + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + } PyStackRef_CLOSE(v); if (err) goto pop_1_error; stack_pointer += -1; @@ -7076,20 +7593,28 @@ #endif /* ENABLE_SPECIALIZATION */ } // _STORE_SLICE - stop = stack_pointer[-1]; - start = stack_pointer[-2]; - container = stack_pointer[-3]; - v = stack_pointer[-4]; { + stop = stack_pointer[-1]; + start = stack_pointer[-2]; + container = stack_pointer[-3]; + v = stack_pointer[-4]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), PyStackRef_AsPyObjectSteal(stop)); + stack_pointer = _PyFrame_GetStackPointer(frame); int err; if (slice == NULL) { err = 1; } else { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(slice); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } PyStackRef_CLOSE(v); PyStackRef_CLOSE(container); @@ -7111,15 +7636,17 @@ _PyStackRef sub; _PyStackRef v; // _SPECIALIZE_STORE_SUBSCR - sub = stack_pointer[-1]; - container = stack_pointer[-2]; { + sub = stack_pointer[-1]; + container = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_StoreSubscr(container, sub, next_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(STORE_SUBSCR); @@ -7127,10 +7654,12 @@ #endif /* ENABLE_SPECIALIZATION */ } // _STORE_SUBSCR - v = stack_pointer[-3]; { + v = stack_pointer[-3]; /* container[sub] = v */ + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectBorrow(sub), PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(v); PyStackRef_CLOSE(container); PyStackRef_CLOSE(sub); @@ -7156,9 +7685,11 @@ PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, PyStackRef_AsPyObjectSteal(sub), PyStackRef_AsPyObjectSteal(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(dict_st); if (err) goto pop_3_error; stack_pointer += -3; @@ -7203,13 +7734,17 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(SWAP); - _PyStackRef bottom; - _PyStackRef top; - top = stack_pointer[-1]; - bottom = stack_pointer[-2 - (oparg-2)]; + _PyStackRef bottom_in; + _PyStackRef top_in; + _PyStackRef top_out; + _PyStackRef bottom_out; + top_in = stack_pointer[-1]; + bottom_in = stack_pointer[-2 - (oparg-2)]; + bottom_out = bottom_in; + top_out = top_in; assert(oparg >= 2); - stack_pointer[-2 - (oparg-2)] = top; - stack_pointer[-1] = bottom; + stack_pointer[-2 - (oparg-2)] = top_out; + stack_pointer[-1] = bottom_out; DISPATCH(); } @@ -7223,14 +7758,16 @@ _PyStackRef value; _PyStackRef res; // _SPECIALIZE_TO_BOOL - value = stack_pointer[-1]; { + value = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_ToBool(value, next_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(TO_BOOL); @@ -7240,7 +7777,9 @@ /* Skip 2 cache entries */ // _TO_BOOL { + _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (err < 0) goto pop_1_error; res = err ? PyStackRef_True : PyStackRef_False; @@ -7259,16 +7798,16 @@ _PyStackRef res; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION - owner = stack_pointer[-1]; { + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, TO_BOOL); } // _REPLACE_WITH_TRUE - value = owner; { + value = owner; PyStackRef_CLOSE(value); res = PyStackRef_True; } @@ -7385,7 +7924,9 @@ _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (res_o == NULL) goto pop_1_error; res = PyStackRef_FromPyObjectSteal(res_o); @@ -7400,7 +7941,9 @@ _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; + _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); if (res_o == NULL) goto pop_1_error; res = PyStackRef_FromPyObjectSteal(res_o); @@ -7431,7 +7974,9 @@ seq = stack_pointer[-1]; right = &stack_pointer[(oparg & 0xFF)]; _PyStackRef *top = right + (oparg >> 8); + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(seq); if (res == 0) goto pop_1_error; stack_pointer += (oparg & 0xFF) + (oparg >> 8); @@ -7449,14 +7994,16 @@ _PyStackRef seq; _PyStackRef *output; // _SPECIALIZE_UNPACK_SEQUENCE - seq = stack_pointer[-1]; { + seq = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_Specialize_UnpackSequence(seq, next_instr, oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(UNPACK_SEQUENCE); @@ -7469,7 +8016,9 @@ { output = &stack_pointer[-1]; _PyStackRef *top = output + oparg; + _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top); + stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(seq); if (res == 0) goto pop_1_error; } @@ -7542,10 +8091,10 @@ DEOPT_IF(PyTuple_GET_SIZE(seq_o) != 2, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); - stack_pointer[0] = val0; val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); - stack_pointer[-1] = val1; PyStackRef_CLOSE(seq); + stack_pointer[-1] = val1; + stack_pointer[0] = val0; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); @@ -7589,8 +8138,10 @@ (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); + _PyFrame_SetStackPointer(frame, stack_pointer); res = PyStackRef_FromPyObjectSteal(PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL)); + stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(res)) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -7616,6 +8167,7 @@ assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; + _PyStackRef temp = retval; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -7629,113 +8181,19 @@ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || + _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); #endif + stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - LOAD_SP(); - value = retval; + value = temp; LLTRACE_RESUME_FRAME(); stack_pointer[0] = value; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } - - TARGET(_DO_CALL_FUNCTION_EX) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; - (void)this_instr; - next_instr += 1; - INSTRUCTION_STATS(_DO_CALL_FUNCTION_EX); - _PyStackRef func_st; - _PyStackRef callargs_st; - _PyStackRef kwargs_st = PyStackRef_NULL; - _PyStackRef result; - if (oparg & 1) { kwargs_st = stack_pointer[-(oparg & 1)]; } - callargs_st = stack_pointer[-1 - (oparg & 1)]; - func_st = stack_pointer[-3 - (oparg & 1)]; - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); - PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); - PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); - // DICT_MERGE is called before this opcode if there are kwargs. - // It converts all dict subtypes in kwargs into regular dicts. - assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - if (!PyTuple_CheckExact(callargs)) { - int err = check_args_iterable(tstate, func, callargs); - if (err < 0) { - goto error; - } - PyObject *tuple = PySequence_Tuple(callargs); - if (tuple == NULL) { - goto error; - } - PyStackRef_CLOSE(callargs_st); - callargs_st = PyStackRef_FromPyObjectSteal(tuple); - callargs = tuple; - } - assert(PyTuple_CheckExact(callargs)); - EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); - if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { - PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? - PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; - int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_CALL, - frame, this_instr, func, arg); - if (err) goto error; - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); - if (!PyFunction_Check(func) && !PyMethod_Check(func)) { - if (PyStackRef_IsNull(result)) { - _Py_call_instrumentation_exc2( - tstate, PY_MONITORING_EVENT_C_RAISE, - frame, this_instr, func, arg); - } - else { - int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_C_RETURN, - frame, this_instr, func, arg); - if (err < 0) { - PyStackRef_CLEAR(result); - } - } - } - } - else { - if (Py_TYPE(func) == &PyFunction_Type && - tstate->interp->eval_frame == NULL && - ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { - assert(PyTuple_CheckExact(callargs)); - Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); - int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; - PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( - tstate, func_st, locals, - nargs, callargs, kwargs, frame); - // Need to manually shrink the stack since we exit with DISPATCH_INLINED. - STACK_SHRINK(oparg + 3); - if (new_frame == NULL) { - goto error; - } - assert(next_instr - this_instr == 1); - frame->return_offset = 1; - DISPATCH_INLINED(new_frame); - } - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); - } - PyStackRef_CLOSE(func_st); - PyStackRef_CLOSE(callargs_st); - PyStackRef_XCLOSE(kwargs_st); - assert(PyStackRef_AsPyObjectBorrow(PEEK(2 + (oparg & 1))) == NULL); - if (PyStackRef_IsNull(result)) { - stack_pointer += -3 - (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); - goto error; - } - stack_pointer[-3 - (oparg & 1)] = result; - stack_pointer += -2 - (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } #undef TIER_ONE diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 49f01ca2932ee2..3fc9d3118d59ad 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -115,7 +115,7 @@ static void *opcode_targets[256] = { &&TARGET_UNPACK_EX, &&TARGET_UNPACK_SEQUENCE, &&TARGET_YIELD_VALUE, - &&TARGET__DO_CALL_FUNCTION_EX, + &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index bf8f0753f800c0..c73b632d1afdd7 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -182,7 +182,9 @@ dummy_func(void) { res = sym_new_type(ctx, &PyFloat_Type); } } - res = sym_new_unknown(ctx); + else { + res = sym_new_unknown(ctx); + } } op(_BINARY_OP_ADD_INT, (left, right -- res)) { @@ -448,8 +450,10 @@ dummy_func(void) { top = bottom; } - op(_SWAP, (bottom, unused[oparg-2], top -- - top, unused[oparg-2], bottom)) { + op(_SWAP, (bottom_in, unused[oparg-2], top_in -- + top_out, unused[oparg-2], bottom_out)) { + bottom_out = bottom_in; + top_out = top_in; } op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, null if (oparg & 1))) { @@ -479,9 +483,7 @@ dummy_func(void) { op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { (void)owner; attr = sym_new_not_null(ctx); - if (oparg & 1) { - self_or_null = sym_new_unknown(ctx); - } + self_or_null = sym_new_unknown(ctx); } op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) { @@ -570,7 +572,6 @@ dummy_func(void) { op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { int argcount = oparg; - (void)callable; PyCodeObject *co = NULL; @@ -647,11 +648,10 @@ dummy_func(void) { } op(_RETURN_VALUE, (retval -- res)) { - SYNC_SP(); + SAVE_STACK(); ctx->frame->stack_pointer = stack_pointer; frame_pop(ctx); stack_pointer = ctx->frame->stack_pointer; - res = retval; /* Stack space handling */ assert(corresponding_check_stack == NULL); @@ -666,6 +666,8 @@ dummy_func(void) { // might be impossible, but bailing is still safe ctx->done = true; } + RELOAD_STACK(); + res = retval; } op(_RETURN_GENERATOR, ( -- res)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index fc0c0eff01d4c1..ae532fd27769ab 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -93,9 +93,9 @@ } case _END_SEND: { - _Py_UopsSymbol *value; - value = sym_new_not_null(ctx); - stack_pointer[-2] = value; + _Py_UopsSymbol *val; + val = sym_new_not_null(ctx); + stack_pointer[-2] = val; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -630,7 +630,6 @@ ctx->frame->stack_pointer = stack_pointer; frame_pop(ctx); stack_pointer = ctx->frame->stack_pointer; - res = retval; /* Stack space handling */ assert(corresponding_check_stack == NULL); assert(co != NULL); @@ -643,6 +642,7 @@ // might be impossible, but bailing is still safe ctx->done = true; } + res = retval; stack_pointer[0] = res; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -832,9 +832,7 @@ _Py_UopsSymbol **res; _Py_UopsSymbol *null = NULL; res = &stack_pointer[0]; - for (int _i = 1; --_i >= 0;) { - res[_i] = sym_new_not_null(ctx); - } + res[0] = sym_new_not_null(ctx); null = sym_new_null(ctx); if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -1021,9 +1019,7 @@ owner = stack_pointer[-1]; (void)owner; attr = sym_new_not_null(ctx); - if (oparg & 1) { - self_or_null = sym_new_unknown(ctx); - } + self_or_null = sym_new_unknown(ctx); stack_pointer[-1] = attr; if (oparg & 1) stack_pointer[0] = self_or_null; stack_pointer += (oparg & 1); @@ -1114,11 +1110,17 @@ PyModuleObject *mod = (PyModuleObject *)sym_get_const(owner); assert(PyModule_CheckExact(mod)); PyObject *dict = mod->md_dict; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); PyObject *res = convert_global_to_const(this_instr, dict); if (res != NULL) { this_instr[-1].opcode = _POP_TOP; attr = sym_new_const(ctx, res); } + stack_pointer += -(oparg & 1); + assert(WITHIN_STACK_BOUNDS()); } if (attr == NULL) { /* No conversion made. We don't know what `attr` is. */ @@ -1239,7 +1241,11 @@ res = sym_new_type(ctx, &PyBool_Type); } else { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); res = _Py_uop_sym_new_not_null(ctx); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); } stack_pointer[-2] = res; stack_pointer += -1; @@ -1659,12 +1665,13 @@ /* _MONITOR_CALL is not a viable micro-op for tier 2 */ case _PY_FRAME_GENERAL: { - _Py_UopsSymbol **args; _Py_UopsSymbol *self_or_null; _Py_UopsSymbol *callable; _Py_UOpsAbstractFrame *new_frame; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); (void)(self_or_null); (void)(callable); PyCodeObject *co = NULL; @@ -1675,8 +1682,8 @@ break; } new_frame = frame_new(ctx, co, 0, NULL, 0); - stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame; - stack_pointer += -1 - oparg; + stack_pointer[0] = (_Py_UopsSymbol *)new_frame; + stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); break; } @@ -1690,14 +1697,12 @@ } case _EXPAND_METHOD: { - _Py_UopsSymbol *method; + _Py_UopsSymbol **method; _Py_UopsSymbol **self; + method = &stack_pointer[-2 - oparg]; self = &stack_pointer[-1 - oparg]; - method = sym_new_not_null(ctx); - for (int _i = 1; --_i >= 0;) { - self[_i] = sym_new_not_null(ctx); - } - stack_pointer[-2 - oparg] = method; + method[0] = sym_new_not_null(ctx); + self[0] = sym_new_not_null(ctx); break; } @@ -1774,6 +1779,8 @@ (void)callable; PyCodeObject *co = NULL; assert((this_instr + 2)->opcode == _PUSH_FRAME); + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); co = get_code_with_logging((this_instr + 2)); if (co == NULL) { ctx->done = true; @@ -1791,8 +1798,8 @@ } else { new_frame = frame_new(ctx, co, 0, NULL, 0); } - stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame; - stack_pointer += -1 - oparg; + stack_pointer[0] = (_Py_UopsSymbol *)new_frame; + stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); break; } @@ -1825,9 +1832,11 @@ if (first_valid_check_stack == NULL) { first_valid_check_stack = corresponding_check_stack; } - else if (corresponding_check_stack) { - // delete all but the first valid _CHECK_STACK_SPACE - corresponding_check_stack->opcode = _NOP; + else { + if (corresponding_check_stack) { + // delete all but the first valid _CHECK_STACK_SPACE + corresponding_check_stack->opcode = _NOP; + } } corresponding_check_stack = NULL; break; @@ -2005,6 +2014,24 @@ /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 */ + case _MAYBE_EXPAND_METHOD_KW: { + _Py_UopsSymbol **func; + _Py_UopsSymbol **maybe_self; + _Py_UopsSymbol **args; + _Py_UopsSymbol *kwnames_out; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; + args = &stack_pointer[-1 - oparg]; + func[0] = sym_new_not_null(ctx); + maybe_self[0] = sym_new_not_null(ctx); + for (int _i = oparg; --_i >= 0;) { + args[_i] = sym_new_not_null(ctx); + } + kwnames_out = sym_new_not_null(ctx); + stack_pointer[-1] = kwnames_out; + break; + } + /* _DO_CALL_KW is not a viable micro-op for tier 2 */ case _PY_FRAME_KW: { @@ -2038,17 +2065,12 @@ } case _EXPAND_METHOD_KW: { - _Py_UopsSymbol *method; + _Py_UopsSymbol **method; _Py_UopsSymbol **self; - _Py_UopsSymbol *kwnames; + method = &stack_pointer[-3 - oparg]; self = &stack_pointer[-2 - oparg]; - method = sym_new_not_null(ctx); - for (int _i = 1; --_i >= 0;) { - self[_i] = sym_new_not_null(ctx); - } - kwnames = sym_new_not_null(ctx); - stack_pointer[-3 - oparg] = method; - stack_pointer[-1] = kwnames; + method[0] = sym_new_not_null(ctx); + self[0] = sym_new_not_null(ctx); break; } @@ -2067,7 +2089,17 @@ /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ - /* __DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ + case _MAKE_CALLARGS_A_TUPLE: { + _Py_UopsSymbol *tuple; + _Py_UopsSymbol *kwargs_out = NULL; + tuple = sym_new_not_null(ctx); + kwargs_out = sym_new_not_null(ctx); + stack_pointer[-1 - (oparg & 1)] = tuple; + if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_out; + break; + } + + /* _DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ case _MAKE_FUNCTION: { _Py_UopsSymbol *func; @@ -2077,9 +2109,9 @@ } case _SET_FUNCTION_ATTRIBUTE: { - _Py_UopsSymbol *func_st; - func_st = sym_new_not_null(ctx); - stack_pointer[-2] = func_st; + _Py_UopsSymbol *func_out; + func_out = sym_new_not_null(ctx); + stack_pointer[-2] = func_out; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -2098,14 +2130,14 @@ assert(framesize > 0); assert(framesize <= curr_space); curr_space -= framesize; + stack_pointer[0] = res; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); co = get_code(this_instr); if (co == NULL) { // might be impossible, but bailing is still safe ctx->done = true; } - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); break; } @@ -2174,7 +2206,9 @@ res = sym_new_type(ctx, &PyFloat_Type); } } - res = sym_new_unknown(ctx); + else { + res = sym_new_unknown(ctx); + } stack_pointer[-2] = res; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -2182,12 +2216,16 @@ } case _SWAP: { - _Py_UopsSymbol *top; - _Py_UopsSymbol *bottom; - top = stack_pointer[-1]; - bottom = stack_pointer[-2 - (oparg-2)]; - stack_pointer[-2 - (oparg-2)] = top; - stack_pointer[-1] = bottom; + _Py_UopsSymbol *top_in; + _Py_UopsSymbol *bottom_in; + _Py_UopsSymbol *top_out; + _Py_UopsSymbol *bottom_out; + top_in = stack_pointer[-1]; + bottom_in = stack_pointer[-2 - (oparg-2)]; + bottom_out = bottom_in; + top_out = top_in; + stack_pointer[-2 - (oparg-2)] = top_out; + stack_pointer[-1] = bottom_out; break; } @@ -2213,7 +2251,11 @@ if (sym_is_const(flag)) { PyObject *value = sym_get_const(flag); assert(value != NULL); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); eliminate_pop_guard(this_instr, value != Py_True); + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); } stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -2226,7 +2268,11 @@ if (sym_is_const(flag)) { PyObject *value = sym_get_const(flag); assert(value != NULL); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); eliminate_pop_guard(this_instr, value != Py_False); + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); } stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -2239,14 +2285,22 @@ if (sym_is_const(flag)) { PyObject *value = sym_get_const(flag); assert(value != NULL); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); eliminate_pop_guard(this_instr, !Py_IsNone(value)); } - else if (sym_has_type(flag)) { - assert(!sym_matches_type(flag, &_PyNone_Type)); - eliminate_pop_guard(this_instr, true); + else { + if (sym_has_type(flag)) { + assert(!sym_matches_type(flag, &_PyNone_Type)); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + eliminate_pop_guard(this_instr, true); + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); break; } @@ -2256,14 +2310,22 @@ if (sym_is_const(flag)) { PyObject *value = sym_get_const(flag); assert(value != NULL); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); eliminate_pop_guard(this_instr, Py_IsNone(value)); } - else if (sym_has_type(flag)) { - assert(!sym_matches_type(flag, &_PyNone_Type)); - eliminate_pop_guard(this_instr, false); + else { + if (sym_has_type(flag)) { + assert(!sym_matches_type(flag, &_PyNone_Type)); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + eliminate_pop_guard(this_instr, false); + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); break; } diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index a4ce207703edcd..9c2981a68ac909 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -1,13 +1,13 @@ -from dataclasses import dataclass +from dataclasses import dataclass, field +import itertools import lexer import parser import re from typing import Optional - @dataclass class Properties: - escapes: bool + escaping_calls: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] error_with_pop: bool error_without_pop: bool deopts: bool @@ -29,14 +29,21 @@ class Properties: needs_prev: bool = False def dump(self, indent: str) -> None: - print(indent, end="") - text = ", ".join([f"{key}: {value}" for (key, value) in self.__dict__.items()]) + simple_properties = self.__dict__.copy() + del simple_properties["escaping_calls"] + text = "escaping_calls:\n" + for tkns in self.escaping_calls.values(): + text += f"{indent} {tkns}\n" + text += ", ".join([f"{key}: {value}" for (key, value) in simple_properties.items()]) print(indent, text, sep="") @staticmethod def from_list(properties: list["Properties"]) -> "Properties": + escaping_calls: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] = {} + for p in properties: + escaping_calls.update(p.escaping_calls) return Properties( - escapes=any(p.escapes for p in properties), + escaping_calls=escaping_calls, error_with_pop=any(p.error_with_pop for p in properties), error_without_pop=any(p.error_without_pop for p in properties), deopts=any(p.deopts for p in properties), @@ -59,9 +66,12 @@ def from_list(properties: list["Properties"]) -> "Properties": def infallible(self) -> bool: return not self.error_with_pop and not self.error_without_pop + @property + def escapes(self) -> bool: + return bool(self.escaping_calls) SKIP_PROPERTIES = Properties( - escapes=False, + escaping_calls={}, error_with_pop=False, error_without_pop=False, deopts=False, @@ -156,6 +166,7 @@ class Uop: stack: StackEffect caches: list[CacheEntry] deferred_refs: dict[lexer.Token, str | None] + output_stores: list[lexer.Token] body: list[lexer.Token] properties: Properties _size: int = -1 @@ -322,11 +333,24 @@ def analyze_stack( ] # Mark variables with matching names at the base of the stack as "peek" modified = False - for input, output in zip(inputs, outputs): - if input.name == output.name and not modified: - input.peek = output.peek = True + input_names: dict[str, lexer.Token] = { i.name : i.first_token for i in op.inputs if i.name != "unused" } + for input, output in itertools.zip_longest(inputs, outputs): + if output is None: + pass + elif input is None: + if output.name in input_names: + raise analysis_error( + f"Reuse of variable '{output.name}' at different stack location", + input_names[output.name]) + elif input.name == output.name: + if not modified: + input.peek = output.peek = True else: modified = True + if output.name in input_names: + raise analysis_error( + f"Reuse of variable '{output.name}' at different stack location", + input_names[output.name]) if isinstance(op, parser.InstDef): output_names = [out.name for out in outputs] for input in inputs: @@ -354,21 +378,46 @@ def analyze_caches(inputs: list[parser.InputEffect]) -> list[CacheEntry]: return [CacheEntry(i.name, int(i.size)) for i in caches] +def find_assignment_target(node: parser.InstDef, idx: int) -> list[lexer.Token]: + """Find the tokens that make up the left-hand side of an assignment""" + offset = 0 + for tkn in reversed(node.block.tokens[: idx]): + if tkn.kind in {"SEMI", "LBRACE", "RBRACE"}: + return node.block.tokens[idx - offset : idx] + offset += 1 + return [] + + +def find_stores_outputs(node: parser.InstDef) -> list[lexer.Token]: + res: list[lexer.Token] = [] + outnames = { out.name for out in node.outputs } + innames = { out.name for out in node.inputs } + for idx, tkn in enumerate(node.block.tokens): + if tkn.kind == "AND": + name = node.block.tokens[idx+1] + if name.text in outnames: + res.append(name) + if tkn.kind != "EQUALS": + continue + lhs = find_assignment_target(node, idx) + assert lhs + while lhs and lhs[0].kind == "COMMENT": + lhs = lhs[1:] + if len(lhs) != 1 or lhs[0].kind != "IDENTIFIER": + continue + name = lhs[0] + if name.text in innames: + raise analysis_error(f"Cannot assign to input variable '{name.text}'", name) + if name.text in outnames: + res.append(name) + return res + def analyze_deferred_refs(node: parser.InstDef) -> dict[lexer.Token, str | None]: """Look for PyStackRef_FromPyObjectNew() calls""" - def find_assignment_target(idx: int) -> list[lexer.Token]: - """Find the tokens that make up the left-hand side of an assignment""" - offset = 1 - for tkn in reversed(node.block.tokens[: idx - 1]): - if tkn.kind == "SEMI" or tkn.kind == "LBRACE" or tkn.kind == "RBRACE": - return node.block.tokens[idx - offset : idx - 1] - offset += 1 - return [] - def in_frame_push(idx: int) -> bool: for tkn in reversed(node.block.tokens[: idx - 1]): - if tkn.kind == "SEMI" or tkn.kind == "LBRACE" or tkn.kind == "RBRACE": + if tkn.kind in {"SEMI", "LBRACE", "RBRACE"}: return False if tkn.kind == "IDENTIFIER" and tkn.text == "_PyFrame_PushUnchecked": return True @@ -386,7 +435,7 @@ def in_frame_push(idx: int) -> bool: continue raise analysis_error("Expected '=' before PyStackRef_FromPyObjectNew", tkn) - lhs = find_assignment_target(idx) + lhs = find_assignment_target(node, idx - 1) if len(lhs) == 0: raise analysis_error( "PyStackRef_FromPyObjectNew() must be assigned to an output", tkn @@ -406,9 +455,13 @@ def in_frame_push(idx: int) -> bool: ) name = lhs[0].text - if not any(var.name == name for var in node.outputs): + match = ( + any(var.name == name for var in node.inputs) + or any(var.name == name for var in node.outputs) + ) + if not match: raise analysis_error( - f"PyStackRef_FromPyObjectNew() must be assigned to an output, not '{name}'", + f"PyStackRef_FromPyObjectNew() must be assigned to an input or output, not '{name}'", tkn, ) @@ -461,125 +514,203 @@ def has_error_without_pop(op: parser.InstDef) -> bool: NON_ESCAPING_FUNCTIONS = ( - "PyStackRef_FromPyObjectSteal", + "PyCFunction_GET_FLAGS", + "PyCFunction_GET_FUNCTION", + "PyCFunction_GET_SELF", + "PyCell_GetRef", + "PyCell_New", + "PyCell_SwapTakeRef", + "PyExceptionInstance_Class", + "PyException_GetCause", + "PyException_GetContext", + "PyException_GetTraceback", + "PyFloat_AS_DOUBLE", + "PyFloat_FromDouble", + "PyFunction_GET_CODE", + "PyFunction_GET_GLOBALS", + "PyList_GET_ITEM", + "PyList_GET_SIZE", + "PyList_SET_ITEM", + "PyLong_AsLong", + "PyLong_FromLong", + "PyLong_FromSsize_t", + "PySlice_New", "PyStackRef_AsPyObjectBorrow", + "PyStackRef_AsPyObjectNew", "PyStackRef_AsPyObjectSteal", + "PyStackRef_CLEAR", "PyStackRef_CLOSE", "PyStackRef_DUP", - "PyStackRef_CLEAR", + "PyStackRef_False", + "PyStackRef_FromPyObjectImmortal", + "PyStackRef_FromPyObjectNew", + "PyStackRef_FromPyObjectSteal", + "PyStackRef_Is", "PyStackRef_IsNull", + "PyStackRef_None", "PyStackRef_TYPE", - "PyStackRef_False", "PyStackRef_True", - "PyStackRef_None", - "PyStackRef_Is", - "PyStackRef_FromPyObjectNew", - "PyStackRef_AsPyObjectNew", - "PyStackRef_FromPyObjectImmortal", - "Py_INCREF", - "_PyManagedDictPointer_IsValues", - "_PyObject_GetManagedDict", - "_PyObject_ManagedDictPointer", - "_PyObject_InlineValues", - "_PyDictValues_AddToInsertionOrder", - "Py_DECREF", - "Py_XDECREF", - "_Py_DECREF_SPECIALIZED", - "DECREF_INPUTS_AND_REUSE_FLOAT", - "PyUnicode_Append", - "_PyLong_IsZero", - "Py_SIZE", - "Py_TYPE", - "PyList_GET_ITEM", - "PyList_SET_ITEM", "PyTuple_GET_ITEM", - "PyList_GET_SIZE", "PyTuple_GET_SIZE", + "PyType_HasFeature", + "PyUnicode_Append", + "PyUnicode_Concat", + "PyUnicode_GET_LENGTH", + "PyUnicode_READ_CHAR", "Py_ARRAY_LENGTH", + "Py_CLEAR", + "Py_DECREF", + "Py_FatalError", + "Py_INCREF", + "Py_IS_TYPE", + "Py_NewRef", + "Py_REFCNT", + "Py_SIZE", + "Py_TYPE", + "Py_UNREACHABLE", "Py_Unicode_GET_LENGTH", - "PyUnicode_READ_CHAR", - "_Py_SINGLETON", - "PyUnicode_GET_LENGTH", - "_PyLong_IsCompact", - "_PyLong_IsNonNegativeCompact", + "Py_XDECREF", + "_PyCode_CODE", + "_PyDictValues_AddToInsertionOrder", + "_PyErr_Occurred", + "_PyEval_FrameClearAndPop", + "_PyFrame_GetCode", + "_PyFrame_IsIncomplete", + "_PyFrame_PushUnchecked", + "_PyFrame_SetStackPointer", + "_PyFrame_StackPush", + "_PyFunction_SetVersion", + "_PyGen_GetGeneratorFromFrame", + "_PyInterpreterState_GET", + "_PyList_AppendTakeRef", + "_PyList_FromStackRefSteal", + "_PyList_ITEMS", + "_PyLong_Add", "_PyLong_CompactValue", "_PyLong_DigitCount", - "_Py_NewRef", - "_Py_IsImmortal", - "PyLong_FromLong", - "_Py_STR", - "_PyLong_Add", + "_PyLong_IsCompact", + "_PyLong_IsNonNegativeCompact", + "_PyLong_IsZero", "_PyLong_Multiply", "_PyLong_Subtract", - "Py_NewRef", - "_PyList_ITEMS", - "_PyTuple_ITEMS", - "_PyList_AppendTakeRef", - "_Py_atomic_load_uintptr_relaxed", - "_PyFrame_GetCode", + "_PyManagedDictPointer_IsValues", + "_PyObject_GC_IS_TRACKED", + "_PyObject_GC_MAY_BE_TRACKED", + "_PyObject_GC_TRACK", + "_PyObject_GetManagedDict", + "_PyObject_InlineValues", + "_PyObject_ManagedDictPointer", "_PyThreadState_HasStackSpace", - "_PyUnicode_Equal", - "_PyFrame_SetStackPointer", + "_PyTuple_FromArraySteal", + "_PyTuple_FromStackRefSteal", + "_PyTuple_ITEMS", "_PyType_HasFeature", - "PyUnicode_Concat", - "PySlice_New", + "_PyType_NewManagedObject", + "_PyUnicode_Equal", + "_PyUnicode_JoinArray", + "_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY", + "_Py_DECREF_NO_DEALLOC", + "_Py_DECREF_SPECIALIZED", + "_Py_EnterRecursiveCallTstateUnchecked", + "_Py_ID", + "_Py_IsImmortal", + "_Py_IsImmortalLoose", "_Py_LeaveRecursiveCallPy", - "CALL_STAT_INC", - "STAT_INC", + "_Py_LeaveRecursiveCallTstate", + "_Py_NewRef", + "_Py_SINGLETON", + "_Py_STR", + "_Py_atomic_load_uintptr_relaxed", + "_Py_set_eval_breaker_bit", + "advance_backoff_counter", + "assert", + "backoff_counter_triggers", + "initial_temperature_backoff_counter", "maybe_lltrace_resume_frame", - "_PyUnicode_JoinArray", - "_PyEval_FrameClearAndPop", - "_PyFrame_StackPush", - "PyCell_New", - "PyFloat_AS_DOUBLE", - "_PyFrame_PushUnchecked", - "Py_FatalError", - "STACKREFS_TO_PYOBJECTS", - "STACKREFS_TO_PYOBJECTS_CLEANUP", - "CONVERSION_FAILED", - "_PyList_FromStackRefSteal", - "_PyTuple_FromArraySteal", - "_PyTuple_FromStackRefSteal", - "_Py_set_eval_breaker_bit" + "restart_backoff_counter", ) -ESCAPING_FUNCTIONS = ( - "import_name", - "import_from", -) - - -def makes_escaping_api_call(instr: parser.InstDef) -> bool: - if "CALL_INTRINSIC" in instr.name: - return True - if instr.name == "_BINARY_OP": - return True - tkns = iter(instr.tokens) - for tkn in tkns: - if tkn.kind != lexer.IDENTIFIER: - continue +def find_stmt_start(node: parser.InstDef, idx: int) -> lexer.Token: + assert idx < len(node.block.tokens) + while True: + tkn = node.block.tokens[idx-1] + if tkn.kind in {"SEMI", "LBRACE", "RBRACE"}: + break + idx -= 1 + assert idx > 0 + while node.block.tokens[idx].kind == "COMMENT": + idx += 1 + return node.block.tokens[idx] + + +def find_stmt_end(node: parser.InstDef, idx: int) -> lexer.Token: + assert idx < len(node.block.tokens) + while True: + idx += 1 + tkn = node.block.tokens[idx] + if tkn.kind == "SEMI": + return node.block.tokens[idx+1] + +def check_escaping_calls(instr: parser.InstDef, escapes: dict[lexer.Token, tuple[lexer.Token, lexer.Token]]) -> None: + calls = {escapes[t][0] for t in escapes} + in_if = 0 + tkn_iter = iter(instr.block.tokens) + for tkn in tkn_iter: + if tkn.kind == "IF": + next(tkn_iter) + in_if = 1 + if tkn.kind == "IDENTIFIER" and tkn.text in ("DEOPT_IF", "ERROR_IF"): + next(tkn_iter) + in_if = 1 + elif tkn.kind == "LPAREN" and in_if: + in_if += 1 + elif tkn.kind == "RPAREN": + if in_if: + in_if -= 1 + elif tkn in calls and in_if: + raise analysis_error(f"Escaping call '{tkn.text} in condition", tkn) + +def find_escaping_api_calls(instr: parser.InstDef) -> dict[lexer.Token, tuple[lexer.Token, lexer.Token]]: + result: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] = {} + tokens = instr.block.tokens + for idx, tkn in enumerate(tokens): try: - next_tkn = next(tkns) - except StopIteration: - return False + next_tkn = tokens[idx+1] + except IndexError: + break + if tkn.kind == "SWITCH": + raise analysis_error(f"switch statements are not supported due to their complex flow control. Sorry.", tkn) if next_tkn.kind != lexer.LPAREN: continue - if tkn.text in ESCAPING_FUNCTIONS: - return True - if tkn.text == "tp_vectorcall": - return True - if not tkn.text.startswith("Py") and not tkn.text.startswith("_Py"): - continue - if tkn.text.endswith("Check"): - continue - if tkn.text.startswith("Py_Is"): - continue - if tkn.text.endswith("CheckExact"): - continue - if tkn.text in NON_ESCAPING_FUNCTIONS: + if tkn.kind == lexer.IDENTIFIER: + if tkn.text.upper() == tkn.text: + # simple macro + continue + #if not tkn.text.startswith(("Py", "_Py", "monitor")): + # continue + if tkn.text.startswith(("sym_", "optimize_")): + # Optimize functions + continue + if tkn.text.endswith("Check"): + continue + if tkn.text.startswith("Py_Is"): + continue + if tkn.text.endswith("CheckExact"): + continue + if tkn.text in NON_ESCAPING_FUNCTIONS: + continue + elif tkn.kind == "RPAREN": + prev = tokens[idx-1] + if prev.text.endswith("_t") or prev.text == "*" or prev.text == "int": + #cast + continue + elif tkn.kind != "RBRACKET": continue - return True - return False + start = find_stmt_start(instr, idx) + end = find_stmt_end(instr, idx) + result[start] = tkn, end + check_escaping_calls(instr, result) + return result EXITS = { @@ -651,6 +782,7 @@ def effect_depends_on_oparg_1(op: parser.InstDef) -> bool: def compute_properties(op: parser.InstDef) -> Properties: + escaping_calls = find_escaping_api_calls(op) has_free = ( variable_used(op, "PyCell_New") or variable_used(op, "PyCell_GetRef") @@ -671,7 +803,7 @@ def compute_properties(op: parser.InstDef) -> Properties: error_with_pop = has_error_with_pop(op) error_without_pop = has_error_without_pop(op) return Properties( - escapes=makes_escaping_api_call(op), + escaping_calls=escaping_calls, error_with_pop=error_with_pop, error_without_pop=error_without_pop, deopts=deopts_if, @@ -706,6 +838,7 @@ def make_uop( stack=analyze_stack(op), caches=analyze_caches(inputs), deferred_refs=analyze_deferred_refs(op), + output_stores=find_stores_outputs(op), body=op.block.tokens, properties=compute_properties(op), ) @@ -726,6 +859,7 @@ def make_uop( stack=analyze_stack(op, bit), caches=analyze_caches(inputs), deferred_refs=analyze_deferred_refs(op), + output_stores=find_stores_outputs(op), body=op.block.tokens, properties=properties, ) @@ -749,6 +883,7 @@ def make_uop( stack=analyze_stack(op), caches=analyze_caches(inputs), deferred_refs=analyze_deferred_refs(op), + output_stores=find_stores_outputs(op), body=op.block.tokens, properties=properties, ) diff --git a/Tools/cases_generator/cwriter.py b/Tools/cases_generator/cwriter.py index 069f0177a74018..8cba9127fa3071 100644 --- a/Tools/cases_generator/cwriter.py +++ b/Tools/cases_generator/cwriter.py @@ -18,8 +18,9 @@ def __init__(self, out: TextIO, indent: int, line_directives: bool): def set_position(self, tkn: Token) -> None: if self.last_token is not None: - if self.last_token.line < tkn.line: + if self.last_token.end_line < tkn.line: self.out.write("\n") + if self.last_token.line < tkn.line: if self.line_directives: self.out.write(f'#line {tkn.line} "{tkn.filename}"\n') self.out.write(" " * self.indents[-1]) @@ -91,6 +92,8 @@ def emit_token(self, tkn: Token) -> None: self.maybe_dedent(tkn.text) self.set_position(tkn) self.emit_text(tkn.text) + if tkn.kind == "CMACRO": + self.newline = True self.maybe_indent(tkn.text) def emit_str(self, txt: str) -> None: diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index 4cfd4ad3d05988..f32a20b304c354 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -9,10 +9,39 @@ analysis_error, ) from cwriter import CWriter -from typing import Callable, Mapping, TextIO, Iterator +from typing import Callable, Mapping, TextIO, Iterator, Iterable from lexer import Token -from stack import Stack +from stack import Stack, Local, Storage, StackError +# Set this to true for voluminous output showing state of stack and locals +PRINT_STACKS = False + +class TokenIterator: + + look_ahead: Token | None + iterator: Iterator[Token] + + def __init__(self, tkns: Iterable[Token]): + self.iterator = iter(tkns) + self.look_ahead = None + + def __iter__(self) -> "TokenIterator": + return self + + def __next__(self) -> Token: + if self.look_ahead is None: + return next(self.iterator) + else: + res = self.look_ahead + self.look_ahead = None + return res + + def peek(self) -> Token | None: + if self.look_ahead is None: + for tkn in self.iterator: + self.look_ahead = tkn + break + return self.look_ahead ROOT = Path(__file__).parent.parent.parent DEFAULT_INPUT = (ROOT / "Python/bytecodes.c").absolute().as_posix() @@ -47,22 +76,28 @@ def write_header( ) -def emit_to(out: CWriter, tkn_iter: Iterator[Token], end: str) -> None: +def emit_to(out: CWriter, tkn_iter: TokenIterator, end: str) -> Token: parens = 0 for tkn in tkn_iter: if tkn.kind == end and parens == 0: - return + return tkn if tkn.kind == "LPAREN": parens += 1 if tkn.kind == "RPAREN": parens -= 1 out.emit(tkn) + raise analysis_error(f"Expecting {end}. Reached end of file", tkn) ReplacementFunctionType = Callable[ - [Token, Iterator[Token], Uop, Stack, Instruction | None], None + [Token, TokenIterator, Uop, Storage, Instruction | None], bool ] +def always_true(tkn: Token | None) -> bool: + if tkn is None: + return False + return tkn.text in {"true", "1"} + class Emitter: out: CWriter @@ -75,21 +110,41 @@ def __init__(self, out: CWriter): "ERROR_IF": self.error_if, "ERROR_NO_POP": self.error_no_pop, "DECREF_INPUTS": self.decref_inputs, + "DEAD": self.kill, + "INPUTS_DEAD": self.kill_inputs, "SYNC_SP": self.sync_sp, - "PyStackRef_FromPyObjectNew": self.py_stack_ref_from_py_object_new, + "SAVE_STACK": self.save_stack, + "RELOAD_STACK": self.reload_stack, + "PyStackRef_CLOSE": self.stackref_close, + "PyStackRef_AsPyObjectSteal": self.stackref_steal, + "DISPATCH": self.dispatch } self.out = out + def dispatch( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: Uop, + storage: Storage, + inst: Instruction | None, + ) -> bool: + self.emit(tkn) + return False + def deopt_if( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - unused: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: self.out.emit_at("DEOPT_IF", tkn) - self.out.emit(next(tkn_iter)) + lparen = next(tkn_iter) + self.emit(lparen) + assert lparen.kind == "LPAREN" + first_tkn = tkn_iter.peek() emit_to(self.out, tkn_iter, "RPAREN") next(tkn_iter) # Semi colon self.out.emit(", ") @@ -97,25 +152,30 @@ def deopt_if( assert inst.family is not None self.out.emit(inst.family.name) self.out.emit(");\n") + return not always_true(first_tkn) exit_if = deopt_if def error_if( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: self.out.emit_at("if ", tkn) - self.out.emit(next(tkn_iter)) + lparen = next(tkn_iter) + self.emit(lparen) + assert lparen.kind == "LPAREN" + first_tkn = tkn_iter.peek() emit_to(self.out, tkn_iter, "COMMA") label = next(tkn_iter).text next(tkn_iter) # RPAREN next(tkn_iter) # Semi colon self.out.emit(") ") - c_offset = stack.peek_offset() + storage.clear_inputs("at ERROR_IF") + c_offset = storage.stack.peek_offset() try: offset = -int(c_offset) except ValueError: @@ -130,33 +190,35 @@ def error_if( self.out.emit(";\n") else: self.out.emit("{\n") - stack.flush_locally(self.out) + storage.copy().flush(self.out) self.out.emit("goto ") self.out.emit(label) self.out.emit(";\n") self.out.emit("}\n") + return not always_true(first_tkn) def error_no_pop( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: next(tkn_iter) # LPAREN next(tkn_iter) # RPAREN next(tkn_iter) # Semi colon self.out.emit_at("goto error;", tkn) + return False def decref_inputs( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: next(tkn_iter) next(tkn_iter) next(tkn_iter) @@ -178,59 +240,278 @@ def decref_inputs( self.out.emit(f"PyStackRef_XCLOSE({var.name});\n") else: self.out.emit(f"PyStackRef_CLOSE({var.name});\n") + for input in storage.inputs: + input.defined = False + return True + + def kill_inputs( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: Uop, + storage: Storage, + inst: Instruction | None, + ) -> bool: + next(tkn_iter) + next(tkn_iter) + next(tkn_iter) + for var in storage.inputs: + var.defined = False + return True + + def kill( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: Uop, + storage: Storage, + inst: Instruction | None, + ) -> bool: + next(tkn_iter) + name_tkn = next(tkn_iter) + name = name_tkn.text + next(tkn_iter) + next(tkn_iter) + for var in storage.inputs: + if var.name == name: + var.defined = False + break + else: + raise analysis_error(f"'{name}' is not a live input-only variable", name_tkn) + return True + + def stackref_close( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: Uop, + storage: Storage, + inst: Instruction | None, + ) -> bool: + self.out.emit(tkn) + tkn = next(tkn_iter) + assert tkn.kind == "LPAREN" + self.out.emit(tkn) + name = next(tkn_iter) + self.out.emit(name) + if name.kind == "IDENTIFIER": + for var in storage.inputs: + if var.name == name.text: + var.defined = False + rparen = emit_to(self.out, tkn_iter, "RPAREN") + self.emit(rparen) + return True + + stackref_steal = stackref_close def sync_sp( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: next(tkn_iter) next(tkn_iter) next(tkn_iter) - stack.flush(self.out) + storage.clear_inputs("when syncing stack") + storage.flush(self.out) + self._print_storage(storage) + return True + + def emit_save(self, storage: Storage) -> None: + storage.save(self.out) + self._print_storage(storage) - def py_stack_ref_from_py_object_new( + def save_stack( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: - target = uop.deferred_refs[tkn] - if target is None: - # An assignment we don't handle, such as to a pointer or array. - self.out.emit(tkn) - return + ) -> bool: + next(tkn_iter) + next(tkn_iter) + next(tkn_iter) + self.emit_save(storage) + return True + + def emit_reload(self, storage: Storage) -> None: + storage.reload(self.out) + self._print_storage(storage) + + def reload_stack( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: Uop, + storage: Storage, + inst: Instruction | None, + ) -> bool: + next(tkn_iter) + next(tkn_iter) + next(tkn_iter) + self.emit_reload(storage) + return True + def _print_storage(self, storage: Storage) -> None: + if PRINT_STACKS: + self.out.start_line() + self.emit(storage.as_comment()) + self.out.start_line() + + def _emit_if( + self, + tkn_iter: TokenIterator, + uop: Uop, + storage: Storage, + inst: Instruction | None, + ) -> tuple[bool, Token, Storage]: + """Returns (reachable?, closing '}', stack).""" + tkn = next(tkn_iter) + assert tkn.kind == "LPAREN" self.out.emit(tkn) - emit_to(self.out, tkn_iter, "SEMI") - self.out.emit(";\n") + rparen = emit_to(self.out, tkn_iter, "RPAREN") + self.emit(rparen) + if_storage = storage.copy() + reachable, rbrace, if_storage = self._emit_block(tkn_iter, uop, if_storage, inst, True) + try: + maybe_else = tkn_iter.peek() + if maybe_else and maybe_else.kind == "ELSE": + self._print_storage(storage) + self.emit(rbrace) + self.emit(next(tkn_iter)) + maybe_if = tkn_iter.peek() + if maybe_if and maybe_if.kind == "IF": + #Emit extra braces around the if to get scoping right + self.emit(" {\n") + self.emit(next(tkn_iter)) + else_reachable, rbrace, else_storage = self._emit_if(tkn_iter, uop, storage, inst) + self.out.start_line() + self.emit("}\n") + else: + else_reachable, rbrace, else_storage = self._emit_block(tkn_iter, uop, storage, inst, True) + if not reachable: + # Discard the if storage + reachable = else_reachable + storage = else_storage + elif not else_reachable: + # Discard the else storage + storage = if_storage + reachable = True + else: + if PRINT_STACKS: + self.emit("/* Merge */\n") + else_storage.merge(if_storage, self.out) + storage = else_storage + self._print_storage(storage) + else: + if reachable: + if PRINT_STACKS: + self.emit("/* Merge */\n") + if_storage.merge(storage, self.out) + storage = if_storage + self._print_storage(storage) + else: + # Discard the if storage + reachable = True + except StackError as ex: + self._print_storage(if_storage) + raise analysis_error(ex.args[0], rbrace) # from None + return reachable, rbrace, storage + + def _emit_block( + self, + tkn_iter: TokenIterator, + uop: Uop, + storage: Storage, + inst: Instruction | None, + emit_first_brace: bool + ) -> tuple[bool, Token, Storage]: + """ Returns (reachable?, closing '}', stack).""" + braces = 1 + out_stores = set(uop.output_stores) + tkn = next(tkn_iter) + reload: Token | None = None + try: + reachable = True + line : int = -1 + if tkn.kind != "LBRACE": + raise analysis_error(f"PEP 7: expected '{{', found: {tkn.text}", tkn) + escaping_calls = uop.properties.escaping_calls + if emit_first_brace: + self.emit(tkn) + self._print_storage(storage) + for tkn in tkn_iter: + if PRINT_STACKS and tkn.line != line: + self.out.start_line() + self.emit(storage.as_comment()) + self.out.start_line() + line = tkn.line + if tkn in escaping_calls: + if tkn != reload: + self.emit_save(storage) + _, reload = escaping_calls[tkn] + elif tkn == reload: + self.emit_reload(storage) + if tkn.kind == "LBRACE": + self.out.emit(tkn) + braces += 1 + elif tkn.kind == "RBRACE": + self._print_storage(storage) + braces -= 1 + if braces == 0: + return reachable, tkn, storage + self.out.emit(tkn) + elif tkn.kind == "GOTO": + reachable = False; + self.out.emit(tkn) + elif tkn.kind == "IDENTIFIER": + if tkn.text in self._replacers: + if not self._replacers[tkn.text](tkn, tkn_iter, uop, storage, inst): + reachable = False + else: + if tkn in out_stores: + for out in storage.outputs: + if out.name == tkn.text: + out.defined = True + out.in_memory = False + break + if tkn.text.startswith("DISPATCH"): + self._print_storage(storage) + reachable = False + self.out.emit(tkn) + elif tkn.kind == "IF": + self.out.emit(tkn) + if_reachable, rbrace, storage = self._emit_if(tkn_iter, uop, storage, inst) + if reachable: + reachable = if_reachable + self.out.emit(rbrace) + else: + self.out.emit(tkn) + except StackError as ex: + raise analysis_error(ex.args[0], tkn) from None + raise analysis_error("Expecting closing brace. Reached end of file", tkn) - # Flush the assignment to the stack. Note that we don't flush the - # stack pointer here, and instead are currently relying on initializing - # unused portions of the stack to NULL. - stack.flush_single_var(self.out, target, uop.stack.outputs) def emit_tokens( self, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: - tkns = uop.body[1:-1] - if not tkns: - return - tkn_iter = iter(tkns) + ) -> Storage: + tkn_iter = TokenIterator(uop.body) self.out.start_line() - for tkn in tkn_iter: - if tkn.kind == "IDENTIFIER" and tkn.text in self._replacers: - self._replacers[tkn.text](tkn, tkn_iter, uop, stack, inst) - else: - self.out.emit(tkn) + _, rbrace, storage = self._emit_block(tkn_iter, uop, storage, inst, False) + try: + self._print_storage(storage) + storage.push_outputs() + self._print_storage(storage) + except StackError as ex: + raise analysis_error(ex.args[0], rbrace) + return storage def emit(self, txt: str | Token) -> None: self.out.emit(txt) diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py index d5831593215f76..37f96398ff175f 100644 --- a/Tools/cases_generator/lexer.py +++ b/Tools/cases_generator/lexer.py @@ -79,7 +79,7 @@ def choice(*opts: str) -> str: opmap = {pattern.replace("\\", "") or "\\": op for op, pattern in operators.items()} # Macros -macro = r"# *(ifdef|ifndef|undef|define|error|endif|if|else|include|#)" +macro = r"#.*\n" CMACRO = "CMACRO" id_re = r"[a-zA-Z_][0-9a-zA-Z_]*" @@ -333,6 +333,9 @@ def tokenize(src: str, line: int = 1, filename: str = "") -> Iterator[Token]: line += newlines else: begin = line, start - linestart + if kind == CMACRO: + linestart = end + line += 1 if kind != "\n": yield Token( filename, kind, text, begin, (line, start - linestart + len(text)) diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py index b74f627235ad84..7a1dfe1b85bf1a 100644 --- a/Tools/cases_generator/optimizer_generator.py +++ b/Tools/cases_generator/optimizer_generator.py @@ -18,11 +18,12 @@ ROOT, write_header, Emitter, + TokenIterator, ) from cwriter import CWriter from typing import TextIO, Iterator from lexer import Token -from stack import Local, Stack, StackError +from stack import Local, Stack, StackError, Storage DEFAULT_OUTPUT = ROOT / "Python/optimizer_cases.c.h" DEFAULT_ABSTRACT_INPUT = (ROOT / "Python/optimizer_bytecodes.c").absolute().as_posix() @@ -45,7 +46,7 @@ def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: variables = {"unused"} if not skip_inputs: for var in reversed(uop.stack.inputs): - if var.name not in variables: + if var.used and var.name not in variables: variables.add(var.name) if var.condition: out.emit(f"{type_name(var)}{var.name} = NULL;\n") @@ -65,7 +66,7 @@ def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: def decref_inputs( out: CWriter, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, stack: Stack, inst: Instruction | None, @@ -76,13 +77,27 @@ def decref_inputs( out.emit_at("", tkn) -def emit_default(out: CWriter, uop: Uop) -> None: - for i, var in enumerate(uop.stack.outputs): +def emit_default(out: CWriter, uop: Uop, stack: Stack) -> None: + for var in reversed(uop.stack.inputs): + stack.pop(var) + top_offset = stack.top_offset.copy() + for var in uop.stack.outputs: + if var.is_array() and not var.peek and not var.name == "unused": + c_offset = top_offset.to_c() + out.emit(f"{var.name} = &stack_pointer[{c_offset}];\n") + top_offset.push(var) + for var in uop.stack.outputs: + local = Local.undefined(var) + stack.push(local) if var.name != "unused" and not var.peek: + local.defined = True if var.is_array(): - out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") - out.emit(f"{var.name}[_i] = sym_new_not_null(ctx);\n") - out.emit("}\n") + if var.size == "1": + out.emit(f"{var.name}[0] = sym_new_not_null(ctx);\n") + else: + out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") + out.emit(f"{var.name}[_i] = sym_new_not_null(ctx);\n") + out.emit("}\n") elif var.name == "null": out.emit(f"{var.name} = sym_new_null(ctx);\n") else: @@ -90,7 +105,12 @@ def emit_default(out: CWriter, uop: Uop) -> None: class OptimizerEmitter(Emitter): - pass + + def emit_save(self, storage: Storage) -> None: + storage.flush(self.out) + + def emit_reload(self, storage: Storage) -> None: + pass def write_uop( @@ -102,22 +122,18 @@ def write_uop( skip_inputs: bool, ) -> None: locals: dict[str, Local] = {} + prototype = override if override else uop try: - prototype = override if override else uop - is_override = override is not None out.start_line() - for var in reversed(prototype.stack.inputs): - code, local = stack.pop(var, extract_bits=True) - if not skip_inputs: + if override: + code_list, storage = Storage.for_uop(stack, prototype, extract_bits=False) + for code in code_list: out.emit(code) - if local.defined: - locals[local.name] = local - out.emit(stack.define_output_arrays(prototype.stack.outputs)) if debug: args = [] - for var in prototype.stack.inputs: - if not var.peek or is_override: - args.append(var.name) + for input in prototype.stack.inputs: + if not input.peek or override: + args.append(input.name) out.emit(f'DEBUG_PRINTF({", ".join(args)});\n') if override: for cache in uop.caches: @@ -130,20 +146,18 @@ def write_uop( out.emit(f"{type}{cache.name} = ({cast})this_instr->operand;\n") if override: emitter = OptimizerEmitter(out) - emitter.emit_tokens(override, stack, None) + # No reference management of inputs needed. + for var in storage.inputs: # type: ignore[possibly-undefined] + var.defined = False + storage = emitter.emit_tokens(override, storage, None) + out.start_line() + storage.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=False) else: - emit_default(out, uop) - - for var in prototype.stack.outputs: - if var.name in locals: - local = locals[var.name] - else: - local = Local.local(var) - stack.push(local) - out.start_line() - stack.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=True) + emit_default(out, uop, stack) + out.start_line() + stack.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=False) except StackError as ex: - raise analysis_error(ex.args[0], uop.body[0]) + raise analysis_error(ex.args[0], prototype.body[0]) # from None SKIPS = ("_EXTENDED_ARG",) diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py index de4d900563ee0b..a954bed4df073c 100644 --- a/Tools/cases_generator/stack.py +++ b/Tools/cases_generator/stack.py @@ -46,20 +46,41 @@ class Local: in_memory: bool defined: bool + def __repr__(self) -> str: + return f"Local('{self.item.name}', mem={self.in_memory}, defined={self.defined}, array={self.is_array()})" + + def compact_str(self) -> str: + mtag = "M" if self.in_memory else "" + dtag = "D" if self.defined else "" + atag = "A" if self.is_array() else "" + return f"'{self.item.name}'{mtag}{dtag}{atag}" + @staticmethod def unused(defn: StackItem) -> "Local": return Local(defn, False, defn.is_array(), False) @staticmethod - def local(defn: StackItem) -> "Local": + def undefined(defn: StackItem) -> "Local": array = defn.is_array() - return Local(defn, not array, array, True) + return Local(defn, not array, array, False) @staticmethod def redefinition(var: StackItem, prev: "Local") -> "Local": assert var.is_array() == prev.is_array() return Local(var, prev.cached, prev.in_memory, True) + @staticmethod + def from_memory(defn: StackItem) -> "Local": + return Local(defn, True, True, True) + + def copy(self) -> "Local": + return Local( + self.item, + self.cached, + self.in_memory, + self.defined + ) + @property def size(self) -> str: return self.item.size @@ -75,6 +96,16 @@ def condition(self) -> str | None: def is_array(self) -> bool: return self.item.is_array() + def __eq__(self, other: object) -> bool: + if not isinstance(other, Local): + return NotImplemented + return ( + self.item is other.item + and self.cached is other.cached + and self.in_memory is other.in_memory + and self.defined is other.defined + ) + @dataclass class StackOffset: @@ -156,10 +187,34 @@ def to_c(self) -> str: res = "-" + res[3:] return res + def as_int(self) -> int | None: + self.simplify() + int_offset = 0 + for item in self.popped: + try: + int_offset -= int(item) + except ValueError: + return None + for item in self.pushed: + try: + int_offset += int(item) + except ValueError: + return None + return int_offset + def clear(self) -> None: self.popped = [] self.pushed = [] + def __bool__(self) -> bool: + self.simplify() + return bool(self.popped) or bool(self.pushed) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, StackOffset): + return NotImplemented + return self.to_c() == other.to_c() + class StackError(Exception): pass @@ -174,7 +229,7 @@ def __init__(self) -> None: self.variables: list[Local] = [] self.defined: set[str] = set() - def pop(self, var: StackItem, extract_bits: bool = False) -> tuple[str, Local]: + def pop(self, var: StackItem, extract_bits: bool = True) -> tuple[str, Local]: self.top_offset.pop(var) indirect = "&" if var.is_array() else "" if self.variables: @@ -192,7 +247,7 @@ def pop(self, var: StackItem, extract_bits: bool = False) -> tuple[str, Local]: if var.name in UNUSED: if popped.name not in UNUSED and popped.name in self.defined: raise StackError( - f"Value is declared unused, but is already cached by prior operation" + f"Value is declared unused, but is already cached by prior operation as '{popped.name}'" ) return "", popped if not var.used: @@ -208,6 +263,7 @@ def pop(self, var: StackItem, extract_bits: bool = False) -> tuple[str, Local]: defn = f"{var.name} = &stack_pointer[{self.top_offset.to_c()}];\n" else: defn = f"{var.name} = stack_pointer[{self.top_offset.to_c()}];\n" + popped.in_memory = True return defn, Local.redefinition(var, popped) self.base_offset.pop(var) @@ -215,7 +271,7 @@ def pop(self, var: StackItem, extract_bits: bool = False) -> tuple[str, Local]: return "", Local.unused(var) self.defined.add(var.name) cast = f"({var.type})" if (not indirect and var.type) else "" - bits = ".bits" if cast and not extract_bits else "" + bits = ".bits" if cast and extract_bits else "" assign = f"{var.name} = {cast}{indirect}stack_pointer[{self.base_offset.to_c()}]{bits};" if var.condition: if var.condition == "1": @@ -226,27 +282,14 @@ def pop(self, var: StackItem, extract_bits: bool = False) -> tuple[str, Local]: assign = f"if ({var.condition}) {{ {assign} }}\n" else: assign = f"{assign}\n" - in_memory = var.is_array() or var.peek - return assign, Local(var, not var.is_array(), in_memory, True) + return assign, Local.from_memory(var) def push(self, var: Local) -> None: + assert(var not in self.variables) self.variables.append(var) self.top_offset.push(var.item) if var.item.used: self.defined.add(var.name) - var.defined = True - - def define_output_arrays(self, outputs: list[StackItem]) -> str: - res = [] - top_offset = self.top_offset.copy() - for var in outputs: - if var.is_array() and var.used and not var.peek: - c_offset = top_offset.to_c() - top_offset.push(var) - res.append(f"{var.name} = &stack_pointer[{c_offset}];\n") - else: - top_offset.push(var) - return "\n".join(res) @staticmethod def _do_emit( @@ -254,102 +297,92 @@ def _do_emit( var: StackItem, base_offset: StackOffset, cast_type: str = "uintptr_t", - extract_bits: bool = False, + extract_bits: bool = True, ) -> None: cast = f"({cast_type})" if var.type else "" - bits = ".bits" if cast and not extract_bits else "" + bits = ".bits" if cast and extract_bits else "" if var.condition == "0": return if var.condition and var.condition != "1": out.emit(f"if ({var.condition}) ") out.emit(f"stack_pointer[{base_offset.to_c()}]{bits} = {cast}{var.name};\n") - @staticmethod - def _do_flush( - out: CWriter, - variables: list[Local], - base_offset: StackOffset, - top_offset: StackOffset, - cast_type: str = "uintptr_t", - extract_bits: bool = False, - ) -> None: - out.start_line() - for var in variables: - if ( - var.cached - and not var.in_memory - and not var.item.peek - and not var.name in UNUSED - ): - Stack._do_emit(out, var.item, base_offset, cast_type, extract_bits) - base_offset.push(var.item) - if base_offset.to_c() != top_offset.to_c(): - print("base", base_offset, "top", top_offset) - assert False - number = base_offset.to_c() + def _adjust_stack_pointer(self, out: CWriter, number: str) -> None: if number != "0": + out.start_line() out.emit(f"stack_pointer += {number};\n") out.emit("assert(WITHIN_STACK_BOUNDS());\n") - out.start_line() - - def flush_locally( - self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = False - ) -> None: - self._do_flush( - out, - self.variables[:], - self.base_offset.copy(), - self.top_offset.copy(), - cast_type, - extract_bits, - ) def flush( - self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = False + self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True ) -> None: - self._do_flush( - out, - self.variables, - self.base_offset, - self.top_offset, - cast_type, - extract_bits, - ) - self.variables = [] - self.base_offset.clear() + out.start_line() + var_offset = self.base_offset.copy() + for var in self.variables: + if ( + var.defined and + not var.in_memory + ): + Stack._do_emit(out, var.item, var_offset, cast_type, extract_bits) + var.in_memory = True + var_offset.push(var.item) + number = self.top_offset.to_c() + self._adjust_stack_pointer(out, number) + self.base_offset -= self.top_offset self.top_offset.clear() + out.start_line() - def flush_single_var( - self, - out: CWriter, - var_name: str, - outputs: list[StackItem], - cast_type: str = "uintptr_t", - extract_bits: bool = False, - ) -> None: - assert any(var.name == var_name for var in outputs) - base_offset = self.base_offset.copy() - top_offset = self.top_offset.copy() - for var in self.variables: - base_offset.push(var.item) - for output in outputs: - if any(output == v.item for v in self.variables): - # The variable is already on the stack, such as a peeked value - # in the tier1 generator - continue - if output.name == var_name: - Stack._do_emit(out, output, base_offset, cast_type, extract_bits) - base_offset.push(output) - top_offset.push(output) - if base_offset.to_c() != top_offset.to_c(): - print("base", base_offset, "top", top_offset) - assert False + def is_flushed(self) -> bool: + return not self.variables and not self.base_offset and not self.top_offset def peek_offset(self) -> str: return self.top_offset.to_c() def as_comment(self) -> str: - return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */" + variables = ", ".join([v.compact_str() for v in self.variables]) + return ( + f"/* Variables: {variables}. base: {self.base_offset.to_c()}. top: {self.top_offset.to_c()} */" + ) + + def copy(self) -> "Stack": + other = Stack() + other.top_offset = self.top_offset.copy() + other.base_offset = self.base_offset.copy() + other.variables = [var.copy() for var in self.variables] + other.defined = set(self.defined) + return other + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Stack): + return NotImplemented + return ( + self.top_offset == other.top_offset + and self.base_offset == other.base_offset + and self.variables == other.variables + ) + + def align(self, other: "Stack", out: CWriter) -> None: + if len(self.variables) != len(other.variables): + raise StackError("Cannot align stacks: differing variables") + if self.top_offset == other.top_offset: + return + diff = self.top_offset - other.top_offset + try: + self.top_offset -= diff + self.base_offset -= diff + self._adjust_stack_pointer(out, diff.to_c()) + except ValueError: + raise StackError("Cannot align stacks: cannot adjust stack pointer") + + def merge(self, other: "Stack", out: CWriter) -> None: + if len(self.variables) != len(other.variables): + raise StackError("Cannot merge stacks: differing variables") + for self_var, other_var in zip(self.variables, other.variables): + if self_var.name != other_var.name: + raise StackError(f"Mismatched variables on stack: {self_var.name} and {other_var.name}") + self_var.defined = self_var.defined and other_var.defined + self_var.in_memory = self_var.in_memory and other_var.in_memory + self.align(other, out) def get_stack_effect(inst: Instruction | PseudoInstruction) -> Stack: @@ -377,3 +410,213 @@ def stacks(inst: Instruction | PseudoInstruction) -> Iterator[StackEffect]: local = Local.unused(var) stack.push(local) return stack + +@dataclass +class Storage: + + stack: Stack + inputs: list[Local] + outputs: list[Local] + peeks: list[Local] + spilled: int = 0 + + @staticmethod + def needs_defining(var: Local) -> bool: + return ( + not var.defined and + not var.is_array() and + var.name != "unused" + ) + + @staticmethod + def is_live(var: Local) -> bool: + return ( + var.defined and + var.name != "unused" + ) + + def first_input_not_cleared(self) -> str: + for input in self.inputs: + if input.defined: + return input.name + return "" + + def clear_inputs(self, reason:str) -> None: + while self.inputs: + tos = self.inputs.pop() + if self.is_live(tos) and not tos.is_array(): + raise StackError( + f"Input '{tos.name}' is still live {reason}" + ) + self.stack.pop(tos.item) + + def clear_dead_inputs(self) -> None: + live = "" + while self.inputs: + tos = self.inputs[-1] + if self.is_live(tos): + live = tos.name + break + self.inputs.pop() + self.stack.pop(tos.item) + for var in self.inputs: + if not var.defined and not var.is_array() and var.name != "unused": + raise StackError( + f"Input '{var.name}' is not live, but '{live}' is" + ) + + def _push_defined_outputs(self) -> None: + defined_output = "" + for output in self.outputs: + if output.defined and not output.in_memory: + defined_output = output.name + if not defined_output: + return + self.clear_inputs(f"when output '{defined_output}' is defined") + undefined = "" + for out in self.outputs: + if out.defined: + if undefined: + f"Locals not defined in stack order. " + f"Expected '{undefined}' to be defined before '{out.name}'" + else: + undefined = out.name + while self.outputs and not self.needs_defining(self.outputs[0]): + out = self.outputs.pop(0) + self.stack.push(out) + + def locals_cached(self) -> bool: + for out in self.outputs: + if out.defined: + return True + return False + + def flush(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True) -> None: + self.clear_dead_inputs() + self._push_defined_outputs() + self.stack.flush(out, cast_type, extract_bits) + + def save(self, out: CWriter) -> None: + assert self.spilled >= 0 + if self.spilled == 0: + self.flush(out) + out.start_line() + out.emit("_PyFrame_SetStackPointer(frame, stack_pointer);\n") + self.spilled += 1 + + def reload(self, out: CWriter) -> None: + if self.spilled == 0: + raise StackError("Cannot reload stack as it hasn't been saved") + assert self.spilled > 0 + self.spilled -= 1 + if self.spilled == 0: + out.start_line() + out.emit("stack_pointer = _PyFrame_GetStackPointer(frame);\n") + + @staticmethod + def for_uop(stack: Stack, uop: Uop, extract_bits: bool = True) -> tuple[list[str], "Storage"]: + code_list: list[str] = [] + inputs: list[Local] = [] + peeks: list[Local] = [] + for input in reversed(uop.stack.inputs): + code, local = stack.pop(input, extract_bits) + code_list.append(code) + if input.peek: + peeks.append(local) + else: + inputs.append(local) + inputs.reverse() + peeks.reverse() + for peek in peeks: + stack.push(peek) + top_offset = stack.top_offset.copy() + for ouput in uop.stack.outputs: + if ouput.is_array() and ouput.used and not ouput.peek: + c_offset = top_offset.to_c() + top_offset.push(ouput) + code_list.append(f"{ouput.name} = &stack_pointer[{c_offset}];\n") + else: + top_offset.push(ouput) + for var in inputs: + stack.push(var) + outputs = [ Local.undefined(var) for var in uop.stack.outputs if not var.peek ] + return code_list, Storage(stack, inputs, outputs, peeks) + + @staticmethod + def copy_list(arg: list[Local]) -> list[Local]: + return [ l.copy() for l in arg ] + + def copy(self) -> "Storage": + new_stack = self.stack.copy() + variables = { var.name: var for var in new_stack.variables } + inputs = [ variables[var.name] for var in self.inputs] + assert [v.name for v in inputs] == [v.name for v in self.inputs], (inputs, self.inputs) + return Storage( + new_stack, inputs, + self.copy_list(self.outputs), self.copy_list(self.peeks) + ) + + def sanity_check(self) -> None: + names: set[str] = set() + for var in self.inputs: + if var.name in names: + raise StackError(f"Duplicate name {var.name}") + names.add(var.name) + names = set() + for var in self.outputs: + if var.name in names: + raise StackError(f"Duplicate name {var.name}") + names.add(var.name) + names = set() + for var in self.stack.variables: + if var.name in names: + raise StackError(f"Duplicate name {var.name}") + names.add(var.name) + + def is_flushed(self) -> bool: + for var in self.outputs: + if var.defined and not var.in_memory: + return False + return self.stack.is_flushed() + + def merge(self, other: "Storage", out: CWriter) -> None: + self.sanity_check() + if len(self.inputs) != len(other.inputs): + self.clear_dead_inputs() + other.clear_dead_inputs() + if len(self.inputs) != len(other.inputs): + diff = self.inputs[-1] if len(self.inputs) > len(other.inputs) else other.inputs[-1] + raise StackError(f"Unmergeable inputs. Differing state of '{diff.name}'") + for var, other_var in zip(self.inputs, other.inputs): + if var.defined != other_var.defined: + raise StackError(f"'{var.name}' is cleared on some paths, but not all") + if len(self.outputs) != len(other.outputs): + self._push_defined_outputs() + other._push_defined_outputs() + if len(self.outputs) != len(other.outputs): + var = self.outputs[0] if len(self.outputs) > len(other.outputs) else other.outputs[0] + raise StackError(f"'{var.name}' is set on some paths, but not all") + self.stack.merge(other.stack, out) + self.sanity_check() + + def push_outputs(self) -> None: + if self.spilled: + raise StackError(f"Unbalanced stack spills") + self.clear_inputs("at the end of the micro-op") + if self.inputs: + raise StackError(f"Input variable '{self.inputs[-1].name}' is still live") + self._push_defined_outputs() + if self.outputs: + for out in self.outputs: + if self.needs_defining(out): + raise StackError(f"Output variable '{self.outputs[0].name}' is not defined") + self.stack.push(out) + self.outputs = [] + + def as_comment(self) -> str: + stack_comment = self.stack.as_comment() + next_line = "\n " + inputs = ", ".join([var.compact_str() for var in self.inputs]) + outputs = ", ".join([var.compact_str() for var in self.outputs]) + peeks = ", ".join([var.name for var in self.peeks]) + return f"{stack_comment[:-2]}{next_line}inputs: {inputs}{next_line}outputs: {outputs}{next_line}peeks: {peeks} */" diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py index c749896c2cb7f6..1b116a578c5a86 100644 --- a/Tools/cases_generator/tier1_generator.py +++ b/Tools/cases_generator/tier1_generator.py @@ -22,10 +22,11 @@ write_header, type_and_null, Emitter, + TokenIterator, ) from cwriter import CWriter from typing import TextIO -from stack import Local, Stack, StackError, get_stack_effect +from stack import Local, Stack, StackError, get_stack_effect, Storage DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h" @@ -47,7 +48,7 @@ def declare_variables(inst: Instruction, out: CWriter) -> None: try: stack = get_stack_effect(inst) except StackError as ex: - raise analysis_error(ex.args[0], inst.where) + raise analysis_error(ex.args[0], inst.where) from None required = set(stack.defined) required.discard("unused") for part in inst.parts: @@ -70,46 +71,26 @@ def write_uop( stack: Stack, inst: Instruction, braces: bool, -) -> int: +) -> tuple[int, Stack]: # out.emit(stack.as_comment() + "\n") if isinstance(uop, Skip): entries = "entries" if uop.size > 1 else "entry" emitter.emit(f"/* Skip {uop.size} cache {entries} */\n") - return offset + uop.size + return (offset + uop.size), stack if isinstance(uop, Flush): emitter.emit(f"// flush\n") stack.flush(emitter.out) - return offset + return offset, stack try: locals: dict[str, Local] = {} emitter.out.start_line() if braces: emitter.out.emit(f"// {uop.name}\n") - peeks: list[Local] = [] - for var in reversed(uop.stack.inputs): - code, local = stack.pop(var) - emitter.emit(code) - if var.peek: - peeks.append(local) - if local.defined: - locals[local.name] = local - # Push back the peeks, so that they remain on the logical - # stack, but their values are cached. - while peeks: - stack.push(peeks.pop()) - if braces: emitter.emit("{\n") - emitter.out.emit(stack.define_output_arrays(uop.stack.outputs)) - outputs: list[Local] = [] - for var in uop.stack.outputs: - if not var.peek: - if var.name in locals: - local = locals[var.name] - elif var.name == "unused": - local = Local.unused(var) - else: - local = Local.local(var) - outputs.append(local) + code_list, storage = Storage.for_uop(stack, uop) + emitter._print_storage(storage) + for code in code_list: + emitter.emit(code) for cache in uop.caches: if cache.name != "unused": @@ -125,17 +106,13 @@ def write_uop( if inst.family is None: emitter.emit(f"(void){cache.name};\n") offset += cache.size - emitter.emit_tokens(uop, stack, inst) - for output in outputs: - if output.name in uop.deferred_refs.values(): - # We've already spilled this when emitting tokens - output.cached = False - stack.push(output) + + storage = emitter.emit_tokens(uop, storage, inst) if braces: emitter.out.start_line() emitter.emit("}\n") # emitter.emit(stack.as_comment() + "\n") - return offset + return offset, storage.stack except StackError as ex: raise analysis_error(ex.args[0], uop.body[0]) @@ -197,10 +174,11 @@ def generate_tier1( for part in inst.parts: # Only emit braces if more than one uop insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) > 1 - offset = write_uop(part, emitter, offset, stack, inst, insert_braces) + offset, stack = write_uop(part, emitter, offset, stack, inst, insert_braces) out.start_line() + + stack.flush(out) if not inst.parts[-1].properties.always_exits: - stack.flush(out) out.emit("DISPATCH();\n") out.start_line() out.emit("}") diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py index b7c70fdad085fd..634848c10309d5 100644 --- a/Tools/cases_generator/tier2_generator.py +++ b/Tools/cases_generator/tier2_generator.py @@ -20,11 +20,13 @@ write_header, type_and_null, Emitter, + TokenIterator, + always_true, ) from cwriter import CWriter from typing import TextIO, Iterator from lexer import Token -from stack import Local, Stack, StackError, get_stack_effect +from stack import Local, Stack, StackError, Storage DEFAULT_OUTPUT = ROOT / "Python/executor_cases.c.h" @@ -32,7 +34,7 @@ def declare_variable( var: StackItem, uop: Uop, required: set[str], out: CWriter ) -> None: - if var.name not in required: + if not var.used or var.name not in required: return required.remove(var.name) type, null = type_and_null(var) @@ -52,7 +54,7 @@ def declare_variables(uop: Uop, out: CWriter) -> None: for var in reversed(uop.stack.inputs): stack.pop(var) for var in uop.stack.outputs: - stack.push(Local.unused(var)) + stack.push(Local.undefined(var)) required = set(stack.defined) required.discard("unused") for var in reversed(uop.stack.inputs): @@ -69,88 +71,103 @@ def __init__(self, out: CWriter): def error_if( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: self.out.emit_at("if ", tkn) - self.emit(next(tkn_iter)) + lparen = next(tkn_iter) + self.emit(lparen) + assert lparen.kind == "LPAREN" + first_tkn = next(tkn_iter) + self.out.emit(first_tkn) emit_to(self.out, tkn_iter, "COMMA") label = next(tkn_iter).text next(tkn_iter) # RPAREN next(tkn_iter) # Semi colon self.emit(") JUMP_TO_ERROR();\n") + return not always_true(first_tkn) + def error_no_pop( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - stack: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: next(tkn_iter) # LPAREN next(tkn_iter) # RPAREN next(tkn_iter) # Semi colon self.out.emit_at("JUMP_TO_ERROR();", tkn) + return False def deopt_if( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - unused: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: self.out.emit_at("if ", tkn) - self.emit(next(tkn_iter)) + lparen = next(tkn_iter) + self.emit(lparen) + assert lparen.kind == "LPAREN" + first_tkn = tkn_iter.peek() emit_to(self.out, tkn_iter, "RPAREN") next(tkn_iter) # Semi colon self.emit(") {\n") self.emit("UOP_STAT_INC(uopcode, miss);\n") self.emit("JUMP_TO_JUMP_TARGET();\n") self.emit("}\n") + return not always_true(first_tkn) def exit_if( # type: ignore[override] self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - unused: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: self.out.emit_at("if ", tkn) - self.emit(next(tkn_iter)) + lparen = next(tkn_iter) + self.emit(lparen) + first_tkn = tkn_iter.peek() emit_to(self.out, tkn_iter, "RPAREN") next(tkn_iter) # Semi colon self.emit(") {\n") self.emit("UOP_STAT_INC(uopcode, miss);\n") self.emit("JUMP_TO_JUMP_TARGET();\n") self.emit("}\n") + return not always_true(first_tkn) def oparg( self, tkn: Token, - tkn_iter: Iterator[Token], + tkn_iter: TokenIterator, uop: Uop, - unused: Stack, + storage: Storage, inst: Instruction | None, - ) -> None: + ) -> bool: if not uop.name.endswith("_0") and not uop.name.endswith("_1"): self.emit(tkn) - return + return True amp = next(tkn_iter) if amp.text != "&": self.emit(tkn) self.emit(amp) - return + return True one = next(tkn_iter) assert one.text == "1" self.out.emit_at(uop.name[-1], tkn) + return True -def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> None: +def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack: locals: dict[str, Local] = {} try: emitter.out.start_line() @@ -160,19 +177,9 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> None: elif uop.properties.const_oparg >= 0: emitter.emit(f"oparg = {uop.properties.const_oparg};\n") emitter.emit(f"assert(oparg == CURRENT_OPARG());\n") - for var in reversed(uop.stack.inputs): - code, local = stack.pop(var) + code_list, storage = Storage.for_uop(stack, uop) + for code in code_list: emitter.emit(code) - if local.defined: - locals[local.name] = local - emitter.emit(stack.define_output_arrays(uop.stack.outputs)) - outputs: list[Local] = [] - for var in uop.stack.outputs: - if var.name in locals: - local = locals[var.name] - else: - local = Local.local(var) - outputs.append(local) for cache in uop.caches: if cache.name != "unused": if cache.size == 4: @@ -181,15 +188,10 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> None: type = f"uint{cache.size*16}_t " cast = f"uint{cache.size*16}_t" emitter.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n") - emitter.emit_tokens(uop, stack, None) - for output in outputs: - if output.name in uop.deferred_refs.values(): - # We've already spilled this when emitting tokens - output.cached = False - stack.push(output) + storage = emitter.emit_tokens(uop, storage, None) except StackError as ex: raise analysis_error(ex.args[0], uop.body[0]) from None - + return storage.stack SKIPS = ("_EXTENDED_ARG",) @@ -226,7 +228,7 @@ def generate_tier2( out.emit(f"case {uop.name}: {{\n") declare_variables(uop, out) stack = Stack() - write_uop(uop, emitter, stack) + stack = write_uop(uop, emitter, stack) out.start_line() if not uop.properties.always_exits: stack.flush(out) From 744caa8ef42ab67c6aa20cd691e078721e72e22a Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 7 Oct 2024 17:37:52 +0200 Subject: [PATCH 030/247] gh-120762: make_ssl_certs: Don't set extensions for the temporary CSR (GH-125045) gh-120762: make_ssl_certs: Don't set extensions for the CSR `openssl req` fails with openssl 3.2.2 because the config line authorityKeyIdentifier = keyid:always,issuer:always is not supported for certificate signing requests (since the issuing certificate authority is not known). David von Oheimb, the OpenSSL dev that made the change, commented in: https://github.com/openssl/openssl/issues/22966#issuecomment-1858396738 : > This problem did not show up in older OpenSSL versions because of a bug: > the `req` app ignored the `-extensions` option unless `-x505` is given, > which I fixed in https://github.com/openssl/openssl/pull/16865. (I assume `-x505` is a typo for `-x509`.) In our `make_cert_key` function: If `sign` is true: - We don't pass `-x509` to `req`, so in this case it should be safe to omit the `-extensions` argument. (Old OpenSSL ignores it, new OpenSSL fails on it.) - The extensions are passed to the `ca` call later in the function. There they take effect, and `authorityKeyIdentifier` is valid. If `sign` is false, this commit has no effect except rearranging the CLI arguments. --- Lib/test/certdata/make_ssl_certs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/certdata/make_ssl_certs.py b/Lib/test/certdata/make_ssl_certs.py index 48f980124e1198..198c64035c5044 100644 --- a/Lib/test/certdata/make_ssl_certs.py +++ b/Lib/test/certdata/make_ssl_certs.py @@ -139,7 +139,6 @@ def make_cert_key(cmdlineargs, hostname, sign=False, extra_san='', f.write(req) args = ['req', '-new', '-nodes', '-days', cmdlineargs.days, '-newkey', key, '-keyout', key_file, - '-extensions', ext, '-config', req_file] if sign: with tempfile.NamedTemporaryFile(delete=False) as f: @@ -148,7 +147,7 @@ def make_cert_key(cmdlineargs, hostname, sign=False, extra_san='', args += ['-out', reqfile ] else: - args += ['-x509', '-out', cert_file ] + args += ['-extensions', ext, '-x509', '-out', cert_file ] check_call(['openssl'] + args) if sign: From 10094a533a947b72d01ed8195dcf540f2e7820ea Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Mon, 7 Oct 2024 17:51:53 +0100 Subject: [PATCH 031/247] gh-125018: Fix role syntax (#125050) --- Doc/library/importlib.metadata.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index ddb72784694fd9..85d5a2d684d6eb 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -122,7 +122,7 @@ Entry points Returns a :class:`EntryPoints` instance describing entry points for the current environment. Any given keyword parameters are passed to the - :meth:`!~EntryPoints.select` method for comparison to the attributes of + :meth:`!select` method for comparison to the attributes of the individual entry point definitions. Note: it is not currently possible to query for entry points based on @@ -158,7 +158,7 @@ attributes for convenience:: >>> sorted(eps.groups) # doctest: +SKIP ['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation'] -:class:`!EntryPoints` has a :meth:`!~EntryPoints.select` method to select entry points +:class:`!EntryPoints` has a :meth:`!select` method to select entry points matching specific properties. Select entry points in the ``console_scripts`` group:: @@ -232,7 +232,7 @@ Distribution metadata `PackageMetadata protocol `_. In addition to providing the defined protocol methods and attributes, subscripting - the instance is equivalent to calling the :meth:`!~PackageMetadata.get` method. + the instance is equivalent to calling the :meth:`!get` method. Every `Distribution Package `_ includes some metadata, which you can extract using the :func:`!metadata` function:: @@ -245,7 +245,7 @@ the values are returned unparsed from the distribution metadata:: >>> wheel_metadata['Requires-Python'] # doctest: +SKIP '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' -:class:`PackageMetadata` also presents a :attr:`!~PackageMetadata.json` attribute that returns +:class:`PackageMetadata` also presents a :attr:`!json` attribute that returns all the metadata in a JSON-compatible form per :PEP:`566`:: >>> wheel_metadata.json['requires_python'] @@ -331,7 +331,7 @@ Once you have the file, you can also read its contents:: return s.encode('utf-8') return s -You can also use the :meth:`!~PackagePath.locate` method to get the absolute +You can also use the :meth:`!locate` method to get the absolute path to the file:: >>> util.locate() # doctest: +SKIP From d1453f60c2d289d74d535874e07741745b023c90 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 7 Oct 2024 18:13:04 +0100 Subject: [PATCH 032/247] GH-121459: Streamline PyObject* to PyStackRef conversions by disallowing NULL pointers. (GH-124894) --- Include/internal/pycore_stackref.h | 14 ++++++---- Python/bytecodes.c | 32 ++++++++++++++--------- Python/executor_cases.c.h | 32 +++++++++++------------ Python/generated_cases.c.h | 42 ++++++++++++++---------------- 4 files changed, 63 insertions(+), 57 deletions(-) diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index b5b6993812057d..cf6dd22cfb18d1 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -111,7 +111,8 @@ PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) static inline PyObject * PyStackRef_AsPyObjectSteal(_PyStackRef stackref) { - if (!PyStackRef_IsNull(stackref) && PyStackRef_IsDeferred(stackref)) { + assert(!PyStackRef_IsNull(stackref)); + if (PyStackRef_IsDeferred(stackref)) { return Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)); } return PyStackRef_AsPyObjectBorrow(stackref); @@ -131,9 +132,10 @@ PyStackRef_AsPyObjectSteal(_PyStackRef stackref) static inline _PyStackRef _PyStackRef_FromPyObjectSteal(PyObject *obj) { + assert(obj != NULL); // Make sure we don't take an already tagged value. assert(((uintptr_t)obj & Py_TAG_BITS) == 0); - unsigned int tag = (obj == NULL || _Py_IsImmortal(obj)) ? (Py_TAG_DEFERRED) : Py_TAG_PTR; + unsigned int tag = _Py_IsImmortal(obj) ? (Py_TAG_DEFERRED) : Py_TAG_PTR; return ((_PyStackRef){.bits = ((uintptr_t)(obj)) | tag}); } # define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj)) @@ -193,6 +195,7 @@ PyStackRef_FromPyObjectImmortal(PyObject *obj) # define PyStackRef_CLOSE(REF) \ do { \ _PyStackRef _close_tmp = (REF); \ + assert(!PyStackRef_IsNull(_close_tmp)); \ if (!PyStackRef_IsDeferred(_close_tmp)) { \ Py_DECREF(PyStackRef_AsPyObjectBorrow(_close_tmp)); \ } \ @@ -214,10 +217,11 @@ PyStackRef_FromPyObjectImmortal(PyObject *obj) static inline _PyStackRef PyStackRef_DUP(_PyStackRef stackref) { + assert(!PyStackRef_IsNull(stackref)); if (PyStackRef_IsDeferred(stackref)) { - assert(PyStackRef_IsNull(stackref) || - _Py_IsImmortal(PyStackRef_AsPyObjectBorrow(stackref)) || - _PyObject_HasDeferredRefcount(PyStackRef_AsPyObjectBorrow(stackref))); + assert(_Py_IsImmortal(PyStackRef_AsPyObjectBorrow(stackref)) || + _PyObject_HasDeferredRefcount(PyStackRef_AsPyObjectBorrow(stackref)) + ); return stackref; } Py_INCREF(PyStackRef_AsPyObjectBorrow(stackref)); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index a0edf17d747e77..228d82173e6126 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1922,9 +1922,10 @@ dummy_func( DECREF_INPUTS(); ERROR_IF(super == NULL, error); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); - attr = PyStackRef_FromPyObjectSteal(PyObject_GetAttr(super, name)); + PyObject *attr_o = PyObject_GetAttr(super, name); Py_DECREF(super); - ERROR_IF(PyStackRef_IsNull(attr), error); + ERROR_IF(attr_o == NULL, error); + attr = PyStackRef_FromPyObjectSteal(attr_o); null = PyStackRef_NULL; } @@ -2740,9 +2741,10 @@ dummy_func( inst(GET_ITER, (iterable -- iter)) { /* before: [obj]; after [getiter(obj)] */ - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable))); + PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); DECREF_INPUTS(); - ERROR_IF(PyStackRef_IsNull(iter), error); + ERROR_IF(iter_o == NULL, error); + iter = PyStackRef_FromPyObjectSteal(iter_o); } inst(GET_YIELD_FROM_ITER, (iterable -- iter)) { @@ -3052,16 +3054,18 @@ dummy_func( PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner); PyObject *name = _Py_SpecialMethods[oparg].name; PyObject *self_or_null_o; - attr = PyStackRef_FromPyObjectSteal(_PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o)); - if (PyStackRef_IsNull(attr)) { + PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o); + if (attr_o == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, _Py_SpecialMethods[oparg].error, Py_TYPE(owner_o)->tp_name); } + ERROR_IF(true, error); } - ERROR_IF(PyStackRef_IsNull(attr), error); - self_or_null = PyStackRef_FromPyObjectSteal(self_or_null_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); + self_or_null = self_or_null_o == NULL ? + PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o); } inst(WITH_EXCEPT_START, (exit_func, exit_self, lasti, unused, val -- exit_func, exit_self, lasti, unused, val, res)) { @@ -3092,9 +3096,10 @@ dummy_func( (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); - res = PyStackRef_FromPyObjectSteal(PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, - (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL)); - ERROR_IF(PyStackRef_IsNull(res), error); + PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, + (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); } pseudo(SETUP_FINALLY, (-- unused), (HAS_ARG)) = { @@ -4539,9 +4544,10 @@ dummy_func( /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value_o)) { - res = PyStackRef_FromPyObjectSteal(PyObject_Format(value_o, NULL)); + PyObject *res_o = PyObject_Format(value_o, NULL); PyStackRef_CLOSE(value); - ERROR_IF(PyStackRef_IsNull(res), error); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); } else { res = value; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 7631ff75ecafd6..4574e183921006 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3281,10 +3281,11 @@ iterable = stack_pointer[-1]; /* before: [obj]; after [getiter(obj)] */ _PyFrame_SetStackPointer(frame, stack_pointer); - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable))); + PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); - if (PyStackRef_IsNull(iter)) JUMP_TO_ERROR(); + if (iter_o == NULL) JUMP_TO_ERROR(); + iter = PyStackRef_FromPyObjectSteal(iter_o); stack_pointer[-1] = iter; break; } @@ -3552,24 +3553,21 @@ stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - attr = PyStackRef_FromPyObjectSteal(_PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o)); + PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(attr)) { + if (attr_o == NULL) { if (!_PyErr_Occurred(tstate)) { - stack_pointer[0] = attr; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, _Py_SpecialMethods[oparg].error, Py_TYPE(owner_o)->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); } + if (true) JUMP_TO_ERROR(); } - if (PyStackRef_IsNull(attr)) JUMP_TO_ERROR(); - self_or_null = PyStackRef_FromPyObjectSteal(self_or_null_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); + self_or_null = self_or_null_o == NULL ? + PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o); stack_pointer[0] = attr; stack_pointer[1] = self_or_null; stack_pointer += 2; @@ -3613,10 +3611,11 @@ PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); _PyFrame_SetStackPointer(frame, stack_pointer); - res = PyStackRef_FromPyObjectSteal(PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, - (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL)); + PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, + (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(res)) JUMP_TO_ERROR(); + if (res_o == NULL) JUMP_TO_ERROR(); + res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -5373,10 +5372,11 @@ * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value_o)) { _PyFrame_SetStackPointer(frame, stack_pointer); - res = PyStackRef_FromPyObjectSteal(PyObject_Format(value_o, NULL)); + PyObject *res_o = PyObject_Format(value_o, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); - if (PyStackRef_IsNull(res)) JUMP_TO_ERROR(); + if (res_o == NULL) JUMP_TO_ERROR(); + res = PyStackRef_FromPyObjectSteal(res_o); } else { res = value; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a9c127784edc83..e1107caa197d7a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3856,10 +3856,11 @@ * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value_o)) { _PyFrame_SetStackPointer(frame, stack_pointer); - res = PyStackRef_FromPyObjectSteal(PyObject_Format(value_o, NULL)); + PyObject *res_o = PyObject_Format(value_o, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(value); - if (PyStackRef_IsNull(res)) goto pop_1_error; + if (res_o == NULL) goto pop_1_error; + res = PyStackRef_FromPyObjectSteal(res_o); } else { res = value; @@ -4239,10 +4240,11 @@ iterable = stack_pointer[-1]; /* before: [obj]; after [getiter(obj)] */ _PyFrame_SetStackPointer(frame, stack_pointer); - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable))); + PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); PyStackRef_CLOSE(iterable); - if (PyStackRef_IsNull(iter)) goto pop_1_error; + if (iter_o == NULL) goto pop_1_error; + iter = PyStackRef_FromPyObjectSteal(iter_o); stack_pointer[-1] = iter; DISPATCH(); } @@ -6270,29 +6272,21 @@ stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - attr = PyStackRef_FromPyObjectSteal(_PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o)); + PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(attr)) { + if (attr_o == NULL) { if (!_PyErr_Occurred(tstate)) { - stack_pointer[0] = attr; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, _Py_SpecialMethods[oparg].error, Py_TYPE(owner_o)->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); } + if (true) goto error; } - if (PyStackRef_IsNull(attr)) { - stack_pointer[0] = attr; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - goto error; - } - self_or_null = PyStackRef_FromPyObjectSteal(self_or_null_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); + self_or_null = self_or_null_o == NULL ? + PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o); stack_pointer[0] = attr; stack_pointer[1] = self_or_null; stack_pointer += 2; @@ -6385,10 +6379,11 @@ stack_pointer += -3; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - attr = PyStackRef_FromPyObjectSteal(PyObject_GetAttr(super, name)); + PyObject *attr_o = PyObject_GetAttr(super, name); stack_pointer = _PyFrame_GetStackPointer(frame); Py_DECREF(super); - if (PyStackRef_IsNull(attr)) goto error; + if (attr_o == NULL) goto error; + attr = PyStackRef_FromPyObjectSteal(attr_o); null = PyStackRef_NULL; } stack_pointer[0] = attr; @@ -8139,10 +8134,11 @@ PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); _PyFrame_SetStackPointer(frame, stack_pointer); - res = PyStackRef_FromPyObjectSteal(PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, - (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL)); + PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, + (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(res)) goto error; + if (res_o == NULL) goto error; + res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); From 51d426dc033ef9208c0244a569f3e816e4c328c9 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 7 Oct 2024 20:35:56 +0300 Subject: [PATCH 033/247] gh-124956: Use `#undef` for temp macros in `_csv.c` (#124957) --- Modules/_csv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Modules/_csv.c b/Modules/_csv.c index a623ea449da779..913560ce4a0ee3 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -367,6 +367,8 @@ static struct PyMemberDef Dialect_memberlist[] = { { NULL } }; +#undef D_OFF + static PyGetSetDef Dialect_getsetlist[] = { { "delimiter", (getter)Dialect_get_delimiter}, { "escapechar", (getter)Dialect_get_escapechar}, @@ -502,6 +504,7 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) DIALECT_GETATTR(skipinitialspace, "skipinitialspace"); DIALECT_GETATTR(strict, "strict"); } +#undef DIALECT_GETATTR /* check types and convert to C values */ #define DIASET(meth, name, target, src, dflt) \ @@ -515,6 +518,7 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL); DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, false); DIASET(_set_bool, "strict", &self->strict, strict, false); +#undef DIASET /* validate options */ if (dialect_check_quoting(self->quoting)) @@ -1026,6 +1030,8 @@ static struct PyMemberDef Reader_memberlist[] = { { NULL } }; +#undef R_OFF + static PyType_Slot Reader_Type_slots[] = { {Py_tp_doc, (char*)Reader_Type_doc}, @@ -1441,6 +1447,8 @@ static struct PyMemberDef Writer_memberlist[] = { { NULL } }; +#undef W_OFF + static int Writer_traverse(WriterObj *self, visitproc visit, void *arg) { From 3287c834e5370294e310450115290979aac06efa Mon Sep 17 00:00:00 2001 From: ffelixg <142172984+ffelixg@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:52:34 +0200 Subject: [PATCH 034/247] gh-124182: Explain naming rules for struct sequence types (#124335) --- Doc/c-api/tuple.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 7a8a6134282ade..815afddad19df1 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -167,7 +167,8 @@ type. .. c:member:: const char *name - Name of the struct sequence type. + Fully qualified name of the type; null-terminated UTF-8 encoded. + The name must contain the module name. .. c:member:: const char *doc From 03775472cc69e150ced22dc30334a7a202fc0380 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 7 Oct 2024 19:54:42 +0200 Subject: [PATCH 035/247] Use _PyLong_GetOne() and _PyLong_GetZero() in long_invmod() (#125044) These functions cannot fail. --- Objects/longobject.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 6ca8d449bcf4a2..4e948940485730 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4828,21 +4828,12 @@ long_divmod(PyObject *a, PyObject *b) static PyLongObject * long_invmod(PyLongObject *a, PyLongObject *n) { - PyLongObject *b, *c; - /* Should only ever be called for positive n */ assert(_PyLong_IsPositive(n)); - b = (PyLongObject *)PyLong_FromLong(1L); - if (b == NULL) { - return NULL; - } - c = (PyLongObject *)PyLong_FromLong(0L); - if (c == NULL) { - Py_DECREF(b); - return NULL; - } Py_INCREF(a); + PyLongObject *b = (PyLongObject *)Py_NewRef(_PyLong_GetOne()); + PyLongObject *c = (PyLongObject *)Py_NewRef(_PyLong_GetZero()); Py_INCREF(n); /* references now owned: a, b, c, n */ From 7ffe94fb242fd51bb07c7f0d31e94efeea3619d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 7 Oct 2024 20:42:19 +0200 Subject: [PATCH 036/247] gh-124653: Relax (again) detection of queue API for logging handlers (GH-124897) --- Doc/library/logging.config.rst | 11 +- Lib/logging/config.py | 14 +-- Lib/test/test_logging.py | 108 +++++++++++------- ...-10-02-15-05-45.gh-issue-124653.tqsTu9.rst | 2 + 4 files changed, 79 insertions(+), 56 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 317ca8728248c8..0e9dc33ae2123a 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -753,16 +753,17 @@ The ``queue`` and ``listener`` keys are optional. If the ``queue`` key is present, the corresponding value can be one of the following: -* An object implementing the :class:`queue.Queue` public API. For instance, - this may be an actual instance of :class:`queue.Queue` or a subclass thereof, - or a proxy obtained by :meth:`multiprocessing.managers.SyncManager.Queue`. +* An object implementing the :meth:`Queue.put_nowait ` + and :meth:`Queue.get ` public API. For instance, this may be + an actual instance of :class:`queue.Queue` or a subclass thereof, or a proxy + obtained by :meth:`multiprocessing.managers.SyncManager.Queue`. This is of course only possible if you are constructing or modifying the configuration dictionary in code. * A string that resolves to a callable which, when called with no arguments, returns - the :class:`queue.Queue` instance to use. That callable could be a - :class:`queue.Queue` subclass or a function which returns a suitable queue instance, + the queue instance to use. That callable could be a :class:`queue.Queue` subclass + or a function which returns a suitable queue instance, such as ``my.module.queue_factory()``. * A dict with a ``'()'`` key which is constructed in the usual way as discussed in diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 3781cb1aeb9ae2..6a6a7f726f7e0c 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -499,7 +499,7 @@ def as_tuple(self, value): def _is_queue_like_object(obj): """Check that *obj* implements the Queue API.""" - if isinstance(obj, queue.Queue): + if isinstance(obj, (queue.Queue, queue.SimpleQueue)): return True # defer importing multiprocessing as much as possible from multiprocessing.queues import Queue as MPQueue @@ -516,13 +516,13 @@ def _is_queue_like_object(obj): # Ideally, we would have wanted to simply use strict type checking # instead of a protocol-based type checking since the latter does # not check the method signatures. - queue_interface = [ - 'empty', 'full', 'get', 'get_nowait', - 'put', 'put_nowait', 'join', 'qsize', - 'task_done', - ] + # + # Note that only 'put_nowait' and 'get' are required by the logging + # queue handler and queue listener (see gh-124653) and that other + # methods are either optional or unused. + minimal_queue_interface = ['put_nowait', 'get'] return all(callable(getattr(obj, method, None)) - for method in queue_interface) + for method in minimal_queue_interface) class DictConfigurator(BaseConfigurator): """ diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 230ba954cd286d..d4ceb7c8dc0b41 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2377,16 +2377,22 @@ def __getattr__(self, attribute): return getattr(queue, attribute) class CustomQueueFakeProtocol(CustomQueueProtocol): - # An object implementing the Queue API (incorrect signatures). + # An object implementing the minimial Queue API for + # the logging module but with incorrect signatures. + # # The object will be considered a valid queue class since we # do not check the signatures (only callability of methods) # but will NOT be usable in production since a TypeError will - # be raised due to a missing argument. - def empty(self, x): + # be raised due to the extra argument in 'put_nowait'. + def put_nowait(self): pass class CustomQueueWrongProtocol(CustomQueueProtocol): - empty = None + put_nowait = None + +class MinimalQueueProtocol: + def put_nowait(self, x): pass + def get(self): pass def queueMaker(): return queue.Queue() @@ -3946,56 +3952,70 @@ def test_config_queue_handler(self): msg = str(ctx.exception) self.assertEqual(msg, "Unable to configure handler 'ah'") + def _apply_simple_queue_listener_configuration(self, qspec): + self.apply_config({ + "version": 1, + "handlers": { + "queue_listener": { + "class": "logging.handlers.QueueHandler", + "queue": qspec, + }, + }, + }) + @threading_helper.requires_working_threading() @support.requires_subprocess() @patch("multiprocessing.Manager") def test_config_queue_handler_does_not_create_multiprocessing_manager(self, manager): - # gh-120868, gh-121723 - - from multiprocessing import Queue as MQ - - q1 = {"()": "queue.Queue", "maxsize": -1} - q2 = MQ() - q3 = queue.Queue() - # CustomQueueFakeProtocol passes the checks but will not be usable - # since the signatures are incompatible. Checking the Queue API - # without testing the type of the actual queue is a trade-off - # between usability and the work we need to do in order to safely - # check that the queue object correctly implements the API. - q4 = CustomQueueFakeProtocol() - - for qspec in (q1, q2, q3, q4): - self.apply_config( - { - "version": 1, - "handlers": { - "queue_listener": { - "class": "logging.handlers.QueueHandler", - "queue": qspec, - }, - }, - } - ) - manager.assert_not_called() + # gh-120868, gh-121723, gh-124653 + + for qspec in [ + {"()": "queue.Queue", "maxsize": -1}, + queue.Queue(), + # queue.SimpleQueue does not inherit from queue.Queue + queue.SimpleQueue(), + # CustomQueueFakeProtocol passes the checks but will not be usable + # since the signatures are incompatible. Checking the Queue API + # without testing the type of the actual queue is a trade-off + # between usability and the work we need to do in order to safely + # check that the queue object correctly implements the API. + CustomQueueFakeProtocol(), + MinimalQueueProtocol(), + ]: + with self.subTest(qspec=qspec): + self._apply_simple_queue_listener_configuration(qspec) + manager.assert_not_called() @patch("multiprocessing.Manager") def test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager(self, manager): # gh-120868, gh-121723 for qspec in [object(), CustomQueueWrongProtocol()]: - with self.assertRaises(ValueError): - self.apply_config( - { - "version": 1, - "handlers": { - "queue_listener": { - "class": "logging.handlers.QueueHandler", - "queue": qspec, - }, - }, - } - ) - manager.assert_not_called() + with self.subTest(qspec=qspec), self.assertRaises(ValueError): + self._apply_simple_queue_listener_configuration(qspec) + manager.assert_not_called() + + @skip_if_tsan_fork + @support.requires_subprocess() + @unittest.skipUnless(support.Py_DEBUG, "requires a debug build for testing" + " assertions in multiprocessing") + def test_config_reject_simple_queue_handler_multiprocessing_context(self): + # multiprocessing.SimpleQueue does not implement 'put_nowait' + # and thus cannot be used as a queue-like object (gh-124653) + + import multiprocessing + + if support.MS_WINDOWS: + start_methods = ['spawn'] + else: + start_methods = ['spawn', 'fork', 'forkserver'] + + for start_method in start_methods: + with self.subTest(start_method=start_method): + ctx = multiprocessing.get_context(start_method) + qspec = ctx.SimpleQueue() + with self.assertRaises(ValueError): + self._apply_simple_queue_listener_configuration(qspec) @skip_if_tsan_fork @support.requires_subprocess() diff --git a/Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst b/Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst new file mode 100644 index 00000000000000..6f5ad12d2c2981 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst @@ -0,0 +1,2 @@ +Fix detection of the minimal Queue API needed by the :mod:`logging` module. +Patch by Bénédikt Tran. From c5df1cb7bde7e86f046196b0e34a0b90f8fc11de Mon Sep 17 00:00:00 2001 From: Zhikang Yan <2951256653@qq.com> Date: Tue, 8 Oct 2024 02:52:09 +0800 Subject: [PATCH 037/247] gh-122392: IDLE - Fix overlapping lines in browsers (#122392) (#124975) Increase currently inadequate vertical spacing for the IDLE browsers (path, module, and stack) on high-resolution monitors. --------- Co-authored-by: Terry Jan Reedy --- Lib/idlelib/tree.py | 14 ++++++++++---- .../2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst diff --git a/Lib/idlelib/tree.py b/Lib/idlelib/tree.py index 0726d7e23660f6..182ce7189614da 100644 --- a/Lib/idlelib/tree.py +++ b/Lib/idlelib/tree.py @@ -83,6 +83,8 @@ def wheel_event(event, widget=None): class TreeNode: + dy = 0 + def __init__(self, canvas, parent, item): self.canvas = canvas self.parent = parent @@ -199,23 +201,22 @@ def update(self): def draw(self, x, y): # XXX This hard-codes too many geometry constants! - dy = 20 self.x, self.y = x, y self.drawicon() self.drawtext() if self.state != 'expanded': - return y + dy + return y + TreeNode.dy # draw children if not self.children: sublist = self.item._GetSubList() if not sublist: # _IsExpandable() was mistaken; that's allowed - return y+17 + return y + TreeNode.dy for item in sublist: child = self.__class__(self.canvas, self, item) self.children.append(child) cx = x+20 - cy = y + dy + cy = y + TreeNode.dy cylast = 0 for child in self.children: cylast = cy @@ -289,6 +290,11 @@ def drawtext(self): self.label.bind("", lambda e: wheel_event(e, self.canvas)) self.label.bind("", lambda e: wheel_event(e, self.canvas)) self.text_id = id + if TreeNode.dy == 0: + # The first row doesn't matter what the dy is, just measure its + # size to get the value of the subsequent dy + coords = self.canvas.bbox(id) + TreeNode.dy = max(20, coords[3] - coords[1] - 3) def select_or_edit(self, event=None): if self.selected and self.item.IsEditable(): diff --git a/Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst b/Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst new file mode 100644 index 00000000000000..541f6212794ef2 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst @@ -0,0 +1,2 @@ +Increase currently inadequate vertical spacing for the IDLE browsers (path, +module, and stack) on high-resolution monitors. From a7f0727ca575fef4d8891b5ebfe71ef2a774868b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 7 Oct 2024 23:24:53 +0200 Subject: [PATCH 038/247] gh-124502: Add PyUnicode_Equal() function (#124504) --- Doc/c-api/unicode.rst | 25 ++++++++++++++ Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.14.rst | 4 +++ Include/unicodeobject.h | 4 +++ Lib/test/test_capi/test_unicode.py | 33 +++++++++++++++++++ Lib/test/test_stable_abi_ctypes.py | 1 + ...-09-25-11-44-02.gh-issue-124502.qWuDjT.rst | 2 ++ Misc/stable_abi.toml | 2 ++ Modules/_testlimitedcapi/unicode.c | 22 +++++++++++-- Objects/unicodeobject.c | 18 ++++++++++ PC/python3dll.c | 1 + 11 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index b2ac0c903c2bd7..f5704cffa199a5 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1438,6 +1438,31 @@ They all return ``NULL`` or ``-1`` if an exception occurs. This function returns ``-1`` upon failure, so one should call :c:func:`PyErr_Occurred` to check for errors. + .. seealso:: + + The :c:func:`PyUnicode_Equal` function. + + +.. c:function:: int PyUnicode_Equal(PyObject *a, PyObject *b) + + Test if two strings are equal: + + * Return ``1`` if *a* is equal to *b*. + * Return ``0`` if *a* is not equal to *b*. + * Set a :exc:`TypeError` exception and return ``-1`` if *a* or *b* is not a + :class:`str` object. + + The function always succeeds if *a* and *b* are :class:`str` objects. + + The function works for :class:`str` subclasses, but does not honor custom + ``__eq__()`` method. + + .. seealso:: + + The :c:func:`PyUnicode_Compare` function. + + .. versionadded:: 3.14 + .. c:function:: int PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *string, Py_ssize_t size) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 19dc71a345b474..9314facd2ad873 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -783,6 +783,7 @@ func,PyUnicode_DecodeUnicodeEscape,3.2,, func,PyUnicode_EncodeCodePage,3.7,on Windows, func,PyUnicode_EncodeFSDefault,3.2,, func,PyUnicode_EncodeLocale,3.7,, +func,PyUnicode_Equal,3.14,, func,PyUnicode_EqualToUTF8,3.13,, func,PyUnicode_EqualToUTF8AndSize,3.13,, func,PyUnicode_FSConverter,3.2,, diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 67d8d389b58082..f1f78ed843f313 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -687,6 +687,10 @@ New Features `__ mentioned in :pep:`630` (:gh:`124153`). +* Add :c:func:`PyUnicode_Equal` function to the limited C API: + test if two strings are equal. + (Contributed by Victor Stinner in :gh:`124502`.) + Porting to Python 3.14 ---------------------- diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h index dee00715b3c51d..2ce3a008b7129e 100644 --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -966,6 +966,10 @@ PyAPI_FUNC(int) PyUnicode_EqualToUTF8(PyObject *, const char *); PyAPI_FUNC(int) PyUnicode_EqualToUTF8AndSize(PyObject *, const char *, Py_ssize_t); #endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 +PyAPI_FUNC(int) PyUnicode_Equal(PyObject *str1, PyObject *str2); +#endif + /* Rich compare two strings and return one of the following: - NULL in case an exception was raised diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index e6f85427214958..65d8242ad3fc60 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -1903,6 +1903,39 @@ def test_recover_error(self): self.assertEqual(writer.finish(), 'Hello World.') + def test_unicode_equal(self): + unicode_equal = _testlimitedcapi.unicode_equal + + def copy(text): + return text.encode().decode() + + self.assertTrue(unicode_equal("", "")) + self.assertTrue(unicode_equal("abc", "abc")) + self.assertTrue(unicode_equal("abc", copy("abc"))) + self.assertTrue(unicode_equal("\u20ac", copy("\u20ac"))) + self.assertTrue(unicode_equal("\U0010ffff", copy("\U0010ffff"))) + + self.assertFalse(unicode_equal("abc", "abcd")) + self.assertFalse(unicode_equal("\u20ac", "\u20ad")) + self.assertFalse(unicode_equal("\U0010ffff", "\U0010fffe")) + + # str subclass + self.assertTrue(unicode_equal("abc", Str("abc"))) + self.assertTrue(unicode_equal(Str("abc"), "abc")) + self.assertFalse(unicode_equal("abc", Str("abcd"))) + self.assertFalse(unicode_equal(Str("abc"), "abcd")) + + # invalid type + for invalid_type in (b'bytes', 123, ("tuple",)): + with self.subTest(invalid_type=invalid_type): + with self.assertRaises(TypeError): + unicode_equal("abc", invalid_type) + with self.assertRaises(TypeError): + unicode_equal(invalid_type, "abc") + + # CRASHES unicode_equal("abc", NULL) + # CRASHES unicode_equal(NULL, "abc") + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index d16ad7ef5d4328..b14d500a9c6e97 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -805,6 +805,7 @@ def test_windows_feature_macros(self): "PyUnicode_DecodeUnicodeEscape", "PyUnicode_EncodeFSDefault", "PyUnicode_EncodeLocale", + "PyUnicode_Equal", "PyUnicode_EqualToUTF8", "PyUnicode_EqualToUTF8AndSize", "PyUnicode_FSConverter", diff --git a/Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst b/Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst new file mode 100644 index 00000000000000..f515619328b359 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst @@ -0,0 +1,2 @@ +Add :c:func:`PyUnicode_Equal` function to the limited C API: test if two +strings are equal. Patch by Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index fe0a5e44f8fb15..62978261745d79 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2536,3 +2536,5 @@ added = '3.14' [const.Py_TP_USE_SPEC] added = '3.14' +[function.PyUnicode_Equal] + added = '3.14' diff --git a/Modules/_testlimitedcapi/unicode.c b/Modules/_testlimitedcapi/unicode.c index 2b70d09108a333..c7a23d5d1cbd71 100644 --- a/Modules/_testlimitedcapi/unicode.c +++ b/Modules/_testlimitedcapi/unicode.c @@ -1,7 +1,7 @@ #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED - // Need limited C API 3.13 to test PyUnicode_EqualToUTF8() -# define Py_LIMITED_API 0x030d0000 + // Need limited C API 3.14 to test PyUnicode_Equal() +# define Py_LIMITED_API 0x030e0000 #endif #include "parts.h" @@ -1837,6 +1837,23 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) #undef CHECK_FORMAT_0 } + +/* Test PyUnicode_Equal() */ +static PyObject * +unicode_equal(PyObject *module, PyObject *args) +{ + PyObject *str1, *str2; + if (!PyArg_ParseTuple(args, "OO", &str1, &str2)) { + return NULL; + } + + NULLABLE(str1); + NULLABLE(str2); + RETURN_INT(PyUnicode_Equal(str1, str2)); +} + + + static PyMethodDef TestMethods[] = { {"codec_incrementalencoder", codec_incrementalencoder, METH_VARARGS}, {"codec_incrementaldecoder", codec_incrementaldecoder, METH_VARARGS}, @@ -1924,6 +1941,7 @@ static PyMethodDef TestMethods[] = { {"unicode_format", unicode_format, METH_VARARGS}, {"unicode_contains", unicode_contains, METH_VARARGS}, {"unicode_isidentifier", unicode_isidentifier, METH_O}, + {"unicode_equal", unicode_equal, METH_VARARGS}, {NULL}, }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index e9589cfe44f3bf..60d4875d3b393e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -11001,6 +11001,24 @@ _PyUnicode_Equal(PyObject *str1, PyObject *str2) } +int +PyUnicode_Equal(PyObject *str1, PyObject *str2) +{ + if (!PyUnicode_Check(str1)) { + PyErr_Format(PyExc_TypeError, + "first argument must be str, not %T", str1); + return -1; + } + if (!PyUnicode_Check(str2)) { + PyErr_Format(PyExc_TypeError, + "second argument must be str, not %T", str2); + return -1; + } + + return _PyUnicode_Equal(str1, str2); +} + + int PyUnicode_Compare(PyObject *left, PyObject *right) { diff --git a/PC/python3dll.c b/PC/python3dll.c index 6b8208ab90bd95..9296474617e115 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -717,6 +717,7 @@ EXPORT_FUNC(PyUnicode_DecodeUTF8Stateful) EXPORT_FUNC(PyUnicode_EncodeCodePage) EXPORT_FUNC(PyUnicode_EncodeFSDefault) EXPORT_FUNC(PyUnicode_EncodeLocale) +EXPORT_FUNC(PyUnicode_Equal) EXPORT_FUNC(PyUnicode_EqualToUTF8) EXPORT_FUNC(PyUnicode_EqualToUTF8AndSize) EXPORT_FUNC(PyUnicode_Find) From 447a15190d6d766004b77619ba43e44256e348e2 Mon Sep 17 00:00:00 2001 From: Emily Morehouse Date: Mon, 7 Oct 2024 16:51:14 -0600 Subject: [PATCH 039/247] gh-125072: Add label for assignment expressions; update tracked section for assignment expression topic (#125074) --- Doc/reference/expressions.rst | 2 + Doc/tools/extensions/pyspecific.py | 4 +- Lib/pydoc_data/topics.py | 64 +++++++++++++++++------------- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index ab72ad49d041e1..decde0d297cf59 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1809,6 +1809,8 @@ returns a boolean value regardless of the type of its argument single: named expression pair: assignment; expression +.. _assignment-expressions: + Assignment expressions ====================== diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index c89b1693343b4e..b6623a2b8e01f1 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -353,8 +353,8 @@ def run(self): # Support for building "topic help" for pydoc pydoc_topic_labels = [ - 'assert', 'assignment', 'async', 'atom-identifiers', 'atom-literals', - 'attribute-access', 'attribute-references', 'augassign', 'await', + 'assert', 'assignment', 'assignment-expressions', 'async', 'atom-identifiers', + 'atom-literals', 'attribute-access', 'attribute-references', 'augassign', 'await', 'binary', 'bitwise', 'bltin-code-objects', 'bltin-ellipsis-object', 'bltin-null-object', 'bltin-type-objects', 'booleans', 'break', 'callable-types', 'calls', 'class', 'comparisons', 'compound', diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 97bb4eb52f4386..ae56c136608472 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -417,33 +417,43 @@ 'caused a\n' 'syntax error.\n', 'assignment-expressions': 'Assignment expressions\n' - '**********************\n' - '\n' - 'An assignment expression (sometimes also called a “named expression”' - '\nor “walrus”) assigns an expression to an identifier, while also\n' - 'returning the value of the expression.\n' - '\n' - 'One common use case is when handling matched regular expressions:\n' - '\n' - ' if matching := pattern.search(data):\n' - ' do_something(matching)\n' - '\n' - 'Or, when processing a file stream in chunks:\n' - '\n' - ' while chunk := file.read(9000):\n' - ' process(chunk)\n' - '\n' - 'Assignment expressions must be surrounded by parentheses when used as\n' - 'expression statements and when used as sub-expressions in slicing,\n' - 'conditional, lambda, keyword-argument, and comprehension-if\n' - 'expressions and in assert, with, and assignment statements. In all\n' - 'other places where they can be used, parentheses are not required,\n' - 'including in if and while statements.\n' - '\n' - 'Added in version 3.8.\n' - 'See also:\n' - '\n' - ' **PEP 572** - Assignment Expressions\n', + '**********************\n' + '\n' + ' assignment_expression ::= [identifier ":="] ' + 'expression\n' + '\n' + 'An assignment expression (sometimes also called a ' + '“named expression”\n' + 'or “walrus”) assigns an "expression" to an ' + '"identifier", while also\n' + 'returning the value of the "expression".\n' + '\n' + 'One common use case is when handling matched ' + 'regular expressions:\n' + '\n' + ' if matching := pattern.search(data):\n' + ' do_something(matching)\n' + '\n' + 'Or, when processing a file stream in chunks:\n' + '\n' + ' while chunk := file.read(9000):\n' + ' process(chunk)\n' + '\n' + 'Assignment expressions must be surrounded by ' + 'parentheses when used as\n' + 'expression statements and when used as ' + 'sub-expressions in slicing,\n' + 'conditional, lambda, keyword-argument, and ' + 'comprehension-if\n' + 'expressions and in "assert", "with", and ' + '"assignment" statements. In\n' + 'all other places where they can be used, ' + 'parentheses are not required,\n' + 'including in "if" and "while" statements.\n' + '\n' + 'Added in version 3.8: See **PEP 572** for more ' + 'details about\n' + 'assignment expressions.\n', 'async': 'Coroutines\n' '**********\n' '\n' From 6e3c70c61bf961e55e9912a31ca11f61c8e2cd0c Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 7 Oct 2024 19:41:13 -0400 Subject: [PATCH 040/247] Docs: make a tutorial example more precise (#125066) Based on discussion here: https://discuss.python.org/t/omission-in-the-documentation/66816 --- Doc/tutorial/introduction.rst | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 054bac59c955d5..65e3b1938bca9c 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -197,21 +197,19 @@ and workarounds. String literals can span multiple lines. One way is using triple-quotes: ``"""..."""`` or ``'''...'''``. End of lines are automatically included in the string, but it's possible to prevent this by adding a ``\`` at -the end of the line. The following example:: - - print("""\ +the end of the line. In the following example, the initial newline is not +included:: + + >>> print("""\ + ... Usage: thingy [OPTIONS] + ... -h Display this usage message + ... -H hostname Hostname to connect to + ... """) Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to - """) - -produces the following output (note that the initial newline is not included): -.. code-block:: text - - Usage: thingy [OPTIONS] - -h Display this usage message - -H hostname Hostname to connect to + >>> Strings can be concatenated (glued together) with the ``+`` operator, and repeated with ``*``:: From cc9b9bebb2c09c475cb0f278268cce03c115eaea Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Mon, 7 Oct 2024 23:50:42 -0700 Subject: [PATCH 041/247] gh-90102: Remove isatty call during regular open (#124922) Co-authored-by: Victor Stinner --- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 ++++ Lib/_pyio.py | 17 +++++++++++++- ...4-10-02-22-53-48.gh-issue-90102.4qX52R.rst | 3 +++ Modules/_io/_iomodule.c | 2 +- Modules/_io/fileio.c | 22 ++++++++++++++++--- Modules/_io/winconsoleio.c | 1 + 9 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 28a76c36801b4b..3140a75a47c5ee 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -757,6 +757,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_initializing)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_io)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_is_text_encoding)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_isatty_open_only)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_length_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_limbo)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_lock_unlock_module)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index ac789b06fb8a61..1591cb0a3f114f 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -246,6 +246,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(_initializing) STRUCT_FOR_ID(_io) STRUCT_FOR_ID(_is_text_encoding) + STRUCT_FOR_ID(_isatty_open_only) STRUCT_FOR_ID(_length_) STRUCT_FOR_ID(_limbo) STRUCT_FOR_ID(_lock_unlock_module) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 7847a5c63ebf3f..c9d20d0b5aacdb 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -755,6 +755,7 @@ extern "C" { INIT_ID(_initializing), \ INIT_ID(_io), \ INIT_ID(_is_text_encoding), \ + INIT_ID(_isatty_open_only), \ INIT_ID(_length_), \ INIT_ID(_limbo), \ INIT_ID(_lock_unlock_module), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index a688f70a2ba36f..d335373e88ee74 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -784,6 +784,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(_isatty_open_only); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_length_); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 18849b309b8605..2a1d2a33d02960 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -238,7 +238,7 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, result = raw try: line_buffering = False - if buffering == 1 or buffering < 0 and raw.isatty(): + if buffering == 1 or buffering < 0 and raw._isatty_open_only(): buffering = -1 line_buffering = True if buffering < 0: @@ -1794,6 +1794,21 @@ def isatty(self): self._checkClosed() return os.isatty(self._fd) + def _isatty_open_only(self): + """Checks whether the file is a TTY using an open-only optimization. + + TTYs are always character devices. If the interpreter knows a file is + not a character device when it would call ``isatty``, can skip that + call. Inside ``open()`` there is a fresh stat result that contains that + information. Use the stat result to skip a system call. Outside of that + context TOCTOU issues (the fd could be arbitrarily modified by + surrounding code). + """ + if (self._stat_atopen is not None + and not stat.S_ISCHR(self._stat_atopen.st_mode)): + return True + return os.isatty(self._fd) + @property def closefd(self): """True if the file descriptor will be closed by close().""" diff --git a/Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst b/Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst new file mode 100644 index 00000000000000..0e708ed11d21b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst @@ -0,0 +1,3 @@ +Skip the ``isatty`` system call during open() when the file is known to not +be a character device. This provides a slight performance improvement when +reading whole files. diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1238e6074246d0..6622f2cabb908b 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -346,7 +346,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, /* buffering */ if (buffering < 0) { - PyObject *res = PyObject_CallMethodNoArgs(raw, &_Py_ID(isatty)); + PyObject *res = PyObject_CallMethodNoArgs(raw, &_Py_ID(_isatty_open_only)); if (res == NULL) goto error; isatty = PyObject_IsTrue(res); diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index d9597f860b9429..f374592eb95967 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -12,9 +12,6 @@ #ifdef HAVE_SYS_TYPES_H # include #endif -#ifdef HAVE_SYS_STAT_H -# include -#endif #ifdef HAVE_IO_H # include #endif @@ -1218,6 +1215,24 @@ _io_FileIO_isatty_impl(fileio *self) return PyBool_FromLong(res); } +/* Checks whether the file is a TTY using an open-only optimization. + + TTYs are always character devices. If the interpreter knows a file is + not a character device when it would call ``isatty``, can skip that + call. Inside ``open()`` there is a fresh stat result that contains that + information. Use the stat result to skip a system call. Outside of that + context TOCTOU issues (the fd could be arbitrarily modified by + surrounding code). */ +static PyObject * +_io_FileIO_isatty_open_only(PyObject *op, PyObject *Py_UNUSED(ignored)) +{ + fileio *self = _PyFileIO_CAST(op); + if (self->stat_atopen != NULL && !S_ISCHR(self->stat_atopen->st_mode)) { + Py_RETURN_FALSE; + } + return _io_FileIO_isatty_impl(self); +} + #include "clinic/fileio.c.h" static PyMethodDef fileio_methods[] = { @@ -1234,6 +1249,7 @@ static PyMethodDef fileio_methods[] = { _IO_FILEIO_WRITABLE_METHODDEF _IO_FILEIO_FILENO_METHODDEF _IO_FILEIO_ISATTY_METHODDEF + {"_isatty_open_only", _io_FileIO_isatty_open_only, METH_NOARGS}, {"_dealloc_warn", fileio_dealloc_warn, METH_O, NULL}, {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS}, {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O}, diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index ec5c298066a587..d7cb5abfdc0abd 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -1128,6 +1128,7 @@ static PyMethodDef winconsoleio_methods[] = { _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF + {"_isatty_open_only", (PyCFunction)_io__WindowsConsoleIO_isatty, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; From 27390990fa9306e2a797a4eb2bd83c5bfc7cb186 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Tue, 8 Oct 2024 17:52:12 +1000 Subject: [PATCH 042/247] gh-70870: Clarify dual usage of 'free variable' (#122545) The term "free variable" has unfortunately become genuinely ambiguous over the years (presumably due to the names of some relevant code object instance attributes). While we can't eliminate that ambiguity at this late date, we can at least alert people to the potential ambiguity by describing both the formal meaning of the term and the common alternative use as a direct synonym for "closure variable". --------- Co-authored-by: Carol Willing --- Doc/c-api/code.rst | 9 ++++-- Doc/glossary.rst | 29 +++++++++++++++++++ Doc/library/dis.rst | 14 ++++----- Doc/library/functions.rst | 7 +++-- Doc/library/symtable.rst | 5 ++-- Doc/library/types.rst | 2 +- Doc/reference/datamodel.rst | 13 ++++++--- Doc/reference/executionmodel.rst | 5 +++- ...4-08-01-17-18-21.gh-issue-70870.fZnBM9.rst | 3 ++ 9 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index 6ae6bfe4aa6ab4..6eae24b38fae48 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -32,11 +32,13 @@ bound into a function. .. c:function:: Py_ssize_t PyCode_GetNumFree(PyCodeObject *co) - Return the number of free variables in a code object. + Return the number of :term:`free (closure) variables ` + in a code object. .. c:function:: int PyUnstable_Code_GetFirstFree(PyCodeObject *co) - Return the position of the first free variable in a code object. + Return the position of the first :term:`free (closure) variable ` + in a code object. .. versionchanged:: 3.13 @@ -144,7 +146,8 @@ bound into a function. Equivalent to the Python code ``getattr(co, 'co_freevars')``. Returns a new reference to a :c:type:`PyTupleObject` containing the names of - the free variables. On error, ``NULL`` is returned and an exception is raised. + the :term:`free (closure) variables `. On error, ``NULL`` is returned + and an exception is raised. .. versionadded:: 3.11 diff --git a/Doc/glossary.rst b/Doc/glossary.rst index e72a8d002d507d..933fb0319452a6 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -231,6 +231,28 @@ Glossary A variable defined in a class and intended to be modified only at class level (i.e., not in an instance of the class). + closure variable + A :term:`free variable` referenced from a :term:`nested scope` that is defined in an outer + scope rather than being resolved at runtime from the globals or builtin namespaces. + May be explicitly defined with the :keyword:`nonlocal` keyword to allow write access, + or implicitly defined if the variable is only being read. + + For example, in the ``inner`` function in the following code, both ``x`` and ``print`` are + :term:`free variables `, but only ``x`` is a *closure variable*:: + + def outer(): + x = 0 + def inner(): + nonlocal x + x += 1 + print(x) + return inner + + Due to the :attr:`codeobject.co_freevars` attribute (which, despite its name, only + includes the names of closure variables rather than listing all referenced free + variables), the more general :term:`free variable` term is sometimes used even + when the intended meaning is to refer specifically to closure variables. + complex number An extension of the familiar real number system in which all numbers are expressed as a sum of a real part and an imaginary part. Imaginary @@ -454,6 +476,13 @@ Glossary the :term:`global interpreter lock` which allows only one thread to execute Python bytecode at a time. See :pep:`703`. + free variable + Formally, as defined in the :ref:`language execution model `, a free + variable is any variable used in a namespace which is not a local variable in that + namespace. See :term:`closure variable` for an example. + Pragmatically, due to the name of the :attr:`codeobject.co_freevars` attribute, + the term is also sometimes used as a synonym for :term:`closure variable`. + function A series of statements which returns some value to a caller. It can also be passed zero or more :term:`arguments ` which may be used in diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index e3919c2ffad84c..75b84a8d827bc9 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1434,7 +1434,7 @@ iterations of the loop. slot ``i`` of the "fast locals" storage in this mapping. If the name is not found there, loads it from the cell contained in slot ``i``, similar to :opcode:`LOAD_DEREF`. This is used for loading - free variables in class bodies (which previously used + :term:`closure variables ` in class bodies (which previously used :opcode:`!LOAD_CLASSDEREF`) and in :ref:`annotation scopes ` within class bodies. @@ -1463,8 +1463,8 @@ iterations of the loop. .. opcode:: COPY_FREE_VARS (n) - Copies the ``n`` free variables from the closure into the frame. - Removes the need for special code on the caller's side when calling + Copies the ``n`` :term:`free (closure) variables ` from the closure + into the frame. Removes the need for special code on the caller's side when calling closures. .. versionadded:: 3.11 @@ -1937,10 +1937,10 @@ instructions: .. data:: hasfree - Sequence of bytecodes that access a free variable. 'free' in this - context refers to names in the current scope that are referenced by inner - scopes or names in outer scopes that are referenced from this scope. It does - *not* include references to global or builtin scopes. + Sequence of bytecodes that access a :term:`free (closure) variable `. + 'free' in this context refers to names in the current scope that are + referenced by inner scopes or names in outer scopes that are referenced + from this scope. It does *not* include references to global or builtin scopes. .. data:: hasname diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index a96f69e6170f00..7f8df704a33327 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -684,9 +684,10 @@ are always available. They are listed here in alphabetical order. ``__builtins__`` dictionary into *globals* before passing it to :func:`exec`. The *closure* argument specifies a closure--a tuple of cellvars. - It's only valid when the *object* is a code object containing free variables. - The length of the tuple must exactly match the number of free variables - referenced by the code object. + It's only valid when the *object* is a code object containing + :term:`free (closure) variables `. + The length of the tuple must exactly match the length of the code object'S + :attr:`~codeobject.co_freevars` attribute. .. audit-event:: exec code_object exec diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index 15e0b23aa12bf0..56cd6b8afaa73e 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -167,11 +167,12 @@ Examining Symbol Tables .. method:: get_nonlocals() - Return a tuple containing names of nonlocals in this function. + Return a tuple containing names of explicitly declared nonlocals in this function. .. method:: get_frees() - Return a tuple containing names of free variables in this function. + Return a tuple containing names of :term:`free (closure) variables ` + in this function. .. class:: Class diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 3c3c760c206ff2..84b80ec6efd59f 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -199,7 +199,7 @@ Standard names are defined for the following types: .. data:: CellType The type for cell objects: such objects are used as containers for - a function's free variables. + a function's :term:`closure variables `. .. versionadded:: 3.8 diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 513199d21456bf..d059a660548c7e 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -564,8 +564,9 @@ Special read-only attributes in which the function was defined. * - .. attribute:: function.__closure__ - - ``None`` or a :class:`tuple` of cells that contain bindings for the - function's free variables. + - ``None`` or a :class:`tuple` of cells that contain bindings for the names specified + in the :attr:`~codeobject.co_freevars` attribute of the function's + :attr:`code object `. A cell object has the attribute ``cell_contents``. This can be used to get the value of the cell, as well as set the value. @@ -1285,10 +1286,14 @@ Special read-only attributes * - .. attribute:: codeobject.co_cellvars - A :class:`tuple` containing the names of :ref:`local variables ` - that are referenced by nested functions inside the function + that are referenced from at least one :term:`nested scope` inside the function * - .. attribute:: codeobject.co_freevars - - A :class:`tuple` containing the names of free variables in the function + - A :class:`tuple` containing the names of + :term:`free (closure) variables ` that a :term:`nested scope` + references in an outer scope. See also :attr:`function.__closure__`. + + Note: references to global and builtin names are *not* included. * - .. attribute:: codeobject.co_code - A string representing the sequence of :term:`bytecode` instructions in diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index 99cb09d09331d8..cb6c524dd97a30 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -90,7 +90,7 @@ If a name is bound in a block, it is a local variable of that block, unless declared as :keyword:`nonlocal` or :keyword:`global`. If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.) If a variable is used in a code block but not -defined there, it is a :dfn:`free variable`. +defined there, it is a :term:`free variable`. Each occurrence of a name in the program text refers to the :dfn:`binding` of that name established by the following name resolution rules. @@ -337,6 +337,9 @@ enclosing namespace, but in the global namespace. [#]_ The :func:`exec` and :func:`eval` functions have optional arguments to override the global and local namespace. If only one namespace is specified, it is used for both. +.. XXX(ncoghlan) above is only accurate for string execution. When executing code objects, + closure cells may now be passed explicitly to resolve co_freevars references. + Docs issue: https://github.com/python/cpython/issues/122826 .. _exceptions: diff --git a/Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst b/Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst new file mode 100644 index 00000000000000..ba607bf7a42cd9 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst @@ -0,0 +1,3 @@ +Clarified the dual usage of the term "free variable" (both the formal +meaning of any reference to names defined outside the local scope, and the +narrower pragmatic meaning of nonlocal variables named in ``co_freevars``). From 93b9e6bd7d48150d8a5d16cea39246a980e073cb Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 8 Oct 2024 11:27:49 +0300 Subject: [PATCH 043/247] gh-69998: Fix decoding error in locale.nl_langinfo() (GH-124963) The function now sets temporarily the LC_CTYPE locale to the locale of the category that determines the requested value if the locales are different and the resulting string is non-ASCII. This temporary change affects other threads. --- Doc/library/locale.rst | 9 + Doc/whatsnew/3.14.rst | 6 + Lib/test/test__locale.py | 12 +- ...4-10-04-12-43-03.gh-issue-69998.DVqOXX.rst | 3 + Modules/_localemodule.c | 193 ++++++++++++------ 5 files changed, 153 insertions(+), 70 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 0246f99157024a..04035b33d0ed48 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -314,6 +314,15 @@ The :mod:`locale` module defines the following exception and functions: Get a representation of up to 100 values used to represent the values 0 to 99. + The function temporarily sets the ``LC_CTYPE`` locale to the locale + of the category that determines the requested value (``LC_TIME``, + ``LC_NUMERIC``, ``LC_MONETARY`` or ``LC_MESSAGES``) if locales are + different and the resulting string is non-ASCII. + This temporary change affects other threads. + + .. versionchanged:: 3.14 + The function now temporarily sets the ``LC_CTYPE`` locale in some cases. + .. function:: getdefaultlocale([envvars]) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index f1f78ed843f313..4d71a24e9cc9ca 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -587,6 +587,12 @@ Changes in the Python API Wrap it in :func:`staticmethod` if you want to preserve the old behavior. (Contributed by Serhiy Storchaka and Dominykas Grigonis in :gh:`121027`.) +* The :func:`locale.nl_langinfo` function now sets temporarily the ``LC_CTYPE`` + locale in some cases. + This temporary change affects other threads. + (Contributed by Serhiy Storchaka in :gh:`69998`.) + + Build Changes ============= diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py index 0947464bb8c04e..ba2d31f9c1ee9d 100644 --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -115,16 +115,17 @@ def numeric_tester(self, calc_type, calc_value, data_type, used_locale): def test_lc_numeric_nl_langinfo(self): # Test nl_langinfo against known values tested = False + oldloc = setlocale(LC_CTYPE) for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) - setlocale(LC_CTYPE, loc) except Error: continue for li, lc in ((RADIXCHAR, "decimal_point"), (THOUSEP, "thousands_sep")): if self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc): tested = True + self.assertEqual(setlocale(LC_CTYPE), oldloc) if not tested: self.skipTest('no suitable locales') @@ -135,10 +136,10 @@ def test_lc_numeric_nl_langinfo(self): def test_lc_numeric_localeconv(self): # Test localeconv against known values tested = False + oldloc = setlocale(LC_CTYPE) for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) - setlocale(LC_CTYPE, loc) except Error: continue formatting = localeconv() @@ -146,6 +147,7 @@ def test_lc_numeric_localeconv(self): "thousands_sep"): if self.numeric_tester('localeconv', formatting[lc], lc, loc): tested = True + self.assertEqual(setlocale(LC_CTYPE), oldloc) if not tested: self.skipTest('no suitable locales') @@ -153,10 +155,10 @@ def test_lc_numeric_localeconv(self): def test_lc_numeric_basic(self): # Test nl_langinfo against localeconv tested = False + oldloc = setlocale(LC_CTYPE) for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) - setlocale(LC_CTYPE, loc) except Error: continue for li, lc in ((RADIXCHAR, "decimal_point"), @@ -173,6 +175,7 @@ def test_lc_numeric_basic(self): nl_radixchar, li_radixchar, loc, set_locale)) tested = True + self.assertEqual(setlocale(LC_CTYPE), oldloc) if not tested: self.skipTest('no suitable locales') @@ -180,10 +183,10 @@ def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. tested = False + oldloc = setlocale(LC_CTYPE) for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) - setlocale(LC_CTYPE, loc) except Error: continue @@ -199,6 +202,7 @@ def test_float_parsing(self): self.assertRaises(ValueError, float, localeconv()['decimal_point'].join(['1', '23'])) tested = True + self.assertEqual(setlocale(LC_CTYPE), oldloc) if not tested: self.skipTest('no suitable locales') diff --git a/Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst b/Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst new file mode 100644 index 00000000000000..65388e0b4e7ee4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst @@ -0,0 +1,3 @@ +Fix :func:`locale.nl_langinfo` in case when different categories have +different locales. The function now sets temporarily the ``LC_CTYPE`` locale +in some cases. This temporary change affects other threads. diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 9452df492bb23b..ce77c4072a6aea 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -144,6 +144,17 @@ locale_is_ascii(const char *str) return (strlen(str) == 1 && ((unsigned char)str[0]) <= 127); } +static int +is_all_ascii(const char *str) +{ + for (; *str; str++) { + if ((unsigned char)*str > 127) { + return 0; + } + } + return 1; +} + static int locale_decode_monetary(PyObject *dict, struct lconv *lc) { @@ -478,113 +489,153 @@ _locale__getdefaultlocale_impl(PyObject *module) #endif #ifdef HAVE_LANGINFO_H -#define LANGINFO(X) {#X, X} +#define LANGINFO(X, Y) {#X, X, Y} static struct langinfo_constant{ - char* name; + const char *name; int value; + int category; } langinfo_constants[] = { /* These constants should exist on any langinfo implementation */ - LANGINFO(DAY_1), - LANGINFO(DAY_2), - LANGINFO(DAY_3), - LANGINFO(DAY_4), - LANGINFO(DAY_5), - LANGINFO(DAY_6), - LANGINFO(DAY_7), - - LANGINFO(ABDAY_1), - LANGINFO(ABDAY_2), - LANGINFO(ABDAY_3), - LANGINFO(ABDAY_4), - LANGINFO(ABDAY_5), - LANGINFO(ABDAY_6), - LANGINFO(ABDAY_7), - - LANGINFO(MON_1), - LANGINFO(MON_2), - LANGINFO(MON_3), - LANGINFO(MON_4), - LANGINFO(MON_5), - LANGINFO(MON_6), - LANGINFO(MON_7), - LANGINFO(MON_8), - LANGINFO(MON_9), - LANGINFO(MON_10), - LANGINFO(MON_11), - LANGINFO(MON_12), - - LANGINFO(ABMON_1), - LANGINFO(ABMON_2), - LANGINFO(ABMON_3), - LANGINFO(ABMON_4), - LANGINFO(ABMON_5), - LANGINFO(ABMON_6), - LANGINFO(ABMON_7), - LANGINFO(ABMON_8), - LANGINFO(ABMON_9), - LANGINFO(ABMON_10), - LANGINFO(ABMON_11), - LANGINFO(ABMON_12), + LANGINFO(DAY_1, LC_TIME), + LANGINFO(DAY_2, LC_TIME), + LANGINFO(DAY_3, LC_TIME), + LANGINFO(DAY_4, LC_TIME), + LANGINFO(DAY_5, LC_TIME), + LANGINFO(DAY_6, LC_TIME), + LANGINFO(DAY_7, LC_TIME), + + LANGINFO(ABDAY_1, LC_TIME), + LANGINFO(ABDAY_2, LC_TIME), + LANGINFO(ABDAY_3, LC_TIME), + LANGINFO(ABDAY_4, LC_TIME), + LANGINFO(ABDAY_5, LC_TIME), + LANGINFO(ABDAY_6, LC_TIME), + LANGINFO(ABDAY_7, LC_TIME), + + LANGINFO(MON_1, LC_TIME), + LANGINFO(MON_2, LC_TIME), + LANGINFO(MON_3, LC_TIME), + LANGINFO(MON_4, LC_TIME), + LANGINFO(MON_5, LC_TIME), + LANGINFO(MON_6, LC_TIME), + LANGINFO(MON_7, LC_TIME), + LANGINFO(MON_8, LC_TIME), + LANGINFO(MON_9, LC_TIME), + LANGINFO(MON_10, LC_TIME), + LANGINFO(MON_11, LC_TIME), + LANGINFO(MON_12, LC_TIME), + + LANGINFO(ABMON_1, LC_TIME), + LANGINFO(ABMON_2, LC_TIME), + LANGINFO(ABMON_3, LC_TIME), + LANGINFO(ABMON_4, LC_TIME), + LANGINFO(ABMON_5, LC_TIME), + LANGINFO(ABMON_6, LC_TIME), + LANGINFO(ABMON_7, LC_TIME), + LANGINFO(ABMON_8, LC_TIME), + LANGINFO(ABMON_9, LC_TIME), + LANGINFO(ABMON_10, LC_TIME), + LANGINFO(ABMON_11, LC_TIME), + LANGINFO(ABMON_12, LC_TIME), #ifdef RADIXCHAR /* The following are not available with glibc 2.0 */ - LANGINFO(RADIXCHAR), - LANGINFO(THOUSEP), + LANGINFO(RADIXCHAR, LC_NUMERIC), + LANGINFO(THOUSEP, LC_NUMERIC), /* YESSTR and NOSTR are deprecated in glibc, since they are a special case of message translation, which should be rather done using gettext. So we don't expose it to Python in the first place. - LANGINFO(YESSTR), - LANGINFO(NOSTR), + LANGINFO(YESSTR, LC_MESSAGES), + LANGINFO(NOSTR, LC_MESSAGES), */ - LANGINFO(CRNCYSTR), + LANGINFO(CRNCYSTR, LC_MONETARY), #endif - LANGINFO(D_T_FMT), - LANGINFO(D_FMT), - LANGINFO(T_FMT), - LANGINFO(AM_STR), - LANGINFO(PM_STR), + LANGINFO(D_T_FMT, LC_TIME), + LANGINFO(D_FMT, LC_TIME), + LANGINFO(T_FMT, LC_TIME), + LANGINFO(AM_STR, LC_TIME), + LANGINFO(PM_STR, LC_TIME), /* The following constants are available only with XPG4, but... OpenBSD doesn't have CODESET but has T_FMT_AMPM, and doesn't have a few of the others. Solution: ifdef-test them all. */ #ifdef CODESET - LANGINFO(CODESET), + LANGINFO(CODESET, LC_CTYPE), #endif #ifdef T_FMT_AMPM - LANGINFO(T_FMT_AMPM), + LANGINFO(T_FMT_AMPM, LC_TIME), #endif #ifdef ERA - LANGINFO(ERA), + LANGINFO(ERA, LC_TIME), #endif #ifdef ERA_D_FMT - LANGINFO(ERA_D_FMT), + LANGINFO(ERA_D_FMT, LC_TIME), #endif #ifdef ERA_D_T_FMT - LANGINFO(ERA_D_T_FMT), + LANGINFO(ERA_D_T_FMT, LC_TIME), #endif #ifdef ERA_T_FMT - LANGINFO(ERA_T_FMT), + LANGINFO(ERA_T_FMT, LC_TIME), #endif #ifdef ALT_DIGITS - LANGINFO(ALT_DIGITS), + LANGINFO(ALT_DIGITS, LC_TIME), #endif #ifdef YESEXPR - LANGINFO(YESEXPR), + LANGINFO(YESEXPR, LC_MESSAGES), #endif #ifdef NOEXPR - LANGINFO(NOEXPR), + LANGINFO(NOEXPR, LC_MESSAGES), #endif #ifdef _DATE_FMT /* This is not available in all glibc versions that have CODESET. */ - LANGINFO(_DATE_FMT), + LANGINFO(_DATE_FMT, LC_TIME), #endif - {0, 0} + {0, 0, 0} }; +/* Temporary make the LC_CTYPE locale to be the same as + * the locale of the specified category. */ +static int +change_locale(int category, char **oldloc) +{ + /* Keep a copy of the LC_CTYPE locale */ + *oldloc = setlocale(LC_CTYPE, NULL); + if (!*oldloc) { + PyErr_SetString(PyExc_RuntimeError, "faild to get LC_CTYPE locale"); + return -1; + } + *oldloc = _PyMem_Strdup(*oldloc); + if (!*oldloc) { + PyErr_NoMemory(); + return -1; + } + + /* Set a new locale if it is different. */ + char *loc = setlocale(category, NULL); + if (loc == NULL || strcmp(loc, *oldloc) == 0) { + PyMem_Free(*oldloc); + *oldloc = NULL; + return 0; + } + + setlocale(LC_CTYPE, loc); + return 1; +} + +/* Restore the old LC_CTYPE locale. */ +static void +restore_locale(char *oldloc) +{ + if (oldloc != NULL) { + setlocale(LC_CTYPE, oldloc); + PyMem_Free(oldloc); + } +} + /*[clinic input] _locale.nl_langinfo @@ -602,14 +653,24 @@ _locale_nl_langinfo_impl(PyObject *module, int item) /* Check whether this is a supported constant. GNU libc sometimes returns numeric values in the char* return value, which would crash PyUnicode_FromString. */ - for (i = 0; langinfo_constants[i].name; i++) + for (i = 0; langinfo_constants[i].name; i++) { if (langinfo_constants[i].value == item) { /* Check NULL as a workaround for GNU libc's returning NULL instead of an empty string for nl_langinfo(ERA). */ const char *result = nl_langinfo(item); result = result != NULL ? result : ""; - return PyUnicode_DecodeLocale(result, NULL); + char *oldloc = NULL; + if (langinfo_constants[i].category != LC_CTYPE + && !is_all_ascii(result) + && change_locale(langinfo_constants[i].category, &oldloc) < 0) + { + return NULL; + } + PyObject *unicode = PyUnicode_DecodeLocale(result, NULL); + restore_locale(oldloc); + return unicode; } + } PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant"); return NULL; } From 7c4b6a68f263320a2dd19cd5ff63b35c964b1fa8 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Tue, 8 Oct 2024 18:34:11 +1000 Subject: [PATCH 044/247] bpo-34206: Improve docs and test coverage for pre-init functions (#8023) - move the Py_Main documentation from the very high level API section to the initialization and finalization section - make it clear that it encapsulates a full Py_Initialize/Finalize cycle of its own - point out that exactly which settings will be read and applied correctly when Py_Main is called after a separate runtime initialization call is version dependent - be explicit that Py_IsInitialized can be called prior to initialization - actually test that Py_IsInitialized can be called prior to initialization - flush stdout in the embedding tests that run code so it appears in the expected order when running with "-vv" - make "-vv" on the subinterpreter embedding tests less spammy --------- Co-authored-by: Carol Willing --- Doc/c-api/init.rst | 162 +++++++++++++++--- Doc/c-api/init_config.rst | 29 +--- Doc/c-api/veryhigh.rst | 24 --- Lib/test/test_embed.py | 11 +- .../2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst | 2 + .../2018-07-04-20-35-25.bpo-34008.bqecIb.rst | 8 + Programs/_testembed.c | 41 ++++- 7 files changed, 199 insertions(+), 78 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst create mode 100644 Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 6d16e04ac3d864..8e0cf7bb0fc088 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -7,7 +7,8 @@ Initialization, Finalization, and Threads ***************************************** -See also the :ref:`Python Initialization Configuration `. +See :ref:`Python Initialization Configuration ` for details +on how to configure the interpreter prior to initialization. .. _pre-init-safe: @@ -21,6 +22,15 @@ a few functions and the :ref:`global configuration variables The following functions can be safely called before Python is initialized: +* Functions that initialize the interpreter: + + * :c:func:`Py_Initialize` + * :c:func:`Py_InitializeEx` + * :c:func:`Py_InitializeFromConfig` + * :c:func:`Py_BytesMain` + * :c:func:`Py_Main` + * the runtime pre-initialization functions covered in :ref:`init-config` + * Configuration functions: * :c:func:`PyImport_AppendInittab` @@ -32,6 +42,7 @@ The following functions can be safely called before Python is initialized: * :c:func:`Py_SetProgramName` * :c:func:`Py_SetPythonHome` * :c:func:`PySys_ResetWarnOptions` + * the configuration functions covered in :ref:`init-config` * Informative functions: @@ -43,10 +54,12 @@ The following functions can be safely called before Python is initialized: * :c:func:`Py_GetCopyright` * :c:func:`Py_GetPlatform` * :c:func:`Py_GetVersion` + * :c:func:`Py_IsInitialized` * Utilities: * :c:func:`Py_DecodeLocale` + * the status reporting and utility functions covered in :ref:`init-config` * Memory allocators: @@ -62,11 +75,13 @@ The following functions can be safely called before Python is initialized: .. note:: - The following functions **should not be called** before - :c:func:`Py_Initialize`: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`, + Despite their apparent similarity to some of the functions listed above, + the following functions **should not be called** before the interpreter has + been initialized: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`, :c:func:`Py_GetPrefix`, :c:func:`Py_GetExecPrefix`, :c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome`, - :c:func:`Py_GetProgramName` and :c:func:`PyEval_InitThreads`. + :c:func:`Py_GetProgramName`, :c:func:`PyEval_InitThreads`, and + :c:func:`Py_RunMain`. .. _global-conf-vars: @@ -346,34 +361,42 @@ Initializing and finalizing the interpreter this should be called before using any other Python/C API functions; see :ref:`Before Python Initialization ` for the few exceptions. - This initializes - the table of loaded modules (``sys.modules``), and creates the fundamental - modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`. It also initializes - the module search path (``sys.path``). It does not set ``sys.argv``; use - the new :c:type:`PyConfig` API of the :ref:`Python Initialization - Configuration ` for that. This is a no-op when called for a - second time - (without calling :c:func:`Py_FinalizeEx` first). There is no return value; it is a - fatal error if the initialization fails. - - Use the :c:func:`Py_InitializeFromConfig` function to customize the + This initializes the table of loaded modules (``sys.modules``), and creates + the fundamental modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`. + It also initializes the module search path (``sys.path``). It does not set + ``sys.argv``; use the :ref:`Python Initialization Configuration ` + API for that. This is a no-op when called for a second time (without calling + :c:func:`Py_FinalizeEx` first). There is no return value; it is a fatal + error if the initialization fails. + + Use :c:func:`Py_InitializeFromConfig` to customize the :ref:`Python Initialization Configuration `. .. note:: - On Windows, changes the console mode from ``O_TEXT`` to ``O_BINARY``, which will - also affect non-Python uses of the console using the C Runtime. + On Windows, changes the console mode from ``O_TEXT`` to ``O_BINARY``, + which will also affect non-Python uses of the console using the C Runtime. .. c:function:: void Py_InitializeEx(int initsigs) This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If - *initsigs* is ``0``, it skips initialization registration of signal handlers, which - might be useful when Python is embedded. + *initsigs* is ``0``, it skips initialization registration of signal handlers, + which may be useful when CPython is embedded as part of a larger application. - Use the :c:func:`Py_InitializeFromConfig` function to customize the + Use :c:func:`Py_InitializeFromConfig` to customize the :ref:`Python Initialization Configuration `. +.. c:function:: PyStatus Py_InitializeFromConfig(const PyConfig *config) + + Initialize Python from *config* configuration, as described in + :ref:`init-from-config`. + + See the :ref:`init-config` section for details on pre-initializing the + interpreter, populating the runtime configuration structure, and querying + the returned status structure. + + .. c:function:: int Py_IsInitialized() Return true (nonzero) when the Python interpreter has been initialized, false @@ -440,12 +463,111 @@ Initializing and finalizing the interpreter .. versionadded:: 3.6 + .. c:function:: void Py_Finalize() This is a backwards-compatible version of :c:func:`Py_FinalizeEx` that disregards the return value. +.. c:function:: int Py_BytesMain(int argc, char **argv) + + Similar to :c:func:`Py_Main` but *argv* is an array of bytes strings, + allowing the calling application to delegate the text decoding step to + the CPython runtime. + + .. versionadded:: 3.8 + + +.. c:function:: int Py_Main(int argc, wchar_t **argv) + + The main program for the standard interpreter, encapsulating a full + initialization/finalization cycle, as well as additional + behaviour to implement reading configurations settings from the environment + and command line, and then executing ``__main__`` in accordance with + :ref:`using-on-cmdline`. + + This is made available for programs which wish to support the full CPython + command line interface, rather than just embedding a Python runtime in a + larger application. + + The *argc* and *argv* parameters are similar to those which are passed to a + C program's :c:func:`main` function, except that the *argv* entries are first + converted to ``wchar_t`` using :c:func:`Py_DecodeLocale`. It is also + important to note that the argument list entries may be modified to point to + strings other than those passed in (however, the contents of the strings + pointed to by the argument list are not modified). + + The return value will be ``0`` if the interpreter exits normally (i.e., + without an exception), ``1`` if the interpreter exits due to an exception, + or ``2`` if the argument list does not represent a valid Python command + line. + + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this + function will not return ``1``, but exit the process, as long as + ``Py_InspectFlag`` is not set. If ``Py_InspectFlag`` is set, execution will + drop into the interactive Python prompt, at which point a second otherwise + unhandled :exc:`SystemExit` will still exit the process, while any other + means of exiting will set the return value as described above. + + In terms of the CPython runtime configuration APIs documented in the + :ref:`runtime configuration ` section (and without accounting + for error handling), ``Py_Main`` is approximately equivalent to:: + + PyConfig config; + PyConfig_InitPythonConfig(&config); + PyConfig_SetArgv(&config, argc, argv); + Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); + + Py_RunMain(); + + In normal usage, an embedding application will call this function + *instead* of calling :c:func:`Py_Initialize`, :c:func:`Py_InitializeEx` or + :c:func:`Py_InitializeFromConfig` directly, and all settings will be applied + as described elsewhere in this documentation. If this function is instead + called *after* a preceding runtime initialization API call, then exactly + which environmental and command line configuration settings will be updated + is version dependent (as it depends on which settings correctly support + being modified after they have already been set once when the runtime was + first initialized). + + +.. c:function:: int Py_RunMain(void) + + Executes the main module in a fully configured CPython runtime. + + Executes the command (:c:member:`PyConfig.run_command`), the script + (:c:member:`PyConfig.run_filename`) or the module + (:c:member:`PyConfig.run_module`) specified on the command line or in the + configuration. If none of these values are set, runs the interactive Python + prompt (REPL) using the ``__main__`` module's global namespace. + + If :c:member:`PyConfig.inspect` is not set (the default), the return value + will be ``0`` if the interpreter exits normally (that is, without raising + an exception), or ``1`` if the interpreter exits due to an exception. If an + otherwise unhandled :exc:`SystemExit` is raised, the function will immediately + exit the process instead of returning ``1``. + + If :c:member:`PyConfig.inspect` is set (such as when the :option:`-i` option + is used), rather than returning when the interpreter exits, execution will + instead resume in an interactive Python prompt (REPL) using the ``__main__`` + module's global namespace. If the interpreter exited with an exception, it + is immediately raised in the REPL session. The function return value is + then determined by the way the *REPL session* terminates: returning ``0`` + if the session terminates without raising an unhandled exception, exiting + immediately for an unhandled :exc:`SystemExit`, and returning ``1`` for + any other unhandled exception. + + This function always finalizes the Python interpreter regardless of whether + it returns a value or immediately exits the process due to an unhandled + :exc:`SystemExit` exception. + + See :ref:`Python Configuration ` for an example of a + customized Python that always runs in isolated mode using + :c:func:`Py_RunMain`. + + Process-wide parameters ======================= diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 9dc9ba61e7a60f..6f8962afc7af0d 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -1356,14 +1356,13 @@ the :option:`-X` command line option. The ``show_alloc_count`` field has been removed. +.. _init-from-config: + Initialization with PyConfig ---------------------------- -Function to initialize Python: - -.. c:function:: PyStatus Py_InitializeFromConfig(const PyConfig *config) - - Initialize Python from *config* configuration. +Initializing the interpreter from a populated configuration struct is handled +by calling :c:func:`Py_InitializeFromConfig`. The caller is responsible to handle exceptions (error or exit) using :c:func:`PyStatus_Exception` and :c:func:`Py_ExitStatusException`. @@ -1835,26 +1834,6 @@ return ``-1`` on error: } -Py_RunMain() -============ - -.. c:function:: int Py_RunMain(void) - - Execute the command (:c:member:`PyConfig.run_command`), the script - (:c:member:`PyConfig.run_filename`) or the module - (:c:member:`PyConfig.run_module`) specified on the command line or in the - configuration. - - By default and when if :option:`-i` option is used, run the REPL. - - Finally, finalizes Python and returns an exit status that can be passed to - the ``exit()`` function. - -See :ref:`Python Configuration ` for an example of -customized Python always running in isolated mode using -:c:func:`Py_RunMain`. - - Runtime Python configuration API ================================ diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 67167444d0a685..9f02bdb5896563 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -25,30 +25,6 @@ are only passed to these functions if it is certain that they were created by the same library that the Python runtime is using. -.. c:function:: int Py_Main(int argc, wchar_t **argv) - - The main program for the standard interpreter. This is made available for - programs which embed Python. The *argc* and *argv* parameters should be - prepared exactly as those which are passed to a C program's :c:func:`main` - function (converted to wchar_t according to the user's locale). It is - important to note that the argument list may be modified (but the contents of - the strings pointed to by the argument list are not). The return value will - be ``0`` if the interpreter exits normally (i.e., without an exception), - ``1`` if the interpreter exits due to an exception, or ``2`` if the parameter - list does not represent a valid Python command line. - - Note that if an otherwise unhandled :exc:`SystemExit` is raised, this - function will not return ``1``, but exit the process, as long as - :c:member:`PyConfig.inspect` is zero. - - -.. c:function:: int Py_BytesMain(int argc, char **argv) - - Similar to :c:func:`Py_Main` but *argv* is an array of bytes strings. - - .. versionadded:: 3.8 - - .. c:function:: int PyRun_AnyFile(FILE *fp, const char *filename) This is a simplified interface to :c:func:`PyRun_AnyFileExFlags` below, leaving diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 3edc19d8254754..035d4418b15c51 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -168,7 +168,8 @@ def run_repeated_init_and_subinterpreters(self): # Parse the line from the loop. The first line is the main # interpreter and the 3 afterward are subinterpreters. interp = Interp(*match.groups()) - if support.verbose > 1: + if support.verbose > 2: + # 5 lines per pass is super-spammy, so limit that to -vvv print(interp) self.assertTrue(interp.interp) self.assertTrue(interp.tstate) @@ -279,6 +280,10 @@ def test_pre_initialization_api(self): """ env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path)) out, err = self.run_embedded_interpreter("test_pre_initialization_api", env=env) + if support.verbose > 1: + print() + print(out) + print(err) if MS_WINDOWS: expected_path = self.test_exe else: @@ -296,6 +301,10 @@ def test_pre_initialization_sys_options(self): env['PYTHONPATH'] = os.pathsep.join(sys.path) out, err = self.run_embedded_interpreter( "test_pre_initialization_sys_options", env=env) + if support.verbose > 1: + print() + print(out) + print(err) expected_output = ( "sys.warnoptions: ['once', 'module', 'default']\n" "sys._xoptions: {'not_an_option': '1', 'also_not_an_option': '2'}\n" diff --git a/Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst b/Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst new file mode 100644 index 00000000000000..1a01dafc758004 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst @@ -0,0 +1,2 @@ +Added ``Py_IsInitialized`` to the list of APIs that are safe to call before +the interpreter is initialized, and updated the embedding tests to cover it. diff --git a/Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst b/Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst new file mode 100644 index 00000000000000..a89086af35bfc1 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst @@ -0,0 +1,8 @@ +The :c:func:`Py_Main` documentation moved from the "Very High Level API" section to the +"Initialization and Finalization" section. + +Also make it explicit that we expect ``Py_Main`` to typically be called instead +of ``Py_Initialize`` rather than after it (since ``Py_Main`` makes its own +call to ``Py_Initialize``). Document that calling both is +supported but is version dependent on which settings +will be applied correctly. diff --git a/Programs/_testembed.c b/Programs/_testembed.c index ab2b2d06cca15d..ab619e32429d63 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -311,14 +311,36 @@ static int test_pre_initialization_api(void) _Py_EMBED_PREINIT_CHECK("Checking Py_SetProgramName\n"); Py_SetProgramName(program); + _Py_EMBED_PREINIT_CHECK("Checking !Py_IsInitialized pre-initialization\n"); + if (Py_IsInitialized()) { + fprintf(stderr, "Fatal error: initialized before initialization!\n"); + return 1; + } + _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n"); Py_Initialize(); + + _Py_EMBED_PREINIT_CHECK("Checking Py_IsInitialized post-initialization\n"); + if (!Py_IsInitialized()) { + fprintf(stderr, "Fatal error: not initialized after initialization!\n"); + return 1; + } + _Py_EMBED_PREINIT_CHECK("Check sys module contents\n"); - PyRun_SimpleString("import sys; " - "print('sys.executable:', sys.executable)"); + PyRun_SimpleString( + "import sys; " + "print('sys.executable:', sys.executable); " + "sys.stdout.flush(); " + ); _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n"); Py_Finalize(); + _Py_EMBED_PREINIT_CHECK("Checking !Py_IsInitialized post-finalization\n"); + if (Py_IsInitialized()) { + fprintf(stderr, "Fatal error: still initialized after finalization!\n"); + return 1; + } + _Py_EMBED_PREINIT_CHECK("Freeing memory allocated by Py_DecodeLocale\n"); PyMem_RawFree(program); return 0; @@ -364,12 +386,15 @@ static int test_pre_initialization_sys_options(void) _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n"); _testembed_Py_InitializeFromConfig(); _Py_EMBED_PREINIT_CHECK("Check sys module contents\n"); - PyRun_SimpleString("import sys; " - "print('sys.warnoptions:', sys.warnoptions); " - "print('sys._xoptions:', sys._xoptions); " - "warnings = sys.modules['warnings']; " - "latest_filters = [f[0] for f in warnings.filters[:3]]; " - "print('warnings.filters[:3]:', latest_filters)"); + PyRun_SimpleString( + "import sys; " + "print('sys.warnoptions:', sys.warnoptions); " + "print('sys._xoptions:', sys._xoptions); " + "warnings = sys.modules['warnings']; " + "latest_filters = [f[0] for f in warnings.filters[:3]]; " + "print('warnings.filters[:3]:', latest_filters); " + "sys.stdout.flush(); " + ); _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n"); Py_Finalize(); From 19984fe024bfd90649f1c36b78c9abf3ed72b27d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 8 Oct 2024 11:40:02 +0300 Subject: [PATCH 045/247] gh-53203: Improve tests for strptime() (GH-125090) Run them with different locales and different date and time. Add the @run_with_locales() decorator to run the test with multiple locales. Improve the run_with_locale() context manager/decorator -- it now catches only expected exceptions and reports the test as skipped if no appropriate locale is available. --- Lib/test/pickletester.py | 4 +- Lib/test/support/__init__.py | 53 +++++++++- Lib/test/test_codecs.py | 9 +- Lib/test/test_decimal.py | 2 +- Lib/test/test_float.py | 2 +- Lib/test/test_imaplib.py | 2 +- Lib/test/test_str.py | 2 +- Lib/test/test_strptime.py | 195 +++++++++++++++++++++++++---------- Lib/test/test_time.py | 12 +-- Lib/test/test_types.py | 4 +- 10 files changed, 200 insertions(+), 85 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 1722cc8612ca6b..8ef8fae44f1d25 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -26,7 +26,7 @@ from test import support from test.support import os_helper from test.support import ( - TestFailed, run_with_locale, no_tracing, + TestFailed, run_with_locales, no_tracing, _2G, _4G, bigmemtest ) from test.support.import_helper import forget @@ -2895,7 +2895,7 @@ def test_float(self): got = self.loads(pickle) self.assert_is_copy(value, got) - @run_with_locale('LC_ALL', 'de_DE', 'fr_FR') + @run_with_locales('LC_ALL', 'de_DE', 'fr_FR', '') def test_float_format(self): # make sure that floats are formatted locale independent with proto 0 self.assertEqual(self.dumps(1.2, 0)[0:3], b'F1.') diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 1a44cc638b5714..72ce5dacd1be4c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -930,8 +930,8 @@ def check_sizeof(test, o, size): test.assertEqual(result, size, msg) #======================================================================= -# Decorator for running a function in a different locale, correctly resetting -# it afterwards. +# Decorator/context manager for running a code in a different locale, +# correctly resetting it afterwards. @contextlib.contextmanager def run_with_locale(catstr, *locales): @@ -942,16 +942,21 @@ def run_with_locale(catstr, *locales): except AttributeError: # if the test author gives us an invalid category string raise - except: + except Exception: # cannot retrieve original locale, so do nothing locale = orig_locale = None + if '' not in locales: + raise unittest.SkipTest('no locales') else: for loc in locales: try: locale.setlocale(category, loc) break - except: + except locale.Error: pass + else: + if '' not in locales: + raise unittest.SkipTest(f'no locales {locales}') try: yield @@ -959,6 +964,46 @@ def run_with_locale(catstr, *locales): if locale and orig_locale: locale.setlocale(category, orig_locale) +#======================================================================= +# Decorator for running a function in multiple locales (if they are +# availasble) and resetting the original locale afterwards. + +def run_with_locales(catstr, *locales): + def deco(func): + @functools.wraps(func) + def wrapper(self, /, *args, **kwargs): + dry_run = '' in locales + try: + import locale + category = getattr(locale, catstr) + orig_locale = locale.setlocale(category) + except AttributeError: + # if the test author gives us an invalid category string + raise + except Exception: + # cannot retrieve original locale, so do nothing + pass + else: + try: + for loc in locales: + with self.subTest(locale=loc): + try: + locale.setlocale(category, loc) + except locale.Error: + self.skipTest(f'no locale {loc!r}') + else: + dry_run = False + func(self, *args, **kwargs) + finally: + locale.setlocale(category, orig_locale) + if dry_run: + # no locales available, so just run the test + # with the current locale + with self.subTest(locale=None): + func(self, *args, **kwargs) + return wrapper + return deco + #======================================================================= # Decorator for running a function in a specific timezone, correctly # resetting it afterwards. diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 428036e1765b8f..290656f070503a 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2,7 +2,6 @@ import contextlib import copy import io -import locale import pickle import sys import unittest @@ -1812,16 +1811,10 @@ def test_getwriter(self): self.assertRaises(TypeError, codecs.getwriter) self.assertRaises(LookupError, codecs.getwriter, "__spam__") + @support.run_with_locale('LC_CTYPE', 'tr_TR') def test_lookup_issue1813(self): # Issue #1813: under Turkish locales, lookup of some codecs failed # because 'I' is lowercased as "ı" (dotless i) - oldlocale = locale.setlocale(locale.LC_CTYPE) - self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale) - try: - locale.setlocale(locale.LC_CTYPE, 'tr_TR') - except locale.Error: - # Unsupported locale on this system - self.skipTest('test needs Turkish locale') c = codecs.lookup('ASCII') self.assertEqual(c.name, 'ascii') diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index c591fd54430b18..d1e7e69e7e951b 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -1253,7 +1253,7 @@ def test_deprecated_N_format(self): self.assertRaises(ValueError, format, h, '10Nf') self.assertRaises(ValueError, format, h, 'Nx') - @run_with_locale('LC_ALL', 'ps_AF') + @run_with_locale('LC_ALL', 'ps_AF', '') def test_wide_char_separator_decimal_point(self): # locale with wide char separator and decimal point Decimal = self.decimal.Decimal diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index 048bb14509064b..f588e16b70123a 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -175,7 +175,7 @@ def check(s): # non-UTF-8 byte string check(b'123\xa0') - @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE') + @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE', '') def test_float_with_comma(self): # set locale to something that doesn't use '.' for the decimal point # float must not accept the locale specific decimal point but diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 1fd75d0a3f4c7b..a6509fc3ba0eae 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -57,7 +57,7 @@ def timevalues(self): timezone(timedelta(0, 2 * 60 * 60))), '"18-May-2033 05:33:20 +0200"'] - @run_with_locale('LC_ALL', 'de_DE', 'fr_FR') + @run_with_locale('LC_ALL', 'de_DE', 'fr_FR', '') # DST rules included to work around quirk where the Gnu C library may not # otherwise restore the previous time zone @run_with_tz('STD-1DST,M3.2.0,M11.1.0') diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py index 6600dcf9157971..4de6c1cba152bd 100644 --- a/Lib/test/test_str.py +++ b/Lib/test/test_str.py @@ -1665,7 +1665,7 @@ def test_startswith_endswith_errors(self): self.assertIn('str', exc) self.assertIn('tuple', exc) - @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') + @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR', '') def test_format_float(self): # should not format with a comma, but always with C locale self.assertEqual('1.0', '%.1f' % 1.0) diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 038746e26c24ad..37f6b08db28b3e 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -7,7 +7,8 @@ import os import sys from test import support -from test.support import skip_if_buggy_ucrt_strfptime, warnings_helper +from test.support import warnings_helper +from test.support import skip_if_buggy_ucrt_strfptime, run_with_locales from datetime import date as datetime_date import _strptime @@ -207,8 +208,8 @@ class StrptimeTests(unittest.TestCase): """Tests for _strptime.strptime.""" def setUp(self): - """Create testing time tuple.""" - self.time_tuple = time.gmtime() + """Create testing time tuples.""" + self.time_tuple = time.localtime() def test_ValueError(self): # Make sure ValueError is raised when match fails or format is bad @@ -289,54 +290,67 @@ def test_unconverteddata(self): # Check ValueError is raised when there is unconverted data self.assertRaises(ValueError, _strptime._strptime_time, "10 12", "%m") - def helper(self, directive, position): + def roundtrip(self, fmt, position, time_tuple=None): """Helper fxn in testing.""" - fmt = "%d %Y" if directive == 'd' else "%" + directive - strf_output = time.strftime(fmt, self.time_tuple) + if time_tuple is None: + time_tuple = self.time_tuple + strf_output = time.strftime(fmt, time_tuple) strp_output = _strptime._strptime_time(strf_output, fmt) - self.assertTrue(strp_output[position] == self.time_tuple[position], - "testing of '%s' directive failed; '%s' -> %s != %s" % - (directive, strf_output, strp_output[position], - self.time_tuple[position])) + self.assertEqual(strp_output[position], time_tuple[position], + "testing of %r format failed; %r -> %r != %r" % + (fmt, strf_output, strp_output[position], + time_tuple[position])) + if support.verbose >= 3: + print("testing of %r format: %r -> %r" % + (fmt, strf_output, strp_output[position])) def test_year(self): # Test that the year is handled properly - for directive in ('y', 'Y'): - self.helper(directive, 0) + self.roundtrip('%Y', 0) + self.roundtrip('%y', 0) + self.roundtrip('%Y', 0, (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + # Must also make sure %y values are correct for bounds set by Open Group - for century, bounds in ((1900, ('69', '99')), (2000, ('00', '68'))): - for bound in bounds: - strp_output = _strptime._strptime_time(bound, '%y') - expected_result = century + int(bound) - self.assertTrue(strp_output[0] == expected_result, - "'y' test failed; passed in '%s' " - "and returned '%s'" % (bound, strp_output[0])) + strptime = _strptime._strptime_time + self.assertEqual(strptime('00', '%y')[0], 2000) + self.assertEqual(strptime('68', '%y')[0], 2068) + self.assertEqual(strptime('69', '%y')[0], 1969) + self.assertEqual(strptime('99', '%y')[0], 1999) def test_month(self): # Test for month directives - for directive in ('B', 'b', 'm'): - self.helper(directive, 1) + self.roundtrip('%m', 1) + + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', 'he_IL', '') + def test_month_locale(self): + # Test for month directives + self.roundtrip('%B', 1) + self.roundtrip('%b', 1) + for m in range(1, 13): + self.roundtrip('%B', 1, (1900, m, 1, 0, 0, 0, 0, 1, 0)) + self.roundtrip('%b', 1, (1900, m, 1, 0, 0, 0, 0, 1, 0)) def test_day(self): # Test for day directives - self.helper('d', 2) + self.roundtrip('%d %Y', 2) def test_hour(self): # Test hour directives - self.helper('H', 3) - strf_output = time.strftime("%I %p", self.time_tuple) - strp_output = _strptime._strptime_time(strf_output, "%I %p") - self.assertTrue(strp_output[3] == self.time_tuple[3], - "testing of '%%I %%p' directive failed; '%s' -> %s != %s" % - (strf_output, strp_output[3], self.time_tuple[3])) + self.roundtrip('%H', 3) + + # NB: Only works on locales with AM/PM + @run_with_locales('LC_TIME', 'C', 'en_US', 'ja_JP') + def test_hour_locale(self): + # Test hour directives + self.roundtrip('%I %p', 3) def test_minute(self): # Test minute directives - self.helper('M', 4) + self.roundtrip('%M', 4) def test_second(self): # Test second directives - self.helper('S', 5) + self.roundtrip('%S', 5) def test_fraction(self): # Test microseconds @@ -347,12 +361,18 @@ def test_fraction(self): def test_weekday(self): # Test weekday directives - for directive in ('A', 'a', 'w', 'u'): - self.helper(directive,6) + self.roundtrip('%w', 6) + self.roundtrip('%u', 6) + + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', '') + def test_weekday_locale(self): + # Test weekday directives + self.roundtrip('%A', 6) + self.roundtrip('%a', 6) def test_julian(self): # Test julian directives - self.helper('j', 7) + self.roundtrip('%j', 7) def test_offset(self): one_hour = 60 * 60 @@ -449,20 +469,96 @@ def test_bad_timezone(self): "time.daylight set to %s and passing in %s" % (time.tzname, tz_value, time.daylight, tz_name)) - def test_date_time(self): + # NB: Does not roundtrip in some locales due to the ambiguity of + # the date and time representation (bugs in locales?): + # * Seconds are not included: bem_ZM, bokmal, ff_SN, nb_NO, nn_NO, + # no_NO, norwegian, nynorsk. + # * Hours are in 12-hour notation without AM/PM indication: hy_AM, + # id_ID, ms_MY. + # * Year is not included: ha_NG. + # * Use non-Gregorian calendar: lo_LA, thai, th_TH. + # + # BUG: Generates invalid regexp for br_FR, csb_PL, Arabic. + # BUG: Generates regexp that does not match the current date and time + # for fa_IR, gez_ER, gez_ET, lzh_TW, my_MM, or_IN, shn_MM, yo_NG. + # BUG: Generates regexp that does not match the current date and time + # for fa_IR, gez_ER, gez_ET, lzh_TW, my_MM, or_IN, shn_MM, yo_NG, + # fr_FR, ja_JP, he_IL, ko_KR, zh_CN, etc. + @run_with_locales('LC_TIME', 'C', 'en_US', 'de_DE', + 'eu_ES', 'mfe_MU') + def test_date_time_locale(self): # Test %c directive - for position in range(6): - self.helper('c', position) - - def test_date(self): + now = time.time() + self.roundtrip('%c', slice(0, 6), time.localtime(now)) + # 1 hour 20 minutes 30 seconds ago + self.roundtrip('%c', slice(0, 6), time.localtime(now - 4830)) + # 12 hours ago + self.roundtrip('%c', slice(0, 6), time.localtime(now - 12*3600)) + # different days of the week + for i in range(1, 7): + self.roundtrip('%c', slice(0, 6), time.localtime(now - i*24*3600)) + # different months + for i in range(1, 12): + self.roundtrip('%c', slice(0, 6), time.localtime(now - i*30*24*3600)) + # different year + self.roundtrip('%c', slice(0, 6), time.localtime(now - 366*24*3600)) + + # NB: Dates before 1969 do not roundtrip on some locales: + # bo_CN, bo_IN, dz_BT, eu_ES, eu_FR. + @run_with_locales('LC_TIME', 'C', 'en_US', 'de_DE', 'ja_JP') + def test_date_time_locale2(self): + # Test %c directive + self.roundtrip('%c', slice(0, 6), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + + # NB: Does not roundtrip because use non-Gregorian calendar: + # lo_LA, thai, th_TH. + # BUG: Generates regexp that does not match the current date + # for az_IR, fa_IR, lzh_TW, my_MM, or_IN, shn_MM, + # Arabic, ja_JP, ko_KR, zh_CN, etc. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', + 'he_IL', 'eu_ES') + def test_date_locale(self): # Test %x directive - for position in range(0,3): - self.helper('x', position) - - def test_time(self): + now = time.time() + self.roundtrip('%x', slice(0, 3), time.localtime(now)) + # different days of the week + for i in range(1, 7): + self.roundtrip('%x', slice(0, 3), time.localtime(now - i*24*3600)) + # different months + for i in range(1, 12): + self.roundtrip('%x', slice(0, 3), time.localtime(now - i*30*24*3600)) + # different year + self.roundtrip('%x', slice(0, 3), time.localtime(now - 366*24*3600)) + + # NB: Dates before 1969 do not roundtrip on many locales, including C. + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "musl libc issue on Emscripten, bpo-46390" + ) + @run_with_locales('LC_TIME', 'en_US', 'fr_FR', 'de_DE', 'ja_JP') + def test_date_locale2(self): + # Test %x directive + self.roundtrip('%x', slice(0, 3), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + + # NB: Does not roundtrip in some locales due to the ambiguity of + # the time representation (bugs in locales?): + # * Seconds are not included: bokmal, ff_SN, nb_NO, nn_NO, no_NO, + # norwegian, nynorsk. + # * Hours are in 12-hour notation without AM/PM indication: hy_AM, + # ms_MY, sm_WS. + # BUG: Generates regexp that does not match the current time for + # aa_DJ, aa_ER, aa_ET, am_ET, az_IR, byn_ER, fa_IR, gez_ER, gez_ET, + # lzh_TW, my_MM, om_ET, om_KE, or_IN, shn_MM, sid_ET, so_DJ, so_ET, + # so_SO, ti_ER, ti_ET, tig_ER, wal_ET. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP') + def test_time_locale(self): # Test %X directive - for position in range(3,6): - self.helper('X', position) + now = time.time() + self.roundtrip('%X', slice(3, 6), time.localtime(now)) + # 1 hour 20 minutes 30 seconds ago + self.roundtrip('%X', slice(3, 6), time.localtime(now - 4830)) + # 12 hours ago + self.roundtrip('%X', slice(3, 6), time.localtime(now - 12*3600)) def test_percent(self): # Make sure % signs are handled properly @@ -714,12 +810,7 @@ def test_new_localetime(self): def test_TimeRE_recreation_locale(self): # The TimeRE instance should be recreated upon changing the locale. - locale_info = locale.getlocale(locale.LC_TIME) - try: - locale.setlocale(locale.LC_TIME, ('en_US', 'UTF8')) - except locale.Error: - self.skipTest('test needs en_US.UTF8 locale') - try: + with support.run_with_locale('LC_TIME', 'en_US.UTF8'): _strptime._strptime_time('10 2004', '%d %Y') # Get id of current cache object. first_time_re = _strptime._TimeRE_cache @@ -736,10 +827,6 @@ def test_TimeRE_recreation_locale(self): # to the resetting to the original locale. except locale.Error: self.skipTest('test needs de_DE.UTF8 locale') - # Make sure we don't trample on the locale setting once we leave the - # test. - finally: - locale.setlocale(locale.LC_TIME, locale_info) @support.run_with_tz('STD-1DST,M4.1.0,M10.1.0') def test_TimeRE_recreation_timezone(self): diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 530c317a852e77..5b5779231f06ce 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -2,7 +2,6 @@ from test.support import warnings_helper import decimal import enum -import locale import math import platform import sys @@ -600,17 +599,8 @@ def test_get_clock_info(self): class TestLocale(unittest.TestCase): - def setUp(self): - self.oldloc = locale.setlocale(locale.LC_ALL) - - def tearDown(self): - locale.setlocale(locale.LC_ALL, self.oldloc) - + @support.run_with_locale('LC_ALL', 'fr_FR', '') def test_bug_3061(self): - try: - tmp = locale.setlocale(locale.LC_ALL, "fr_FR") - except locale.Error: - self.skipTest('could not set locale.LC_ALL to fr_FR') # This should not cause an exception time.strftime("%B", (2009,2,1,0,0,0,0,0,0)) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 3c9e33e3c9dbfc..d1161719d98040 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -398,7 +398,7 @@ def test(i, format_spec, result): test(123456, "1=20", '11111111111111123456') test(123456, "*=20", '**************123456') - @run_with_locale('LC_NUMERIC', 'en_US.UTF8') + @run_with_locale('LC_NUMERIC', 'en_US.UTF8', '') def test_float__format__locale(self): # test locale support for __format__ code 'n' @@ -407,7 +407,7 @@ def test_float__format__locale(self): self.assertEqual(locale.format_string('%g', x, grouping=True), format(x, 'n')) self.assertEqual(locale.format_string('%.10g', x, grouping=True), format(x, '.10n')) - @run_with_locale('LC_NUMERIC', 'en_US.UTF8') + @run_with_locale('LC_NUMERIC', 'en_US.UTF8', '') def test_int__format__locale(self): # test locale support for __format__ code 'n' for integers From ba14dfafd97d1fd03938ac8ddec4ca5b2f12985d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 8 Oct 2024 13:37:59 +0200 Subject: [PATCH 046/247] gh-123378: fix a crash in `UnicodeError.__str__` (#124935) --- Lib/test/test_exceptions.py | 24 ++++ ...-10-03-14-39-41.gh-issue-123378.dCxANf.rst | 3 + Objects/exceptions.c | 111 +++++++++++------- 3 files changed, 93 insertions(+), 45 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index ba858c49400911..b3c21cd4f3d585 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -8,6 +8,7 @@ import weakref import errno from codecs import BOM_UTF8 +from itertools import product from textwrap import dedent from test.support import (captured_stderr, check_impl_detail, @@ -1336,6 +1337,29 @@ def test_unicode_errors_no_object(self): for klass in klasses: self.assertEqual(str(klass.__new__(klass)), "") + def test_unicode_error_str_does_not_crash(self): + # Test that str(UnicodeError(...)) does not crash. + # See https://github.com/python/cpython/issues/123378. + + for start, end, objlen in product( + range(-5, 5), + range(-5, 5), + range(7), + ): + obj = 'a' * objlen + with self.subTest('encode', objlen=objlen, start=start, end=end): + exc = UnicodeEncodeError('utf-8', obj, start, end, '') + self.assertIsInstance(str(exc), str) + + with self.subTest('translate', objlen=objlen, start=start, end=end): + exc = UnicodeTranslateError(obj, start, end, '') + self.assertIsInstance(str(exc), str) + + encoded = obj.encode() + with self.subTest('decode', objlen=objlen, start=start, end=end): + exc = UnicodeDecodeError('utf-8', encoded, start, end, '') + self.assertIsInstance(str(exc), str) + @no_tracing def test_badisinstance(self): # Bug #2542: if issubclass(e, MyException) raises an exception, diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst new file mode 100644 index 00000000000000..5cd34535d674d3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst @@ -0,0 +1,3 @@ +Fix a crash in the :meth:`~object.__str__` method of :exc:`UnicodeError` +objects when the :attr:`UnicodeError.start` and :attr:`UnicodeError.end` +values are invalid or out-of-range. Patch by Bénédikt Tran. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index b3910855165494..c685481b13a93a 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2994,46 +2994,55 @@ UnicodeEncodeError_init(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * UnicodeEncodeError_str(PyObject *self) { - PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; + PyUnicodeErrorObject *exc = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; PyObject *encoding_str = NULL; - if (!uself->object) + if (exc->object == NULL) { /* Not properly initialized. */ return PyUnicode_FromString(""); + } /* Get reason and encoding as strings, which they might not be if they've been modified after we were constructed. */ - reason_str = PyObject_Str(uself->reason); - if (reason_str == NULL) + reason_str = PyObject_Str(exc->reason); + if (reason_str == NULL) { goto done; - encoding_str = PyObject_Str(uself->encoding); - if (encoding_str == NULL) + } + encoding_str = PyObject_Str(exc->encoding); + if (encoding_str == NULL) { goto done; + } + + Py_ssize_t len = PyUnicode_GET_LENGTH(exc->object); + Py_ssize_t start = exc->start, end = exc->end; - if (uself->start < PyUnicode_GET_LENGTH(uself->object) && uself->end == uself->start+1) { - Py_UCS4 badchar = PyUnicode_ReadChar(uself->object, uself->start); + if ((start >= 0 && start < len) && (end >= 0 && end <= len) && end == start + 1) { + Py_UCS4 badchar = PyUnicode_ReadChar(exc->object, start); const char *fmt; - if (badchar <= 0xff) + if (badchar <= 0xff) { fmt = "'%U' codec can't encode character '\\x%02x' in position %zd: %U"; - else if (badchar <= 0xffff) + } + else if (badchar <= 0xffff) { fmt = "'%U' codec can't encode character '\\u%04x' in position %zd: %U"; - else + } + else { fmt = "'%U' codec can't encode character '\\U%08x' in position %zd: %U"; + } result = PyUnicode_FromFormat( fmt, encoding_str, (int)badchar, - uself->start, + start, reason_str); } else { result = PyUnicode_FromFormat( "'%U' codec can't encode characters in position %zd-%zd: %U", encoding_str, - uself->start, - uself->end-1, + start, + end - 1, reason_str); } done: @@ -3107,41 +3116,46 @@ UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * UnicodeDecodeError_str(PyObject *self) { - PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; + PyUnicodeErrorObject *exc = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; PyObject *encoding_str = NULL; - if (!uself->object) + if (exc->object == NULL) { /* Not properly initialized. */ return PyUnicode_FromString(""); + } /* Get reason and encoding as strings, which they might not be if they've been modified after we were constructed. */ - reason_str = PyObject_Str(uself->reason); - if (reason_str == NULL) + reason_str = PyObject_Str(exc->reason); + if (reason_str == NULL) { goto done; - encoding_str = PyObject_Str(uself->encoding); - if (encoding_str == NULL) + } + encoding_str = PyObject_Str(exc->encoding); + if (encoding_str == NULL) { goto done; + } + + Py_ssize_t len = PyBytes_GET_SIZE(exc->object); + Py_ssize_t start = exc->start, end = exc->end; - if (uself->start < PyBytes_GET_SIZE(uself->object) && uself->end == uself->start+1) { - int byte = (int)(PyBytes_AS_STRING(((PyUnicodeErrorObject *)self)->object)[uself->start]&0xff); + if ((start >= 0 && start < len) && (end >= 0 && end <= len) && end == start + 1) { + int badbyte = (int)(PyBytes_AS_STRING(exc->object)[start] & 0xff); result = PyUnicode_FromFormat( "'%U' codec can't decode byte 0x%02x in position %zd: %U", encoding_str, - byte, - uself->start, + badbyte, + start, reason_str); } else { result = PyUnicode_FromFormat( "'%U' codec can't decode bytes in position %zd-%zd: %U", encoding_str, - uself->start, - uself->end-1, - reason_str - ); + start, + end - 1, + reason_str); } done: Py_XDECREF(reason_str); @@ -3204,42 +3218,49 @@ UnicodeTranslateError_init(PyUnicodeErrorObject *self, PyObject *args, static PyObject * UnicodeTranslateError_str(PyObject *self) { - PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; + PyUnicodeErrorObject *exc = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; - if (!uself->object) + if (exc->object == NULL) { /* Not properly initialized. */ return PyUnicode_FromString(""); + } /* Get reason as a string, which it might not be if it's been modified after we were constructed. */ - reason_str = PyObject_Str(uself->reason); - if (reason_str == NULL) + reason_str = PyObject_Str(exc->reason); + if (reason_str == NULL) { goto done; + } + + Py_ssize_t len = PyUnicode_GET_LENGTH(exc->object); + Py_ssize_t start = exc->start, end = exc->end; - if (uself->start < PyUnicode_GET_LENGTH(uself->object) && uself->end == uself->start+1) { - Py_UCS4 badchar = PyUnicode_ReadChar(uself->object, uself->start); + if ((start >= 0 && start < len) && (end >= 0 && end <= len) && end == start + 1) { + Py_UCS4 badchar = PyUnicode_ReadChar(exc->object, start); const char *fmt; - if (badchar <= 0xff) + if (badchar <= 0xff) { fmt = "can't translate character '\\x%02x' in position %zd: %U"; - else if (badchar <= 0xffff) + } + else if (badchar <= 0xffff) { fmt = "can't translate character '\\u%04x' in position %zd: %U"; - else + } + else { fmt = "can't translate character '\\U%08x' in position %zd: %U"; + } result = PyUnicode_FromFormat( fmt, (int)badchar, - uself->start, - reason_str - ); - } else { + start, + reason_str); + } + else { result = PyUnicode_FromFormat( "can't translate characters in position %zd-%zd: %U", - uself->start, - uself->end-1, - reason_str - ); + start, + end - 1, + reason_str); } done: Py_XDECREF(reason_str); From e4292c041018dd9e831e541b515fec1119f92690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 8 Oct 2024 13:42:44 +0200 Subject: [PATCH 047/247] gh-123961: Convert _curses to a multi-phase init module (PEP-489) (#124965) --- ...-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst | 2 + Modules/_cursesmodule.c | 192 +++++++++++------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 4 +- 3 files changed, 116 insertions(+), 82 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst diff --git a/Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst b/Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst new file mode 100644 index 00000000000000..b637b895d0b803 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst @@ -0,0 +1,2 @@ +Convert :mod:`curses` to multi-phase initialization (:pep:`489`), thereby +fixing reference leaks at interpreter shutdown. Patch by Bénédikt Tran. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 61b65675375547..27d5df08de933e 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -160,30 +160,31 @@ typedef chtype attr_t; /* No attr_t type is available */ #define _CURSES_PAIR_CONTENT_FUNC pair_content #endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ -typedef struct _cursesmodule_state { - PyObject *error; // PyCursesError - PyTypeObject *window_type; // PyCursesWindow_Type -} _cursesmodule_state; +typedef struct { + PyObject *error; // curses exception type + PyTypeObject *window_type; // exposed by PyCursesWindow_Type +} cursesmodule_state; -// For now, we keep a global state variable to prepare for PEP 489. -static _cursesmodule_state curses_global_state; - -static inline _cursesmodule_state * -get_cursesmodule_state(PyObject *Py_UNUSED(module)) +static inline cursesmodule_state * +get_cursesmodule_state(PyObject *module) { - return &curses_global_state; + void *state = PyModule_GetState(module); + assert(state != NULL); + return (cursesmodule_state *)state; } -static inline _cursesmodule_state * -get_cursesmodule_state_by_cls(PyTypeObject *Py_UNUSED(cls)) +static inline cursesmodule_state * +get_cursesmodule_state_by_cls(PyTypeObject *cls) { - return &curses_global_state; + void *state = PyType_GetModuleState(cls); + assert(state != NULL); + return (cursesmodule_state *)state; } -static inline _cursesmodule_state * -get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win)) +static inline cursesmodule_state * +get_cursesmodule_state_by_win(PyCursesWindowObject *win) { - return &curses_global_state; + return get_cursesmodule_state_by_cls(Py_TYPE(win)); } /*[clinic input] @@ -192,6 +193,9 @@ class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/ +/* Indicate whether the module has already been loaded or not. */ +static int curses_module_loaded = 0; + /* Tells whether setupterm() has been called to initialise terminfo. */ static int curses_setupterm_called = FALSE; @@ -211,8 +215,8 @@ static const char *curses_screen_encoding = NULL; * set and this returns 0. Otherwise, this returns 1. * * Since this function can be called in functions that do not - * have a direct access to the module's state, the exception - * type is directly taken from the global state for now. + * have a direct access to the module's state, '_curses.error' + * is imported on demand. */ static inline int _PyCursesCheckFunction(int called, const char *funcname) @@ -220,7 +224,12 @@ _PyCursesCheckFunction(int called, const char *funcname) if (called == TRUE) { return 1; } - PyErr_Format(curses_global_state.error, "must call %s() first", funcname); + PyObject *exc = _PyImport_GetModuleAttrString("_curses", "error"); + if (exc != NULL) { + PyErr_Format(exc, "must call %s() first", funcname); + Py_DECREF(exc); + } + assert(PyErr_Occurred()); return 0; } @@ -237,7 +246,7 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam if (called == TRUE) { return 1; } - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_Format(state->error, "must call %s() first", funcname); return 0; } @@ -275,7 +284,7 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam /* Utility Functions */ static inline void -_PyCursesSetError(_cursesmodule_state *state, const char *funcname) +_PyCursesSetError(cursesmodule_state *state, const char *funcname) { if (funcname == NULL) { PyErr_SetString(state->error, catchall_ERR); @@ -296,7 +305,7 @@ PyCursesCheckERR(PyObject *module, int code, const char *fname) if (code != ERR) { Py_RETURN_NONE; } else { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); _PyCursesSetError(state, fname); return NULL; } @@ -308,7 +317,7 @@ PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, const char *fname) if (code != ERR) { Py_RETURN_NONE; } else { - _cursesmodule_state *state = get_cursesmodule_state_by_win(win); + cursesmodule_state *state = get_cursesmodule_state_by_win(win); _PyCursesSetError(state, fname); return NULL; } @@ -746,7 +755,7 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns") /* Allocation and deallocation of Window Objects */ static PyObject * -PyCursesWindow_New(_cursesmodule_state *state, +PyCursesWindow_New(cursesmodule_state *state, WINDOW *win, const char *encoding) { if (encoding == NULL) { @@ -1405,12 +1414,12 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, win = derwin(self->win,nlines,ncols,begin_y,begin_x); if (win == NULL) { - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, catchall_NULL); return NULL; } - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); return PyCursesWindow_New(state, win, NULL); } @@ -1559,7 +1568,7 @@ _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1, /* getch() returns ERR in nodelay mode */ PyErr_CheckSignals(); if (!PyErr_Occurred()) { - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "no input"); } return NULL; @@ -1619,7 +1628,7 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, return NULL; /* get_wch() returns ERR in nodelay mode */ - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "no input"); return NULL; } @@ -2133,7 +2142,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) #ifdef py_is_pad if (py_is_pad(self->win)) { if (!group_right_1) { - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "noutrefresh() called for a pad " "requires 6 arguments"); @@ -2358,7 +2367,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, #ifdef py_is_pad if (py_is_pad(self->win)) { if (!group_right_1) { - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "refresh() for a pad requires 6 arguments"); return NULL; @@ -2441,12 +2450,12 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, win = subwin(self->win, nlines, ncols, begin_y, begin_x); if (win == NULL) { - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, catchall_NULL); return NULL; } - _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + cursesmodule_state *state = get_cursesmodule_state_by_win(self); return PyCursesWindow_New(state, win, self->encoding); } @@ -2846,7 +2855,7 @@ _curses_color_content_impl(PyObject *module, int color_number) PyCursesStatefulInitialisedColor(module); if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) == ERR) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_Format(state->error, "%s() returned ERR", Py_STRINGIFY(_COLOR_CONTENT_FUNC)); return NULL; @@ -3086,7 +3095,7 @@ _curses_getmouse_impl(PyObject *module) rtn = getmouse( &event ); if (rtn == ERR) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, "getmouse() returned ERR"); return NULL; } @@ -3181,11 +3190,11 @@ _curses_getwin(PyObject *module, PyObject *file) fseek(fp, 0, 0); win = getwin(fp); if (win == NULL) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); goto error; } - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); res = PyCursesWindow_New(state, win, NULL); error: @@ -3332,7 +3341,7 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) COLOR_PAIRS - 1); } else { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_Format(state->error, "%s() returned ERR", Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC)); } @@ -3358,14 +3367,14 @@ _curses_initscr_impl(PyObject *module) if (curses_initscr_called) { wrefresh(stdscr); - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); return PyCursesWindow_New(state, stdscr, NULL); } win = initscr(); if (win == NULL) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); return NULL; } @@ -3462,7 +3471,7 @@ _curses_initscr_impl(PyObject *module) SetDictInt("COLS", COLS); #undef SetDictInt - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyObject *winobj = PyCursesWindow_New(state, win, NULL); if (winobj == NULL) { return NULL; @@ -3496,7 +3505,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) sys_stdout = PySys_GetObject("stdout"); if (sys_stdout == NULL || sys_stdout == Py_None) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, "lost sys.stdout"); return NULL; } @@ -3517,7 +3526,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) s = "setupterm: could not find terminfo database"; } - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, s); return NULL; } @@ -3835,12 +3844,12 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) win = newpad(nlines, ncols); if (win == NULL) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); return NULL; } - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); return PyCursesWindow_New(state, win, NULL); } @@ -3876,12 +3885,12 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, win = newwin(nlines,ncols,begin_y,begin_x); if (win == NULL) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); return NULL; } - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); return PyCursesWindow_New(state, win, NULL); } @@ -3996,7 +4005,7 @@ _curses_pair_content_impl(PyObject *module, int pair_number) COLOR_PAIRS - 1); } else { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_Format(state->error, "%s() returned ERR", Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC)); } @@ -4327,7 +4336,7 @@ _curses_start_color_impl(PyObject *module) PyCursesStatefulInitialised(module); if (start_color() == ERR) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, "start_color() returned ERR"); return NULL; } @@ -4480,7 +4489,7 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3, result = tparm((char *)str,i1,i2,i3,i4,i5,i6,i7,i8,i9); if (!result) { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, "tparm() returned NULL"); return NULL; } @@ -4682,7 +4691,7 @@ _curses_use_default_colors_impl(PyObject *module) if (code != ERR) { Py_RETURN_NONE; } else { - _cursesmodule_state *state = get_cursesmodule_state(module); + cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, "use_default_colors() returned ERR"); return NULL; } @@ -4763,7 +4772,7 @@ _curses_has_extended_color_support_impl(PyObject *module) /* List of functions defined in the module */ -static PyMethodDef PyCurses_methods[] = { +static PyMethodDef cursesmodule_methods[] = { _CURSES_BAUDRATE_METHODDEF _CURSES_BEEP_METHODDEF _CURSES_CAN_CHANGE_COLOR_METHODDEF @@ -4872,7 +4881,7 @@ curses_capi_start_color_called(void) } static void * -curses_capi_new(_cursesmodule_state *state) +curses_capi_new(cursesmodule_state *state) { assert(state->window_type != NULL); void **capi = (void **)PyMem_Calloc(PyCurses_API_pointers, sizeof(void *)); @@ -4892,8 +4901,9 @@ curses_capi_free(void *capi) { assert(capi != NULL); void **capi_ptr = (void **)capi; - assert(capi_ptr[0] != NULL); - Py_DECREF(capi_ptr[0]); // decref curses window type + // In free-threaded builds, capi_ptr[0] may have been already cleared + // by curses_capi_capsule_destructor(), hence the use of Py_XDECREF(). + Py_XDECREF(capi_ptr[0]); // decref curses window type PyMem_Free(capi_ptr); } @@ -4942,12 +4952,44 @@ curses_capi_capsule_new(void *capi) return capsule; } -/* Module initialization */ +/* Module initialization and cleanup functions */ + +static int +cursesmodule_traverse(PyObject *mod, visitproc visit, void *arg) +{ + cursesmodule_state *state = get_cursesmodule_state(mod); + Py_VISIT(state->error); + Py_VISIT(state->window_type); + return 0; +} + +static int +cursesmodule_clear(PyObject *mod) +{ + cursesmodule_state *state = get_cursesmodule_state(mod); + Py_CLEAR(state->error); + Py_CLEAR(state->window_type); + return 0; +} + +static void +cursesmodule_free(void *mod) +{ + (void)cursesmodule_clear((PyObject *)mod); + curses_module_loaded = 0; // allow reloading once garbage-collected +} static int cursesmodule_exec(PyObject *module) { - _cursesmodule_state *state = get_cursesmodule_state(module); + if (curses_module_loaded) { + PyErr_SetString(PyExc_ImportError, + "module 'curses' can only be loaded once per process"); + return -1; + } + curses_module_loaded = 1; + + cursesmodule_state *state = get_cursesmodule_state(module); /* Initialize object type */ state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec( module, &PyCursesWindow_Type_spec, NULL); @@ -4987,7 +5029,6 @@ cursesmodule_exec(PyObject *module) return -1; } rc = PyDict_SetItemString(module_dict, "error", state->error); - Py_DECREF(state->error); if (rc < 0) { return -1; } @@ -5181,33 +5222,26 @@ cursesmodule_exec(PyObject *module) /* Initialization function for the module */ -static struct PyModuleDef _cursesmodule = { +static PyModuleDef_Slot cursesmodule_slots[] = { + {Py_mod_exec, cursesmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL} +}; + +static struct PyModuleDef cursesmodule = { PyModuleDef_HEAD_INIT, .m_name = "_curses", - .m_size = -1, - .m_methods = PyCurses_methods, + .m_size = sizeof(cursesmodule_state), + .m_methods = cursesmodule_methods, + .m_slots = cursesmodule_slots, + .m_traverse = cursesmodule_traverse, + .m_clear = cursesmodule_clear, + .m_free = cursesmodule_free }; PyMODINIT_FUNC PyInit__curses(void) { - // create the module - PyObject *mod = PyModule_Create(&_cursesmodule); - if (mod == NULL) { - goto error; - } -#ifdef Py_GIL_DISABLED - if (PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED) < 0) { - goto error; - } -#endif - // populate the module - if (cursesmodule_exec(mod) < 0) { - goto error; - } - return mod; - -error: - Py_XDECREF(mod); - return NULL; + return PyModuleDef_Init(&cursesmodule); } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index a0be2a0a203f8c..badd7b79102310 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -358,7 +358,6 @@ Modules/_testclinic.c - TestClass - ##----------------------- ## static types -Modules/_cursesmodule.c - PyCursesWindow_Type - Modules/_datetimemodule.c - PyDateTime_DateTimeType - Modules/_datetimemodule.c - PyDateTime_DateType - Modules/_datetimemodule.c - PyDateTime_DeltaType - @@ -383,7 +382,6 @@ Modules/_tkinter.c - Tktt_Type - Modules/xxlimited_35.c - Xxo_Type - ## exception types -Modules/_cursesmodule.c - PyCursesError - Modules/_tkinter.c - Tkinter_TclError - Modules/xxlimited_35.c - ErrorObject - Modules/xxmodule.c - ErrorObject - @@ -409,6 +407,7 @@ Modules/_tkinter.c - trbInCmd - Include/datetime.h - PyDateTimeAPI - Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized - Modules/_ctypes/malloc_closure.c - _pagesize - +Modules/_cursesmodule.c - curses_module_loaded - Modules/_cursesmodule.c - curses_initscr_called - Modules/_cursesmodule.c - curses_setupterm_called - Modules/_cursesmodule.c - curses_start_color_called - @@ -423,7 +422,6 @@ Modules/readline.c - libedit_history_start - Modules/_ctypes/cfield.c - formattable - Modules/_ctypes/malloc_closure.c - free_list - -Modules/_cursesmodule.c - curses_global_state - Modules/_curses_panel.c - lop - Modules/_ssl/debughelpers.c _PySSL_keylog_callback lock - Modules/_tkinter.c - quitMainLoop - From 43ad3b51707f51ae4b434e2b5950d2c8bf7cca6e Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 8 Oct 2024 04:49:50 -0700 Subject: [PATCH 048/247] gh-90102: Fix pyio _isatty_open_only() (#125089) Spotted by @ngnpope. `isatty` returns False to indicate the file is not a TTY. The C implementation of _io does that (`Py_RETURN_FALSE`) but I got the bool backwards in the _pyio implementaiton. --- Lib/_pyio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 2a1d2a33d02960..7b6d10c008d3cb 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -1806,7 +1806,7 @@ def _isatty_open_only(self): """ if (self._stat_atopen is not None and not stat.S_ISCHR(self._stat_atopen.st_mode)): - return True + return False return os.isatty(self._fd) @property From 9047146e546599325cddda266e420f42fb318e4e Mon Sep 17 00:00:00 2001 From: Jan Kaliszewski Date: Tue, 8 Oct 2024 14:13:37 +0200 Subject: [PATCH 049/247] gh-75898: make use of thread more explicit in the "Socket Programming HOWTO" document (#125023) --- Doc/howto/sockets.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst index 0bbf97da39768d..cbc49d15a0771b 100644 --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -100,8 +100,8 @@ mainloop of the web server:: (clientsocket, address) = serversocket.accept() # now do something with the clientsocket # in this case, we'll pretend this is a threaded server - ct = client_thread(clientsocket) - ct.run() + ct = make_client_thread(clientsocket) + ct.start() There's actually 3 general ways in which this loop could work - dispatching a thread to handle ``clientsocket``, create a new process to handle From 9a35d053383c87d577ea09951bc9740704f4788d Mon Sep 17 00:00:00 2001 From: Mikhail Efimov Date: Tue, 8 Oct 2024 15:18:28 +0300 Subject: [PATCH 050/247] gh-121404: typo fix in compile.c: MATADATA -> METADATA (#125101) --- Python/compile.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 9826d3fbbde976..d463fcde204a05 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1534,7 +1534,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, _PyCompile_CodeUnitMetadata *umd = &c->u->u_metadata; -#define SET_MATADATA_INT(key, value) do { \ +#define SET_METADATA_INT(key, value) do { \ PyObject *v = PyLong_FromLong((long)value); \ if (v == NULL) goto finally; \ int res = PyDict_SetItemString(metadata, key, v); \ @@ -1542,10 +1542,10 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, if (res < 0) goto finally; \ } while (0); - SET_MATADATA_INT("argcount", umd->u_argcount); - SET_MATADATA_INT("posonlyargcount", umd->u_posonlyargcount); - SET_MATADATA_INT("kwonlyargcount", umd->u_kwonlyargcount); -#undef SET_MATADATA_INT + SET_METADATA_INT("argcount", umd->u_argcount); + SET_METADATA_INT("posonlyargcount", umd->u_posonlyargcount); + SET_METADATA_INT("kwonlyargcount", umd->u_kwonlyargcount); +#undef SET_METADATA_INT int addNone = mod->kind != Expression_kind; if (_PyCodegen_AddReturnAtEnd(c, addNone) < 0) { From e8773e59a835d23b9648271e0eb79c1651581564 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Tue, 8 Oct 2024 15:25:40 +0300 Subject: [PATCH 051/247] Doc: Improve description of ``GET_LEN`` opcode (#114583) --- Doc/library/dis.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 75b84a8d827bc9..1d084a8bf38d98 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -969,7 +969,8 @@ iterations of the loop. .. opcode:: GET_LEN - Perform ``STACK.append(len(STACK[-1]))``. + Perform ``STACK.append(len(STACK[-1]))``. Used in :keyword:`match` statements where + comparison with structure of pattern is needed. .. versionadded:: 3.10 From 5967dd8a4de60a418de84d1d1d9efc063ad12c47 Mon Sep 17 00:00:00 2001 From: monkeyman192 Date: Tue, 8 Oct 2024 23:41:46 +1100 Subject: [PATCH 052/247] gh-112433 add versionadded for `ctypes.Structure._align_` (#125087) Co-authored-by: Kumar Aditya --- Doc/library/ctypes.rst | 2 ++ Doc/whatsnew/3.13.rst | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 535c5173be50de..d76b8d4809c078 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2589,6 +2589,8 @@ fields, or any other data types containing pointer type fields. the structure when being packed or unpacked to/from memory. Setting this attribute to 0 is the same as not setting it at all. + .. versionadded:: 3.13 + .. attribute:: _layout_ An optional string naming the struct/union layout. It can currently diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index a47d5e077a357b..565f74149725d5 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -814,6 +814,10 @@ ctypes See :gh:`124520` for discussion and links to changes in some affected projects. +* :class:`ctypes.Structure` objects have a new :attr:`~ctypes.Structure._align_` + attribute which allows the alignment of the structure being packed to/from + memory to be specified explicitly. + (Contributed by Matt Sanderson in :gh:`112433`) dbm --- From 65ce228d63878d8b6d0005f682e89ad9d5289c4b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 8 Oct 2024 15:48:40 +0200 Subject: [PATCH 053/247] gh-125096: Don't import _pyrepl in site if PYTHON_BASIC_REPL (#125097) If the PYTHON_BASIC_REPL environment variable is set, the site module no longer imports the _pyrepl module. Moreover, the site module now respects -E and -I command line options: ignore PYTHON_BASIC_REPL in this case. --- Lib/site.py | 26 ++++++++++++++----- Lib/test/test_pyrepl/test_pyrepl.py | 12 +++++++++ ...-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst | 5 ++++ 3 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst diff --git a/Lib/site.py b/Lib/site.py index cafd3ab70b2cac..b3194d79fb5ab8 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -491,12 +491,21 @@ def register_readline(): This can be overridden in the sitecustomize or usercustomize module, or in a PYTHONSTARTUP file. """ + if not sys.flags.ignore_environment: + PYTHON_BASIC_REPL = os.getenv("PYTHON_BASIC_REPL") + else: + PYTHON_BASIC_REPL = False + import atexit try: import readline import rlcompleter # noqa: F401 - import _pyrepl.readline - import _pyrepl.unix_console + if PYTHON_BASIC_REPL: + CAN_USE_PYREPL = False + else: + import _pyrepl.readline + import _pyrepl.unix_console + from _pyrepl.main import CAN_USE_PYREPL except ImportError: return @@ -517,7 +526,6 @@ def register_readline(): pass if readline.get_current_history_length() == 0: - from _pyrepl.main import CAN_USE_PYREPL # If no history was loaded, default to .python_history, # or PYTHON_HISTORY. # The guard is necessary to avoid doubling history size at @@ -525,13 +533,17 @@ def register_readline(): # through a PYTHONSTARTUP hook, see: # http://bugs.python.org/issue5845#msg198636 history = gethistoryfile() - if os.getenv("PYTHON_BASIC_REPL") or not CAN_USE_PYREPL: - readline_module = readline - else: + + if CAN_USE_PYREPL: readline_module = _pyrepl.readline + exceptions = (OSError, *_pyrepl.unix_console._error) + else: + readline_module = readline + exceptions = OSError + try: readline_module.read_history_file(history) - except (OSError,* _pyrepl.unix_console._error): + except exceptions: pass def write_history(): diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index 36f940eaea4eac..1a76832386bf1d 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -1204,6 +1204,18 @@ def test_python_basic_repl(self): self.assertNotIn("Exception", output) self.assertNotIn("Traceback", output) + # The site module must not load _pyrepl if PYTHON_BASIC_REPL is set + commands = ("import sys\n" + "print('_pyrepl' in sys.modules)\n" + "exit()\n") + env["PYTHON_BASIC_REPL"] = "1" + output, exit_code = self.run_repl(commands, env=env) + self.assertEqual(exit_code, 0) + self.assertIn("False", output) + self.assertNotIn("True", output) + self.assertNotIn("Exception", output) + self.assertNotIn("Traceback", output) + @force_not_colorized def test_bad_sys_excepthook_doesnt_crash_pyrepl(self): env = os.environ.copy() diff --git a/Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst b/Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst new file mode 100644 index 00000000000000..c582a2dfe7243c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst @@ -0,0 +1,5 @@ +If the :envvar:`PYTHON_BASIC_REPL` environment variable is set, the +:mod:`site` module no longer imports the :mod:`!_pyrepl` module. Moreover, +the :mod:`site` module now respects :option:`-E` and :option:`-I` command +line options: ignore :envvar:`PYTHON_BASIC_REPL` in this case. Patch by +Victor Stinner. From e99f159be4f70cf9e40865d638e79fa426968827 Mon Sep 17 00:00:00 2001 From: mpage Date: Tue, 8 Oct 2024 07:04:35 -0700 Subject: [PATCH 054/247] gh-115999: Stop the world when invalidating function versions (#124997) Stop the world when invalidating function versions The tier1 interpreter specializes `CALL` instructions based on the values of certain function attributes (e.g. `__code__`, `__defaults__`). The tier1 interpreter uses function versions to verify that the attributes of a function during execution of a specialization match those seen during specialization. A function's version is initialized in `MAKE_FUNCTION` and is invalidated when any of the critical function attributes are changed. The tier1 interpreter stores the function version in the inline cache during specialization. A guard is used by the specialized instruction to verify that the version of the function on the operand stack matches the cached version (and therefore has all of the expected attributes). It is assumed that once the guard passes, all attributes will remain unchanged while executing the rest of the specialized instruction. Stopping the world when invalidating function versions ensures that all critical function attributes will remain unchanged after the function version guard passes in free-threaded builds. It's important to note that this is only true if the remainder of the specialized instruction does not enter and exit a stop-the-world point. We will stop the world the first time any of the following function attributes are mutated: - defaults - vectorcall - kwdefaults - closure - code This should happen rarely and only happens once per function, so the performance impact on majority of code should be minimal. Additionally, refactor the API for manipulating function versions to more clearly match the stated semantics. --- Include/internal/pycore_function.h | 10 +++ Include/internal/pycore_runtime_init.h | 3 +- Objects/funcobject.c | 89 ++++++++++++++++---------- Python/specialize.c | 8 +-- 4 files changed, 72 insertions(+), 38 deletions(-) diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 6d44e933e8a8cb..c45d281125febb 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -18,6 +18,10 @@ extern PyObject* _PyFunction_Vectorcall( #define FUNC_MAX_WATCHERS 8 +#define FUNC_VERSION_UNSET 0 +#define FUNC_VERSION_CLEARED 1 +#define FUNC_VERSION_FIRST_VALID 2 + #define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ struct _func_version_cache_item { @@ -41,6 +45,12 @@ struct _py_func_state { extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr); +static inline int +_PyFunction_IsVersionValid(uint32_t version) +{ + return version >= FUNC_VERSION_FIRST_VALID; +} + extern uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func); PyAPI_FUNC(void) _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version); void _PyFunction_ClearCodeByVersion(uint32_t version); diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index e6adb98eb19130..a17ba46966daa1 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -11,6 +11,7 @@ extern "C" { #include "pycore_ceval_state.h" // _PyEval_RUNTIME_PERF_INIT #include "pycore_faulthandler.h" // _faulthandler_runtime_state_INIT #include "pycore_floatobject.h" // _py_float_format_unknown +#include "pycore_function.h" #include "pycore_object.h" // _PyObject_HEAD_INIT #include "pycore_obmalloc_init.h" // _obmalloc_global_state_INIT #include "pycore_parser.h" // _parser_runtime_state_INIT @@ -243,7 +244,7 @@ extern PyTypeObject _PyExc_MemoryError; .dict_state = _dict_state_INIT, \ .mem_free_queue = _Py_mem_free_queue_INIT(INTERP.mem_free_queue), \ .func_state = { \ - .next_version = 1, \ + .next_version = FUNC_VERSION_FIRST_VALID, \ }, \ .types = { \ .next_version_tag = _Py_TYPE_BASE_VERSION_TAG, \ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 98e6766d0ca0d8..855d1a2eeca819 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -128,7 +128,7 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr) op->func_annotate = NULL; op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; - op->func_version = 0; + op->func_version = FUNC_VERSION_UNSET; // NOTE: functions created via FrameConstructor do not use deferred // reference counting because they are typically not part of cycles // nor accessed by multiple threads. @@ -207,7 +207,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname op->func_annotate = NULL; op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; - op->func_version = 0; + op->func_version = FUNC_VERSION_UNSET; if ((code_obj->co_flags & CO_NESTED) == 0) { // Use deferred reference counting for top-level functions, but not // nested functions because they are more likely to capture variables, @@ -287,31 +287,59 @@ functions is running. */ +static inline struct _func_version_cache_item * +get_cache_item(PyInterpreterState *interp, uint32_t version) +{ + return interp->func_state.func_version_cache + + (version % FUNC_VERSION_CACHE_SIZE); +} + void _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version) { + assert(func->func_version == FUNC_VERSION_UNSET); + assert(version >= FUNC_VERSION_FIRST_VALID); + // This should only be called from MAKE_FUNCTION. No code is specialized + // based on the version, so we do not need to stop the world to set it. + func->func_version = version; #ifndef Py_GIL_DISABLED PyInterpreterState *interp = _PyInterpreterState_GET(); - if (func->func_version != 0) { - struct _func_version_cache_item *slot = - interp->func_state.func_version_cache - + (func->func_version % FUNC_VERSION_CACHE_SIZE); - if (slot->func == func) { - slot->func = NULL; - // Leave slot->code alone, there may be use for it. - } - } + struct _func_version_cache_item *slot = get_cache_item(interp, version); + slot->func = func; + slot->code = func->func_code; #endif - func->func_version = version; +} + +static void +func_clear_version(PyInterpreterState *interp, PyFunctionObject *func) +{ + if (func->func_version < FUNC_VERSION_FIRST_VALID) { + // Version was never set or has already been cleared. + return; + } #ifndef Py_GIL_DISABLED - if (version != 0) { - struct _func_version_cache_item *slot = - interp->func_state.func_version_cache - + (version % FUNC_VERSION_CACHE_SIZE); - slot->func = func; - slot->code = func->func_code; + struct _func_version_cache_item *slot = + get_cache_item(interp, func->func_version); + if (slot->func == func) { + slot->func = NULL; + // Leave slot->code alone, there may be use for it. } #endif + func->func_version = FUNC_VERSION_CLEARED; +} + +// Called when any of the critical function attributes are changed +static void +_PyFunction_ClearVersion(PyFunctionObject *func) +{ + if (func->func_version < FUNC_VERSION_FIRST_VALID) { + // Version was never set or has already been cleared. + return; + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyEval_StopTheWorld(interp); + func_clear_version(interp, func); + _PyEval_StartTheWorld(interp); } void @@ -319,9 +347,7 @@ _PyFunction_ClearCodeByVersion(uint32_t version) { #ifndef Py_GIL_DISABLED PyInterpreterState *interp = _PyInterpreterState_GET(); - struct _func_version_cache_item *slot = - interp->func_state.func_version_cache - + (version % FUNC_VERSION_CACHE_SIZE); + struct _func_version_cache_item *slot = get_cache_item(interp, version); if (slot->code) { assert(PyCode_Check(slot->code)); PyCodeObject *code = (PyCodeObject *)slot->code; @@ -340,9 +366,7 @@ _PyFunction_LookupByVersion(uint32_t version, PyObject **p_code) return NULL; #else PyInterpreterState *interp = _PyInterpreterState_GET(); - struct _func_version_cache_item *slot = - interp->func_state.func_version_cache - + (version % FUNC_VERSION_CACHE_SIZE); + struct _func_version_cache_item *slot = get_cache_item(interp, version); if (slot->code) { assert(PyCode_Check(slot->code)); PyCodeObject *code = (PyCodeObject *)slot->code; @@ -431,7 +455,7 @@ PyFunction_SetDefaults(PyObject *op, PyObject *defaults) } handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS, (PyFunctionObject *) op, defaults); - _PyFunction_SetVersion((PyFunctionObject *)op, 0); + _PyFunction_ClearVersion((PyFunctionObject *)op); Py_XSETREF(((PyFunctionObject *)op)->func_defaults, defaults); return 0; } @@ -440,7 +464,7 @@ void PyFunction_SetVectorcall(PyFunctionObject *func, vectorcallfunc vectorcall) { assert(func != NULL); - _PyFunction_SetVersion(func, 0); + _PyFunction_ClearVersion(func); func->vectorcall = vectorcall; } @@ -473,7 +497,7 @@ PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults) } handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS, (PyFunctionObject *) op, defaults); - _PyFunction_SetVersion((PyFunctionObject *)op, 0); + _PyFunction_ClearVersion((PyFunctionObject *)op); Py_XSETREF(((PyFunctionObject *)op)->func_kwdefaults, defaults); return 0; } @@ -506,7 +530,7 @@ PyFunction_SetClosure(PyObject *op, PyObject *closure) Py_TYPE(closure)->tp_name); return -1; } - _PyFunction_SetVersion((PyFunctionObject *)op, 0); + _PyFunction_ClearVersion((PyFunctionObject *)op); Py_XSETREF(((PyFunctionObject *)op)->func_closure, closure); return 0; } @@ -658,7 +682,7 @@ func_set_code(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) } handle_func_event(PyFunction_EVENT_MODIFY_CODE, op, value); - _PyFunction_SetVersion(op, 0); + _PyFunction_ClearVersion(op); Py_XSETREF(op->func_code, Py_NewRef(value)); return 0; } @@ -744,7 +768,7 @@ func_set_defaults(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) } handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS, op, value); - _PyFunction_SetVersion(op, 0); + _PyFunction_ClearVersion(op); Py_XSETREF(op->func_defaults, Py_XNewRef(value)); return 0; } @@ -787,7 +811,7 @@ func_set_kwdefaults(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) } handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS, op, value); - _PyFunction_SetVersion(op, 0); + _PyFunction_ClearVersion(op); Py_XSETREF(op->func_kwdefaults, Py_XNewRef(value)); return 0; } @@ -1030,7 +1054,7 @@ static int func_clear(PyObject *self) { PyFunctionObject *op = _PyFunction_CAST(self); - _PyFunction_SetVersion(op, 0); + func_clear_version(_PyInterpreterState_GET(), op); Py_CLEAR(op->func_globals); Py_CLEAR(op->func_builtins); Py_CLEAR(op->func_module); @@ -1068,7 +1092,6 @@ func_dealloc(PyObject *self) if (op->func_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *) op); } - _PyFunction_SetVersion(op, 0); (void)func_clear((PyObject*)op); // These aren't cleared by func_clear(). Py_DECREF(op->func_code); diff --git a/Python/specialize.c b/Python/specialize.c index d8bff39511cf12..4b33a468733d6b 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1599,7 +1599,7 @@ function_get_version(PyObject *o, int opcode) assert(Py_IS_TYPE(o, &PyFunction_Type)); PyFunctionObject *func = (PyFunctionObject *)o; uint32_t version = _PyFunction_GetVersionForCurrentState(func); - if (version == 0) { + if (!_PyFunction_IsVersionValid(version)) { SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS); return 0; } @@ -1692,7 +1692,7 @@ _Py_Specialize_BinarySubscr( goto fail; } uint32_t version = _PyFunction_GetVersionForCurrentState(func); - if (version == 0) { + if (!_PyFunction_IsVersionValid(version)) { SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } @@ -1977,7 +1977,7 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, argcount = code->co_argcount; } int version = _PyFunction_GetVersionForCurrentState(func); - if (version == 0) { + if (!_PyFunction_IsVersionValid(version)) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); return -1; } @@ -2009,7 +2009,7 @@ specialize_py_call_kw(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, return -1; } int version = _PyFunction_GetVersionForCurrentState(func); - if (version == 0) { + if (!_PyFunction_IsVersionValid(version)) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); return -1; } From c203955f3b433e06118d00a2fe7215546a0b7fe6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 8 Oct 2024 16:25:24 +0200 Subject: [PATCH 055/247] gh-124502: Optimize unicode_eq() (#125105) --- Objects/stringlib/eq.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Objects/stringlib/eq.h b/Objects/stringlib/eq.h index 2eac4baf5ca9ce..821b692f26b830 100644 --- a/Objects/stringlib/eq.h +++ b/Objects/stringlib/eq.h @@ -4,14 +4,19 @@ * unicode_eq() is called when the hash of two unicode objects is equal. */ Py_LOCAL_INLINE(int) -unicode_eq(PyObject *a, PyObject *b) +unicode_eq(PyObject *str1, PyObject *str2) { - if (PyUnicode_GET_LENGTH(a) != PyUnicode_GET_LENGTH(b)) + Py_ssize_t len = PyUnicode_GET_LENGTH(str1); + if (PyUnicode_GET_LENGTH(str2) != len) { return 0; - if (PyUnicode_GET_LENGTH(a) == 0) - return 1; - if (PyUnicode_KIND(a) != PyUnicode_KIND(b)) + } + + int kind = PyUnicode_KIND(str1); + if (PyUnicode_KIND(str2) != kind) { return 0; - return memcmp(PyUnicode_1BYTE_DATA(a), PyUnicode_1BYTE_DATA(b), - PyUnicode_GET_LENGTH(a) * PyUnicode_KIND(a)) == 0; + } + + const void *data1 = PyUnicode_DATA(str1); + const void *data2 = PyUnicode_DATA(str2); + return (memcmp(data1, data2, len * kind) == 0); } From fca552993da32044165223eec2297b6aaaac60ad Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Tue, 8 Oct 2024 20:17:32 +0530 Subject: [PATCH 056/247] gh-117721: use PyMutex in `_thread.lock` (#125110) --- Modules/_threadmodule.c | 56 ++++++++--------------------------------- 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 153fe85597749d..9617f9cafe76ff 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -705,9 +705,7 @@ static PyType_Spec ThreadHandle_Type_spec = { typedef struct { PyObject_HEAD - PyThread_type_lock lock_lock; - PyObject *in_weakreflist; - char locked; /* for sanity checking */ + PyMutex lock; } lockobject; static int @@ -722,15 +720,7 @@ lock_dealloc(PyObject *op) { lockobject *self = (lockobject*)op; PyObject_GC_UnTrack(self); - if (self->in_weakreflist != NULL) { - PyObject_ClearWeakRefs((PyObject *) self); - } - if (self->lock_lock != NULL) { - /* Unlock the lock so it's safe to free it */ - if (self->locked) - PyThread_release_lock(self->lock_lock); - PyThread_free_lock(self->lock_lock); - } + PyObject_ClearWeakRefs((PyObject *) self); PyTypeObject *tp = Py_TYPE(self); tp->tp_free((PyObject*)self); Py_DECREF(tp); @@ -798,13 +788,12 @@ lock_PyThread_acquire_lock(PyObject *op, PyObject *args, PyObject *kwds) return NULL; } - PyLockStatus r = acquire_timed(self->lock_lock, timeout); + PyLockStatus r = _PyMutex_LockTimed(&self->lock, timeout, + _PY_LOCK_HANDLE_SIGNALS | _PY_LOCK_DETACH); if (r == PY_LOCK_INTR) { return NULL; } - if (r == PY_LOCK_ACQUIRED) - self->locked = 1; return PyBool_FromLong(r == PY_LOCK_ACQUIRED); } @@ -836,13 +825,11 @@ lock_PyThread_release_lock(PyObject *op, PyObject *Py_UNUSED(ignored)) { lockobject *self = (lockobject*)op; /* Sanity check: the lock must be locked */ - if (!self->locked) { + if (_PyMutex_TryUnlock(&self->lock) < 0) { PyErr_SetString(ThreadError, "release unlocked lock"); return NULL; } - self->locked = 0; - PyThread_release_lock(self->lock_lock); Py_RETURN_NONE; } @@ -870,7 +857,7 @@ static PyObject * lock_locked_lock(PyObject *op, PyObject *Py_UNUSED(ignored)) { lockobject *self = (lockobject*)op; - return PyBool_FromLong((long)self->locked); + return PyBool_FromLong(PyMutex_IsLocked(&self->lock)); } PyDoc_STRVAR(locked_doc, @@ -890,21 +877,15 @@ lock_repr(PyObject *op) { lockobject *self = (lockobject*)op; return PyUnicode_FromFormat("<%s %s object at %p>", - self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self); + PyMutex_IsLocked(&self->lock) ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self); } #ifdef HAVE_FORK static PyObject * lock__at_fork_reinit(PyObject *op, PyObject *Py_UNUSED(args)) { - lockobject *self = (lockobject*)op; - if (_PyThread_at_fork_reinit(&self->lock_lock) < 0) { - PyErr_SetString(ThreadError, "failed to reinitialize lock at fork"); - return NULL; - } - - self->locked = 0; - + lockobject *self = (lockobject *)op; + _PyMutex_at_fork_reinit(&self->lock); Py_RETURN_NONE; } #endif /* HAVE_FORK */ @@ -970,18 +951,12 @@ A lock is not owned by the thread that locked it; another thread may\n\ unlock it. A thread attempting to lock a lock that it has already locked\n\ will block until another thread unlocks it. Deadlocks may ensue."); -static PyMemberDef lock_type_members[] = { - {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(lockobject, in_weakreflist), Py_READONLY}, - {NULL}, -}; - static PyType_Slot lock_type_slots[] = { {Py_tp_dealloc, lock_dealloc}, {Py_tp_repr, lock_repr}, {Py_tp_doc, (void *)lock_doc}, {Py_tp_methods, lock_methods}, {Py_tp_traverse, lock_traverse}, - {Py_tp_members, lock_type_members}, {Py_tp_new, lock_new}, {0, 0} }; @@ -990,7 +965,7 @@ static PyType_Spec lock_type_spec = { .name = "_thread.lock", .basicsize = sizeof(lockobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_IMMUTABLETYPE), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_WEAKREF), .slots = lock_type_slots, }; @@ -1340,16 +1315,7 @@ newlockobject(PyObject *module) if (self == NULL) { return NULL; } - - self->lock_lock = PyThread_allocate_lock(); - self->locked = 0; - self->in_weakreflist = NULL; - - if (self->lock_lock == NULL) { - Py_DECREF(self); - PyErr_SetString(ThreadError, "can't allocate lock"); - return NULL; - } + self->lock = (PyMutex){0}; return self; } From 7dca7322cca7ff146444e56f28f21f1090987fff Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 8 Oct 2024 10:16:02 -0700 Subject: [PATCH 057/247] gh-125084: Resolve paths in generator common code (GH-125085) In out of tree builds, the paths can contain `../ which needs to be resolved for the relative path calculation to work. --- Tools/cases_generator/generators_common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index f32a20b304c354..0bfa1a3b56fbc2 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -43,13 +43,13 @@ def peek(self) -> Token | None: break return self.look_ahead -ROOT = Path(__file__).parent.parent.parent -DEFAULT_INPUT = (ROOT / "Python/bytecodes.c").absolute().as_posix() +ROOT = Path(__file__).parent.parent.parent.resolve() +DEFAULT_INPUT = (ROOT / "Python/bytecodes.c").as_posix() def root_relative_path(filename: str) -> str: try: - return Path(filename).absolute().relative_to(ROOT).as_posix() + return Path(filename).resolve().relative_to(ROOT).as_posix() except ValueError: # Not relative to root, just return original path. return filename From c6127af8685c2a9b416207e46089cee79d028b85 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 8 Oct 2024 13:18:39 -0400 Subject: [PATCH 058/247] gh-125063: Emit slices as constants in the bytecode compiler (#125064) * Make slices marshallable * Emit slices as constants * Update Python/marshal.c Co-authored-by: Peter Bierma * Refactor codegen_slice into two functions so it always has the same net effect * Fix for free-threaded builds * Simplify marshal loading of slices * Only return SUCCESS/ERROR from codegen_slice --------- Co-authored-by: Mark Shannon Co-authored-by: Peter Bierma --- Include/internal/pycore_magic_number.h | 3 +- Lib/test/test_compile.py | 27 ++++++++- Objects/codeobject.c | 1 + Objects/sliceobject.c | 2 +- Python/codegen.c | 78 +++++++++++++++++++------- Python/marshal.c | 34 +++++++++++ 6 files changed, 122 insertions(+), 23 deletions(-) diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index 2414d25d41bfbf..a88ff2deeba941 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -259,6 +259,7 @@ Known values: Python 3.14a1 3605 (Move ENTER_EXECUTOR to opcode 255) Python 3.14a1 3606 (Specialize CALL_KW) Python 3.14a1 3607 (Add pseudo instructions JUMP_IF_TRUE/FALSE) + Python 3.14a1 3608 (Add support for slices) Python 3.15 will start with 3650 @@ -271,7 +272,7 @@ PC/launcher.c must also be updated. */ -#define PYC_MAGIC_NUMBER 3607 +#define PYC_MAGIC_NUMBER 3608 /* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes (little-endian) and then appending b'\r\n'. */ #define PYC_MAGIC_NUMBER_TOKEN \ diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e6dc7a53189e12..6f838da6018741 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1386,6 +1386,14 @@ def check_op_count(func, op, expected): actual += 1 self.assertEqual(actual, expected) + def check_consts(func, typ, expected): + slice_consts = 0 + consts = func.__code__.co_consts + for instr in dis.Bytecode(func): + if instr.opname == "LOAD_CONST" and isinstance(consts[instr.oparg], typ): + slice_consts += 1 + self.assertEqual(slice_consts, expected) + def load(): return x[a:b] + x [a:] + x[:b] + x[:] @@ -1401,15 +1409,30 @@ def long_slice(): def aug(): x[a:b] += y - check_op_count(load, "BINARY_SLICE", 4) + def aug_const(): + x[1:2] += y + + def compound_const_slice(): + x[1:2:3, 4:5:6] = y + + check_op_count(load, "BINARY_SLICE", 3) check_op_count(load, "BUILD_SLICE", 0) - check_op_count(store, "STORE_SLICE", 4) + check_consts(load, slice, 1) + check_op_count(store, "STORE_SLICE", 3) check_op_count(store, "BUILD_SLICE", 0) + check_consts(store, slice, 1) check_op_count(long_slice, "BUILD_SLICE", 1) check_op_count(long_slice, "BINARY_SLICE", 0) check_op_count(aug, "BINARY_SLICE", 1) check_op_count(aug, "STORE_SLICE", 1) check_op_count(aug, "BUILD_SLICE", 0) + check_op_count(aug_const, "BINARY_SLICE", 0) + check_op_count(aug_const, "STORE_SLICE", 0) + check_consts(aug_const, slice, 1) + check_op_count(compound_const_slice, "BINARY_SLICE", 0) + check_op_count(compound_const_slice, "BUILD_SLICE", 0) + check_consts(compound_const_slice, slice, 0) + check_consts(compound_const_slice, tuple, 1) def test_compare_positions(self): for opname_prefix, op in [ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 6f0b3f8b9a3262..8a2f4d32b911d9 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2336,6 +2336,7 @@ _PyCode_ConstantKey(PyObject *op) if (op == Py_None || op == Py_Ellipsis || PyLong_CheckExact(op) || PyUnicode_CheckExact(op) + || PySlice_Check(op) /* code_richcompare() uses _PyCode_ConstantKey() internally */ || PyCode_Check(op)) { diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 1b6d35998c2b69..4fef0af93fe095 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -343,7 +343,7 @@ Create a slice object. This is used for extended slicing (e.g. a[0:10:2])."); static void slice_dealloc(PySliceObject *r) { - _PyObject_GC_UNTRACK(r); + PyObject_GC_UnTrack(r); Py_DECREF(r->step); Py_DECREF(r->start); Py_DECREF(r->stop); diff --git a/Python/codegen.c b/Python/codegen.c index 896c30cc14952a..689d2b5124e9d3 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -194,6 +194,7 @@ static int codegen_visit_expr(compiler *, expr_ty); static int codegen_augassign(compiler *, stmt_ty); static int codegen_annassign(compiler *, stmt_ty); static int codegen_subscript(compiler *, expr_ty); +static int codegen_slice_two_parts(compiler *, expr_ty); static int codegen_slice(compiler *, expr_ty); static bool are_all_items_const(asdl_expr_seq *, Py_ssize_t, Py_ssize_t); @@ -5005,12 +5006,8 @@ codegen_visit_expr(compiler *c, expr_ty e) } break; case Slice_kind: - { - int n = codegen_slice(c, e); - RETURN_IF_ERROR(n); - ADDOP_I(c, loc, BUILD_SLICE, n); + RETURN_IF_ERROR(codegen_slice(c, e)); break; - } case Name_kind: return codegen_nameop(c, loc, e->v.Name.id, e->v.Name.ctx); /* child nodes of List and Tuple will have expr_context set */ @@ -5023,9 +5020,22 @@ codegen_visit_expr(compiler *c, expr_ty e) } static bool -is_two_element_slice(expr_ty s) +is_constant_slice(expr_ty s) { return s->kind == Slice_kind && + (s->v.Slice.lower == NULL || + s->v.Slice.lower->kind == Constant_kind) && + (s->v.Slice.upper == NULL || + s->v.Slice.upper->kind == Constant_kind) && + (s->v.Slice.step == NULL || + s->v.Slice.step->kind == Constant_kind); +} + +static bool +should_apply_two_element_slice_optimization(expr_ty s) +{ + return !is_constant_slice(s) && + s->kind == Slice_kind && s->v.Slice.step == NULL; } @@ -5046,8 +5056,8 @@ codegen_augassign(compiler *c, stmt_ty s) break; case Subscript_kind: VISIT(c, expr, e->v.Subscript.value); - if (is_two_element_slice(e->v.Subscript.slice)) { - RETURN_IF_ERROR(codegen_slice(c, e->v.Subscript.slice)); + if (should_apply_two_element_slice_optimization(e->v.Subscript.slice)) { + RETURN_IF_ERROR(codegen_slice_two_parts(c, e->v.Subscript.slice)); ADDOP_I(c, loc, COPY, 3); ADDOP_I(c, loc, COPY, 3); ADDOP_I(c, loc, COPY, 3); @@ -5084,7 +5094,7 @@ codegen_augassign(compiler *c, stmt_ty s) ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: - if (is_two_element_slice(e->v.Subscript.slice)) { + if (should_apply_two_element_slice_optimization(e->v.Subscript.slice)) { ADDOP_I(c, loc, SWAP, 4); ADDOP_I(c, loc, SWAP, 3); ADDOP_I(c, loc, SWAP, 2); @@ -5231,8 +5241,10 @@ codegen_subscript(compiler *c, expr_ty e) } VISIT(c, expr, e->v.Subscript.value); - if (is_two_element_slice(e->v.Subscript.slice) && ctx != Del) { - RETURN_IF_ERROR(codegen_slice(c, e->v.Subscript.slice)); + if (should_apply_two_element_slice_optimization(e->v.Subscript.slice) && + ctx != Del + ) { + RETURN_IF_ERROR(codegen_slice_two_parts(c, e->v.Subscript.slice)); if (ctx == Load) { ADDOP(c, loc, BINARY_SLICE); } @@ -5254,15 +5266,9 @@ codegen_subscript(compiler *c, expr_ty e) return SUCCESS; } -/* Returns the number of the values emitted, - * thus are needed to build the slice, or -1 if there is an error. */ static int -codegen_slice(compiler *c, expr_ty s) +codegen_slice_two_parts(compiler *c, expr_ty s) { - int n = 2; - assert(s->kind == Slice_kind); - - /* only handles the cases where BUILD_SLICE is emitted */ if (s->v.Slice.lower) { VISIT(c, expr, s->v.Slice.lower); } @@ -5277,11 +5283,45 @@ codegen_slice(compiler *c, expr_ty s) ADDOP_LOAD_CONST(c, LOC(s), Py_None); } + return 0; +} + +static int +codegen_slice(compiler *c, expr_ty s) +{ + int n = 2; + assert(s->kind == Slice_kind); + + if (is_constant_slice(s)) { + PyObject *start = NULL; + if (s->v.Slice.lower) { + start = s->v.Slice.lower->v.Constant.value; + } + PyObject *stop = NULL; + if (s->v.Slice.upper) { + stop = s->v.Slice.upper->v.Constant.value; + } + PyObject *step = NULL; + if (s->v.Slice.step) { + step = s->v.Slice.step->v.Constant.value; + } + PyObject *slice = PySlice_New(start, stop, step); + if (slice == NULL) { + return ERROR; + } + ADDOP_LOAD_CONST_NEW(c, LOC(s), slice); + return SUCCESS; + } + + RETURN_IF_ERROR(codegen_slice_two_parts(c, s)); + if (s->v.Slice.step) { n++; VISIT(c, expr, s->v.Slice.step); } - return n; + + ADDOP_I(c, LOC(s), BUILD_SLICE, n); + return SUCCESS; } diff --git a/Python/marshal.c b/Python/marshal.c index b1708a7306f9e7..3d127b4e331d0d 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -76,6 +76,7 @@ module marshal #define TYPE_UNKNOWN '?' #define TYPE_SET '<' #define TYPE_FROZENSET '>' +#define TYPE_SLICE ':' #define FLAG_REF '\x80' /* with a type, add obj to index */ #define TYPE_ASCII 'a' @@ -613,6 +614,13 @@ w_complex_object(PyObject *v, char flag, WFILE *p) w_pstring(view.buf, view.len, p); PyBuffer_Release(&view); } + else if (PySlice_Check(v)) { + PySliceObject *slice = (PySliceObject *)v; + W_TYPE(TYPE_SLICE, p); + w_object(slice->start, p); + w_object(slice->stop, p); + w_object(slice->step, p); + } else { W_TYPE(TYPE_UNKNOWN, p); p->error = WFERR_UNMARSHALLABLE; @@ -1534,6 +1542,32 @@ r_object(RFILE *p) retval = Py_NewRef(v); break; + case TYPE_SLICE: + { + Py_ssize_t idx = r_ref_reserve(flag, p); + PyObject *stop = NULL; + PyObject *step = NULL; + PyObject *start = r_object(p); + if (start == NULL) { + goto cleanup; + } + stop = r_object(p); + if (stop == NULL) { + goto cleanup; + } + step = r_object(p); + if (step == NULL) { + goto cleanup; + } + retval = PySlice_New(start, stop, step); + r_ref_insert(retval, idx, flag, p); + cleanup: + Py_XDECREF(start); + Py_XDECREF(stop); + Py_XDECREF(step); + break; + } + default: /* Bogus data got written, which isn't ideal. This will let you keep working and recover. */ From 760b1e103a0aa696cdf448e0d500cd1bac2213fa Mon Sep 17 00:00:00 2001 From: spacemanspiff2007 <10754716+spacemanspiff2007@users.noreply.github.com> Date: Tue, 8 Oct 2024 20:17:53 +0200 Subject: [PATCH 059/247] gh-124832: Add a note to indicate that `datetime.now` may return the same instant (#124834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update datetime.rst * Update datetime.rst replace warning with note * Update Doc/library/datetime.rst Co-authored-by: Victor Stinner * Update Doc/library/datetime.rst Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --------- Co-authored-by: Victor Stinner Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/datetime.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 64510a77c67c11..f0b465bc9ce39c 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -948,6 +948,10 @@ Other constructors, all class methods: This function is preferred over :meth:`today` and :meth:`utcnow`. + .. note:: + + Subsequent calls to :meth:`!datetime.now` may return the same + instant depending on the precision of the underlying clock. .. classmethod:: datetime.utcnow() From b2a7272408593355c4c8e1d2ce9018cf96691bea Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 8 Oct 2024 14:02:58 -0500 Subject: [PATCH 060/247] Misc improvements to the itertools docs (gh-125147) --- Doc/library/itertools.rst | 136 +++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 39 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 9a62249816c9bf..c138e903fa5a0f 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -134,7 +134,7 @@ loops that truncate the stream. To compute a running minimum, set *function* to :func:`min`. For a running maximum, set *function* to :func:`max`. Or for a running product, set *function* to :func:`operator.mul`. - To build an `Amortization table + To build an `amortization table `_, accumulate the interest and apply payments: @@ -736,6 +736,26 @@ loops that truncate the stream. allows nested :func:`tee` calls to share the same underlying data chain and to have a single update step rather than a chain of calls. + The flattening property makes tee iterators efficiently peekable: + + .. testcode:: + + def lookahead(tee_iterator): + "Return the next value without moving the input forward" + [forked_iterator] = tee(tee_iterator, 1) + return next(forked_iterator) + + .. doctest:: + + >>> iterator = iter('abcdef') + >>> [iterator] = tee(iterator, 1) # Make the input peekable + >>> next(iterator) # Move the iterator forward + 'a' + >>> lookahead(iterator) # Check next value + 'b' + >>> next(iterator) # Continue moving forward + 'b' + ``tee`` iterators are not threadsafe. A :exc:`RuntimeError` may be raised when simultaneously using iterators returned by the same :func:`tee` call, even if the original *iterable* is threadsafe. @@ -952,15 +972,6 @@ and :term:`generators ` which incur interpreter overhead. iterators = cycle(islice(iterators, num_active)) yield from map(next, iterators) - def partition(predicate, iterable): - """Partition entries into false entries and true entries. - - If *predicate* is slow, consider wrapping it with functools.lru_cache(). - """ - # partition(is_odd, range(10)) → 0 2 4 6 8 and 1 3 5 7 9 - t1, t2 = tee(iterable) - return filterfalse(predicate, t1), filter(predicate, t2) - def subslices(seq): "Return all contiguous non-empty subslices of a sequence." # subslices('ABCD') → A AB ABC ABCD B BC BCD C CD D @@ -1178,15 +1189,19 @@ The following recipes have a more mathematical flavor: >>> list(it) ['d', 'e', 'f'] + >>> list(prepend(1, [2, 3, 4])) [1, 2, 3, 4] + >>> list(enumerate('abc')) [(0, 'a'), (1, 'b'), (2, 'c')] + >>> list(islice(tabulate(lambda x: 2*x), 4)) [0, 2, 4, 6] + >>> list(tail(3, 'ABCDEFG')) ['E', 'F', 'G'] >>> # Verify the input is consumed greedily @@ -1195,6 +1210,7 @@ The following recipes have a more mathematical flavor: >>> list(input_iterator) [] + >>> it = iter(range(10)) >>> consume(it, 3) >>> # Verify the input is consumed lazily @@ -1205,6 +1221,7 @@ The following recipes have a more mathematical flavor: >>> next(it, 'Done') 'Done' + >>> nth('abcde', 3) 'd' >>> nth('abcde', 9) is None @@ -1216,6 +1233,7 @@ The following recipes have a more mathematical flavor: >>> list(it) ['d', 'e'] + >>> [all_equal(s) for s in ('', 'A', 'AAAA', 'AAAB', 'AAABA')] [True, True, True, False, False] >>> [all_equal(s, key=str.casefold) for s in ('', 'A', 'AaAa', 'AAAB', 'AAABA')] @@ -1229,24 +1247,19 @@ The following recipes have a more mathematical flavor: >>> ''.join(it) 'bbccc' + >>> quantify(range(99), lambda x: x%2==0) 50 - >>> quantify([True, False, False, True, True]) 3 - >>> quantify(range(12), predicate=lambda x: x%2==1) 6 + >>> a = [[1, 2, 3], [4, 5, 6]] >>> list(flatten(a)) [1, 2, 3, 4, 5, 6] - >>> list(repeatfunc(pow, 5, 2, 3)) - [8, 8, 8, 8, 8] - - >>> take(5, map(int, repeatfunc(random.random))) - [0, 0, 0, 0, 0] >>> list(ncycles('abc', 3)) ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c'] @@ -1256,9 +1269,11 @@ The following recipes have a more mathematical flavor: >>> list(input_iterator) [] + >>> sum_of_squares([10, 20, 30]) 1400 + >>> list(reshape([(0, 1), (2, 3), (4, 5)], 3)) [(0, 1, 2), (3, 4, 5)] >>> M = [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)] @@ -1279,6 +1294,7 @@ The following recipes have a more mathematical flavor: >>> list(reshape(M, 12)) [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)] + >>> list(transpose([(1, 2, 3), (11, 22, 33)])) [(1, 11), (2, 22), (3, 33)] >>> # Verify that the inputs are consumed lazily @@ -1290,11 +1306,13 @@ The following recipes have a more mathematical flavor: >>> list(zip(input1, input2)) [(2, 22), (3, 33)] + >>> list(matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]])) [(49, 80), (41, 60)] >>> list(matmul([[2, 5], [7, 9], [3, 4]], [[7, 11, 5, 4, 9], [3, 5, 2, 6, 3]])) [(29, 47, 20, 38, 33), (76, 122, 53, 82, 90), (33, 53, 23, 36, 39)] + >>> list(convolve([1, -1, -20], [1, -3])) == [1, -4, -17, 60] True >>> data = [20, 40, 24, 32, 20, 28, 16] @@ -1317,6 +1335,7 @@ The following recipes have a more mathematical flavor: >>> list(signal_iterator) [30, 40, 50] + >>> from fractions import Fraction >>> from decimal import Decimal >>> polynomial_eval([1, -4, -17, 60], x=5) @@ -1348,6 +1367,7 @@ The following recipes have a more mathematical flavor: >>> polynomial_eval([11, 2], 7) == 11 * 7 + 2 True + >>> polynomial_from_roots([5, -4, 3]) [1, -4, -17, 60] >>> factored = lambda x: (x - 5) * (x + 4) * (x - 3) @@ -1355,9 +1375,11 @@ The following recipes have a more mathematical flavor: >>> all(factored(x) == expanded(x) for x in range(-10, 11)) True + >>> polynomial_derivative([1, -4, -17, 60]) [3, -8, -17] + >>> list(iter_index('AABCADEAF', 'A')) [0, 1, 4, 7] >>> list(iter_index('AABCADEAF', 'B')) @@ -1415,12 +1437,14 @@ The following recipes have a more mathematical flavor: >>> ''.join(input_iterator) 'DEAF' + >>> # Verify that the target value can be a sequence. >>> seq = [[10, 20], [30, 40], 30, 40, [30, 40], 50] >>> target = [30, 40] >>> list(iter_index(seq, target)) [1, 4] + >>> # Verify faithfulness to type specific index() method behaviors. >>> # For example, bytes and str perform continuous-subsequence searches >>> # that do not match the general behavior specified @@ -1450,6 +1474,7 @@ The following recipes have a more mathematical flavor: >>> set(sieve(10_000)).isdisjoint(carmichael) True + >>> list(factor(99)) # Code example 1 [3, 3, 11] >>> list(factor(1_000_000_000_000_007)) # Code example 2 @@ -1495,6 +1520,7 @@ The following recipes have a more mathematical flavor: >>> all(list(factor(n)) == sorted(factor(n)) for n in range(2_000)) True + >>> totient(0) # https://www.wolframalpha.com/input?i=totient+0 0 >>> first_totients = [1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, @@ -1514,9 +1540,15 @@ The following recipes have a more mathematical flavor: >>> totient(6 ** 20) == 1 * 2**19 * 2 * 3**19 # repeated primes True + >>> list(flatten([('a', 'b'), (), ('c', 'd', 'e'), ('f',), ('g', 'h', 'i')])) ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] + + >>> list(repeatfunc(pow, 5, 2, 3)) + [8, 8, 8, 8, 8] + >>> take(5, map(int, repeatfunc(random.random))) + [0, 0, 0, 0, 0] >>> random.seed(85753098575309) >>> list(repeatfunc(random.random, 3)) [0.16370491282496968, 0.45889608687313455, 0.3747076837820118] @@ -1525,9 +1557,11 @@ The following recipes have a more mathematical flavor: >>> list(repeatfunc(pow, 3, 2, 5)) [32, 32, 32] + >>> list(grouper('abcdefg', 3, fillvalue='x')) [('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'x', 'x')] + >>> it = grouper('abcdefg', 3, incomplete='strict') >>> next(it) ('a', 'b', 'c') @@ -1541,6 +1575,7 @@ The following recipes have a more mathematical flavor: >>> list(grouper('abcdefg', n=3, incomplete='ignore')) [('a', 'b', 'c'), ('d', 'e', 'f')] + >>> list(sliding_window('ABCDEFG', 1)) [('A',), ('B',), ('C',), ('D',), ('E',), ('F',), ('G',)] >>> list(sliding_window('ABCDEFG', 2)) @@ -1570,6 +1605,7 @@ The following recipes have a more mathematical flavor: ... 'zero or negative n not supported' + >>> list(roundrobin('abc', 'd', 'ef')) ['a', 'd', 'e', 'b', 'f', 'c'] >>> ranges = [range(5, 1000), range(4, 3000), range(0), range(3, 2000), range(2, 5000), range(1, 3500)] @@ -1583,38 +1619,19 @@ The following recipes have a more mathematical flavor: >>> ''.join(chain(*input_iterators)) 'dijkopqr' - >>> def is_odd(x): - ... return x % 2 == 1 - - >>> evens, odds = partition(is_odd, range(10)) - >>> list(evens) - [0, 2, 4, 6, 8] - >>> list(odds) - [1, 3, 5, 7, 9] - >>> # Verify that the input is consumed lazily - >>> input_iterator = iter(range(10)) - >>> evens, odds = partition(is_odd, input_iterator) - >>> next(odds) - 1 - >>> next(odds) - 3 - >>> next(evens) - 0 - >>> list(input_iterator) - [4, 5, 6, 7, 8, 9] >>> list(subslices('ABCD')) ['A', 'AB', 'ABC', 'ABCD', 'B', 'BC', 'BCD', 'C', 'CD', 'D'] + >>> list(powerset([1,2,3])) [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)] - >>> all(len(list(powerset(range(n)))) == 2**n for n in range(18)) True - >>> list(powerset('abcde')) == sorted(sorted(set(powerset('abcde'))), key=len) True + >>> list(unique_everseen('AAAABBBCCDAABBB')) ['A', 'B', 'C', 'D'] >>> list(unique_everseen('ABBCcAD', str.casefold)) @@ -1629,6 +1646,7 @@ The following recipes have a more mathematical flavor: >>> ''.join(input_iterator) 'AAABBBCCDAABBB' + >>> list(unique_justseen('AAAABBBCCDAABBB')) ['A', 'B', 'C', 'D', 'A', 'B'] >>> list(unique_justseen('ABBCcAD', str.casefold)) @@ -1643,6 +1661,7 @@ The following recipes have a more mathematical flavor: >>> ''.join(input_iterator) 'AAABBBCCDAABBB' + >>> list(unique([[1, 2], [3, 4], [1, 2]])) [[1, 2], [3, 4]] >>> list(unique('ABBcCAD', str.casefold)) @@ -1650,6 +1669,7 @@ The following recipes have a more mathematical flavor: >>> list(unique('ABBcCAD', str.casefold, reverse=True)) ['D', 'c', 'B', 'A'] + >>> d = dict(a=1, b=2, c=3) >>> it = iter_except(d.popitem, KeyError) >>> d['d'] = 4 @@ -1667,6 +1687,7 @@ The following recipes have a more mathematical flavor: >>> next(it, 'empty') 'empty' + >>> first_true('ABC0DEF1', '9', str.isdigit) '0' >>> # Verify that inputs are consumed lazily @@ -1747,21 +1768,36 @@ The following recipes have a more mathematical flavor: return true_iterator(), chain(transition, it) + def partition(predicate, iterable): + """Partition entries into false entries and true entries. + + If *predicate* is slow, consider wrapping it with functools.lru_cache(). + """ + # partition(is_odd, range(10)) → 0 2 4 6 8 and 1 3 5 7 9 + t1, t2 = tee(iterable) + return filterfalse(predicate, t1), filter(predicate, t2) + + + .. doctest:: :hide: >>> dotproduct([1,2,3], [4,5,6]) 32 + >>> sumprod([1,2,3], [4,5,6]) 32 + >>> list(islice(pad_none('abc'), 0, 6)) ['a', 'b', 'c', None, None, None] + >>> list(triplewise('ABCDEFG')) [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')] + >>> population = 'ABCDEFGH' >>> for r in range(len(population) + 1): ... seq = list(combinations(population, r)) @@ -1769,16 +1805,38 @@ The following recipes have a more mathematical flavor: ... assert nth_combination(population, r, i) == seq[i] ... for i in range(-len(seq), 0): ... assert nth_combination(population, r, i) == seq[i] - + ... >>> iterable = 'abcde' >>> r = 3 >>> combos = list(combinations(iterable, r)) >>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos)) True + >>> it = iter('ABCdEfGhI') >>> all_upper, remainder = before_and_after(str.isupper, it) >>> ''.join(all_upper) 'ABC' >>> ''.join(remainder) 'dEfGhI' + + + >>> def is_odd(x): + ... return x % 2 == 1 + ... + >>> evens, odds = partition(is_odd, range(10)) + >>> list(evens) + [0, 2, 4, 6, 8] + >>> list(odds) + [1, 3, 5, 7, 9] + >>> # Verify that the input is consumed lazily + >>> input_iterator = iter(range(10)) + >>> evens, odds = partition(is_odd, input_iterator) + >>> next(odds) + 1 + >>> next(odds) + 3 + >>> next(evens) + 0 + >>> list(input_iterator) + [4, 5, 6, 7, 8, 9] From eafd14fbe0fd464b9d700f6d00137415193aa143 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 8 Oct 2024 22:36:03 +0300 Subject: [PATCH 061/247] gh-116110: remove extra processing for the __signature__ attribute (GH-116234) This is an alternative to GH-100168. --- Lib/enum.py | 22 +++++++++---- Lib/inspect.py | 10 +----- Lib/test/test_inspect/test_inspect.py | 32 ------------------- ...-02-27-10-22-15.gh-issue-115937.0cVNur.rst | 3 ++ 4 files changed, 19 insertions(+), 48 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst diff --git a/Lib/enum.py b/Lib/enum.py index 9d53eb86bc2116..17d72738792982 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1092,6 +1092,21 @@ def _add_member_(cls, name, member): # now add to _member_map_ (even aliases) cls._member_map_[name] = member + @property + def __signature__(cls): + from inspect import Parameter, Signature + if cls._member_names_: + return Signature([Parameter('values', Parameter.VAR_POSITIONAL)]) + else: + return Signature([Parameter('new_class_name', Parameter.POSITIONAL_ONLY), + Parameter('names', Parameter.POSITIONAL_OR_KEYWORD), + Parameter('module', Parameter.KEYWORD_ONLY, default=None), + Parameter('qualname', Parameter.KEYWORD_ONLY, default=None), + Parameter('type', Parameter.KEYWORD_ONLY, default=None), + Parameter('start', Parameter.KEYWORD_ONLY, default=1), + Parameter('boundary', Parameter.KEYWORD_ONLY, default=None)]) + + EnumMeta = EnumType # keep EnumMeta name for backwards compatibility @@ -1135,13 +1150,6 @@ class Enum(metaclass=EnumType): attributes -- see the documentation for details. """ - @classmethod - def __signature__(cls): - if cls._member_names_: - return '(*values)' - else: - return '(new_class_name, /, names, *, module=None, qualname=None, type=None, start=1, boundary=None)' - def __new__(cls, value): # all enum instances are actually created during class construction # without calling this method; this method is called by the metaclass' diff --git a/Lib/inspect.py b/Lib/inspect.py index 17314564f35397..1763ef640bbe04 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2424,18 +2424,10 @@ def _signature_from_callable(obj, *, pass else: if sig is not None: - # since __text_signature__ is not writable on classes, __signature__ - # may contain text (or be a callable that returns text); - # if so, convert it - o_sig = sig - if not isinstance(sig, (Signature, str)) and callable(sig): - sig = sig() - if isinstance(sig, str): - sig = _signature_fromstr(sigcls, obj, sig) if not isinstance(sig, Signature): raise TypeError( 'unexpected object {!r} in __signature__ ' - 'attribute'.format(o_sig)) + 'attribute'.format(sig)) return sig try: diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index d2dc9e147d29c2..2ecb7ec1e26e0e 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -4879,38 +4879,6 @@ def foo(): pass self.assertEqual(signature_func(foo), inspect.Signature()) self.assertEqual(inspect.get_annotations(foo), {}) - def test_signature_as_str(self): - self.maxDiff = None - class S: - __signature__ = '(a, b=2)' - - self.assertEqual(self.signature(S), - ((('a', ..., ..., 'positional_or_keyword'), - ('b', 2, ..., 'positional_or_keyword')), - ...)) - - def test_signature_as_callable(self): - # __signature__ should be either a staticmethod or a bound classmethod - class S: - @classmethod - def __signature__(cls): - return '(a, b=2)' - - self.assertEqual(self.signature(S), - ((('a', ..., ..., 'positional_or_keyword'), - ('b', 2, ..., 'positional_or_keyword')), - ...)) - - class S: - @staticmethod - def __signature__(): - return '(a, b=2)' - - self.assertEqual(self.signature(S), - ((('a', ..., ..., 'positional_or_keyword'), - ('b', 2, ..., 'positional_or_keyword')), - ...)) - def test_signature_on_derived_classes(self): # gh-105080: Make sure that signatures are consistent on derived classes diff --git a/Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst b/Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst new file mode 100644 index 00000000000000..f9dae0c9b8e2b2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst @@ -0,0 +1,3 @@ +Removed extra preprocessing for the ``__signature__`` attribute: the code +just check if it's a :class:`inspect.Signature` instance. Patch by Sergey B +Kirpichev. From 37228bd16e3ef97d32da08848552f7ef016d68ab Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 8 Oct 2024 15:07:29 -0700 Subject: [PATCH 062/247] GH-124478: Cleanup argparse documentation (#124877) Co-authored-by: Jelle Zijlstra Co-authored-by: Tomas R --- Doc/howto/argparse-optparse.rst | 55 +++ Doc/library/argparse.rst | 576 ++++++++------------------------ 2 files changed, 196 insertions(+), 435 deletions(-) create mode 100644 Doc/howto/argparse-optparse.rst diff --git a/Doc/howto/argparse-optparse.rst b/Doc/howto/argparse-optparse.rst new file mode 100644 index 00000000000000..cef2d893b28a62 --- /dev/null +++ b/Doc/howto/argparse-optparse.rst @@ -0,0 +1,55 @@ +.. currentmodule:: argparse + +.. _upgrading-optparse-code: + +========================== +Upgrading optparse code +========================== + +Originally, the :mod:`argparse` module had attempted to maintain compatibility +with :mod:`optparse`. However, :mod:`optparse` was difficult to extend +transparently, particularly with the changes required to support +``nargs=`` specifiers and better usage messages. When most everything in +:mod:`optparse` had either been copy-pasted over or monkey-patched, it no +longer seemed practical to try to maintain the backwards compatibility. + +The :mod:`argparse` module improves on the :mod:`optparse` +module in a number of ways including: + +* Handling positional arguments. +* Supporting subcommands. +* Allowing alternative option prefixes like ``+`` and ``/``. +* Handling zero-or-more and one-or-more style arguments. +* Producing more informative usage messages. +* Providing a much simpler interface for custom ``type`` and ``action``. + +A partial upgrade path from :mod:`optparse` to :mod:`argparse`: + +* Replace all :meth:`optparse.OptionParser.add_option` calls with + :meth:`ArgumentParser.add_argument` calls. + +* Replace ``(options, args) = parser.parse_args()`` with ``args = + parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` + calls for the positional arguments. Keep in mind that what was previously + called ``options``, now in the :mod:`argparse` context is called ``args``. + +* Replace :meth:`optparse.OptionParser.disable_interspersed_args` + by using :meth:`~ArgumentParser.parse_intermixed_args` instead of + :meth:`~ArgumentParser.parse_args`. + +* Replace callback actions and the ``callback_*`` keyword arguments with + ``type`` or ``action`` arguments. + +* Replace string names for ``type`` keyword arguments with the corresponding + type objects (e.g. int, float, complex, etc). + +* Replace :class:`optparse.Values` with :class:`Namespace` and + :exc:`optparse.OptionError` and :exc:`optparse.OptionValueError` with + :exc:`ArgumentError`. + +* Replace strings with implicit arguments such as ``%default`` or ``%prog`` with + the standard Python syntax to use dictionaries to format strings, that is, + ``%(default)s`` and ``%(prog)s``. + +* Replace the OptionParser constructor ``version`` argument with a call to + ``parser.add_argument('--version', action='version', version='')``. diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 83d0a9ed7b1d0a..e9a08984f77c3a 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1,4 +1,4 @@ -:mod:`!argparse` --- Parser for command-line options, arguments and sub-commands +:mod:`!argparse` --- Parser for command-line options, arguments and subcommands ================================================================================ .. module:: argparse @@ -19,36 +19,13 @@ introduction to Python command-line parsing, have a look at the :ref:`argparse tutorial `. -The :mod:`argparse` module makes it easy to write user-friendly command-line -interfaces. The program defines what arguments it requires, and :mod:`argparse` -will figure out how to parse those out of :data:`sys.argv`. The :mod:`argparse` +The :mod:`!argparse` module makes it easy to write user-friendly command-line +interfaces. The program defines what arguments it requires, and :mod:`!argparse` +will figure out how to parse those out of :data:`sys.argv`. The :mod:`!argparse` module also automatically generates help and usage messages. The module will also issue errors when users give the program invalid arguments. -Quick Links for ArgumentParser ---------------------------------------- -========================= =========================================================================================================== ================================================================================== -Name Description Values -========================= =========================================================================================================== ================================================================================== -prog_ The name of the program -usage_ The string describing the program usage -description_ A brief description of what the program does -epilog_ Additional description of the program after the argument help -parents_ A list of :class:`ArgumentParser` objects whose arguments should also be included -formatter_class_ A class for customizing the help output ``argparse.HelpFormatter`` -prefix_chars_ The set of characters that prefix optional arguments Defaults to ``'-'`` -fromfile_prefix_chars_ The set of characters that prefix files to read additional arguments from Defaults to ``None`` (meaning arguments will never be treated as file references) -argument_default_ The global default value for arguments -allow_abbrev_ Allows long options to be abbreviated if the abbreviation is unambiguous ``True`` or ``False`` (default: ``True``) -conflict_handler_ The strategy for resolving conflicting optionals -add_help_ Add a ``-h/--help`` option to the parser ``True`` or ``False`` (default: ``True``) -exit_on_error_ Determines whether or not to exit with error info when an error occurs ``True`` or ``False`` (default: ``True``) -========================= =========================================================================================================== ================================================================================== - -Core Functionality ------------------- - -The :mod:`argparse` module's support for command-line interfaces is built +The :mod:`!argparse` module's support for command-line interfaces is built around an instance of :class:`argparse.ArgumentParser`. It is a container for argument specifications and has options that apply to the parser as whole:: @@ -72,133 +49,9 @@ the extracted data in a :class:`argparse.Namespace` object:: args = parser.parse_args() print(args.filename, args.count, args.verbose) - -Quick Links for add_argument() ------------------------------- - -============================ =========================================================== ========================================================================================================================== -Name Description Values -============================ =========================================================== ========================================================================================================================== -action_ Specify how an argument should be handled ``'store'``, ``'store_const'``, ``'store_true'``, ``'append'``, ``'append_const'``, ``'count'``, ``'help'``, ``'version'`` -choices_ Limit values to a specific set of choices ``['foo', 'bar']``, ``range(1, 10)``, or :class:`~collections.abc.Container` instance -const_ Store a constant value -default_ Default value used when an argument is not provided Defaults to ``None`` -dest_ Specify the attribute name used in the result namespace -help_ Help message for an argument -metavar_ Alternate display name for the argument as shown in help -nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, or ``'+'`` -required_ Indicate whether an argument is required or optional ``True`` or ``False`` -:ref:`type ` Automatically convert an argument to the given type :class:`int`, :class:`float`, ``argparse.FileType('w')``, or callable function -============================ =========================================================== ========================================================================================================================== - - -Example -------- - -The following code is a Python program that takes a list of integers and -produces either the sum or the max:: - - import argparse - - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('integers', metavar='N', type=int, nargs='+', - help='an integer for the accumulator') - parser.add_argument('--sum', dest='accumulate', action='store_const', - const=sum, default=max, - help='sum the integers (default: find the max)') - - args = parser.parse_args() - print(args.accumulate(args.integers)) - -Assuming the above Python code is saved into a file called ``prog.py``, it can -be run at the command line and it provides useful help messages: - -.. code-block:: shell-session - - $ python prog.py -h - usage: prog.py [-h] [--sum] N [N ...] - - Process some integers. - - positional arguments: - N an integer for the accumulator - - options: - -h, --help show this help message and exit - --sum sum the integers (default: find the max) - -When run with the appropriate arguments, it prints either the sum or the max of -the command-line integers: - -.. code-block:: shell-session - - $ python prog.py 1 2 3 4 - 4 - - $ python prog.py 1 2 3 4 --sum - 10 - -If invalid arguments are passed in, an error will be displayed: - -.. code-block:: shell-session - - $ python prog.py a b c - usage: prog.py [-h] [--sum] N [N ...] - prog.py: error: argument N: invalid int value: 'a' - -The following sections walk you through this example. - - -Creating a parser -^^^^^^^^^^^^^^^^^ - -The first step in using the :mod:`argparse` is creating an -:class:`ArgumentParser` object:: - - >>> parser = argparse.ArgumentParser(description='Process some integers.') - -The :class:`ArgumentParser` object will hold all the information necessary to -parse the command line into Python data types. - - -Adding arguments -^^^^^^^^^^^^^^^^ - -Filling an :class:`ArgumentParser` with information about program arguments is -done by making calls to the :meth:`~ArgumentParser.add_argument` method. -Generally, these calls tell the :class:`ArgumentParser` how to take the strings -on the command line and turn them into objects. This information is stored and -used when :meth:`~ArgumentParser.parse_args` is called. For example:: - - >>> parser.add_argument('integers', metavar='N', type=int, nargs='+', - ... help='an integer for the accumulator') - >>> parser.add_argument('--sum', dest='accumulate', action='store_const', - ... const=sum, default=max, - ... help='sum the integers (default: find the max)') - -Later, calling :meth:`~ArgumentParser.parse_args` will return an object with -two attributes, ``integers`` and ``accumulate``. The ``integers`` attribute -will be a list of one or more integers, and the ``accumulate`` attribute will be -either the :func:`sum` function, if ``--sum`` was specified at the command line, -or the :func:`max` function if it was not. - - -Parsing arguments -^^^^^^^^^^^^^^^^^ - -:class:`ArgumentParser` parses arguments through the -:meth:`~ArgumentParser.parse_args` method. This will inspect the command line, -convert each argument to the appropriate type and then invoke the appropriate action. -In most cases, this means a simple :class:`Namespace` object will be built up from -attributes parsed out of the command line:: - - >>> parser.parse_args(['--sum', '7', '-1', '42']) - Namespace(accumulate=, integers=[7, -1, 42]) - -In a script, :meth:`~ArgumentParser.parse_args` will typically be called with no -arguments, and the :class:`ArgumentParser` will automatically determine the -command-line arguments from :data:`sys.argv`. - +.. note:: + If you're looking a guide about how to upgrade optparse code + to argparse, see :ref:`Upgrading Optparse Code `. ArgumentParser objects ---------------------- @@ -268,8 +121,9 @@ The following sections describe how each of these are used. prog ^^^^ + By default, :class:`ArgumentParser` calculates the name of the program -to display in help messages depending on the way the Python inerpreter was run: +to display in help messages depending on the way the Python interpreter was run: * The :func:`base name ` of ``sys.argv[0]`` if a file was passed as argument. @@ -278,48 +132,10 @@ to display in help messages depending on the way the Python inerpreter was run: * The Python interpreter name followed by ``-m`` followed by the module or package name if the :option:`-m` option was used. -This default is almost -always desirable because it will make the help messages match the string that was -used to invoke the program on the command line. For example, consider a file -named ``myprogram.py`` with the following code:: - - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('--foo', help='foo help') - args = parser.parse_args() - -The help for this program will display ``myprogram.py`` as the program name -(regardless of where the program was invoked from) if it is run as a script: - -.. code-block:: shell-session - - $ python myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] - - options: - -h, --help show this help message and exit - --foo FOO foo help - $ cd .. - $ python subdir/myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] - - options: - -h, --help show this help message and exit - --foo FOO foo help - -If it is executed via the :option:`-m` option, the help will display a corresponding command line: - -.. code-block:: shell-session - - $ /usr/bin/python3 -m subdir.myprogram --help - usage: python3 -m subdir.myprogram [-h] [--foo FOO] - - options: - -h, --help show this help message and exit - --foo FOO foo help - -To change this default behavior, another value can be supplied using the -``prog=`` argument to :class:`ArgumentParser`:: +This default is almost always desirable because it will make the help messages +match the string that was used to invoke the program on the command line. +However, to change this default behavior, another value can be supplied using +the ``prog=`` argument to :class:`ArgumentParser`:: >>> parser = argparse.ArgumentParser(prog='myprogram') >>> parser.print_help() @@ -352,22 +168,8 @@ usage ^^^^^ By default, :class:`ArgumentParser` calculates the usage message from the -arguments it contains:: - - >>> parser = argparse.ArgumentParser(prog='PROG') - >>> parser.add_argument('--foo', nargs='?', help='foo help') - >>> parser.add_argument('bar', nargs='+', help='bar help') - >>> parser.print_help() - usage: PROG [-h] [--foo [FOO]] bar [bar ...] - - positional arguments: - bar bar help - - options: - -h, --help show this help message and exit - --foo [FOO] foo help - -The default message can be overridden with the ``usage=`` keyword argument:: +arguments it contains. The default message can be overridden with the +``usage=`` keyword argument:: >>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s [options]') >>> parser.add_argument('--foo', nargs='?', help='foo help') @@ -395,16 +197,7 @@ Most calls to the :class:`ArgumentParser` constructor will use the ``description=`` keyword argument. This argument gives a brief description of what the program does and how it works. In help messages, the description is displayed between the command-line usage string and the help messages for the -various arguments:: - - >>> parser = argparse.ArgumentParser(description='A foo that bars') - >>> parser.print_help() - usage: argparse.py [-h] - - A foo that bars - - options: - -h, --help show this help message and exit +various arguments. By default, the description will be line-wrapped so that it fits within the given space. To change this behavior, see the formatter_class_ argument. @@ -534,7 +327,7 @@ should not be line-wrapped:: -h, --help show this help message and exit :class:`RawTextHelpFormatter` maintains whitespace for all sorts of help text, -including argument descriptions. However, multiple new lines are replaced with +including argument descriptions. However, multiple newlines are replaced with one. If you wish to preserve multiple blank lines, add spaces between the newlines. @@ -628,8 +421,8 @@ arguments will never be treated as file references. .. versionchanged:: 3.12 :class:`ArgumentParser` changed encoding and errors to read arguments files - from default (e.g. :func:`locale.getpreferredencoding(False) ` and - ``"strict"``) to :term:`filesystem encoding and error handler`. + from default (e.g. :func:`locale.getpreferredencoding(False) ` + and ``"strict"``) to the :term:`filesystem encoding and error handler`. Arguments file should be encoded in UTF-8 instead of ANSI Codepage on Windows. @@ -715,25 +508,8 @@ add_help ^^^^^^^^ By default, ArgumentParser objects add an option which simply displays -the parser's help message. For example, consider a file named -``myprogram.py`` containing the following code:: - - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('--foo', help='foo help') - args = parser.parse_args() - -If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser -help will be printed: - -.. code-block:: shell-session - - $ python myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] - - options: - -h, --help show this help message and exit - --foo FOO foo help +the parser's help message. If ``-h`` or ``--help`` is supplied at the command +line, the ArgumentParser help will be printed. Occasionally, it may be useful to disable the addition of this help option. This can be achieved by passing ``False`` as the ``add_help=`` argument to @@ -872,12 +648,7 @@ them, though most actions simply add an attribute to the object returned by how the command-line arguments should be handled. The supplied actions are: * ``'store'`` - This just stores the argument's value. This is the default - action. For example:: - - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> parser.parse_args('--foo 1'.split()) - Namespace(foo='1') + action. * ``'store_const'`` - This stores the value specified by the const_ keyword argument; note that the const_ keyword argument defaults to ``None``. The @@ -892,7 +663,7 @@ how the command-line arguments should be handled. The supplied actions are: * ``'store_true'`` and ``'store_false'`` - These are special cases of ``'store_const'`` used for storing the values ``True`` and ``False`` respectively. In addition, they create default values of ``False`` and - ``True`` respectively. For example:: + ``True`` respectively:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', action='store_true') @@ -1137,7 +908,7 @@ was not present at the command line:: Namespace(foo=42) If the target namespace already has an attribute set, the action *default* -will not over write it:: +will not overwrite it:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', default=42) @@ -1211,7 +982,6 @@ Common built-in types and functions can be used as type converters: parser.add_argument('distance', type=float) parser.add_argument('street', type=ascii) parser.add_argument('code_point', type=ord) - parser.add_argument('source_file', type=open) parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1')) parser.add_argument('datapath', type=pathlib.Path) @@ -1242,10 +1012,11 @@ better reporting than can be given by the ``type`` keyword. A :exc:`FileNotFoundError` exception would not be handled at all. Even :class:`~argparse.FileType` has its limitations for use with the ``type`` -keyword. If one argument uses *FileType* and then a subsequent argument fails, -an error is reported but the file is not automatically closed. In this case, it -would be better to wait until after the parser has run and then use the -:keyword:`with`-statement to manage the files. +keyword. If one argument uses :class:`~argparse.FileType` and then a +subsequent argument fails, an error is reported but the file is not +automatically closed. In this case, it would be better to wait until after +the parser has run and then use the :keyword:`with`-statement to manage the +files. For type checkers that simply check against a fixed set of values, consider using the choices_ keyword instead. @@ -1273,15 +1044,7 @@ if the argument was not one of the acceptable values:: Note that inclusion in the *choices* sequence is checked after any type_ conversions have been performed, so the type of the objects in the *choices* -sequence should match the type_ specified:: - - >>> parser = argparse.ArgumentParser(prog='doors.py') - >>> parser.add_argument('door', type=int, choices=range(1, 4)) - >>> print(parser.parse_args(['3'])) - Namespace(door=3) - >>> parser.parse_args(['4']) - usage: doors.py [-h] {1,2,3} - doors.py: error: argument door: invalid choice: 4 (choose from 1, 2, 3) +sequence should match the type_ specified. Any sequence can be passed as the *choices* value, so :class:`list` objects, :class:`tuple` objects, and custom sequences are all supported. @@ -1331,22 +1094,7 @@ help The ``help`` value is a string containing a brief description of the argument. When a user requests help (usually by using ``-h`` or ``--help`` at the command line), these ``help`` descriptions will be displayed with each -argument:: - - >>> parser = argparse.ArgumentParser(prog='frobble') - >>> parser.add_argument('--foo', action='store_true', - ... help='foo the bars before frobbling') - >>> parser.add_argument('bar', nargs='+', - ... help='one of the bars to be frobbled') - >>> parser.parse_args(['-h']) - usage: frobble [-h] [--foo] bar [bar ...] - - positional arguments: - bar one of the bars to be frobbled - - options: - -h, --help show this help message and exit - --foo foo the bars before frobbling +argument. The ``help`` strings can include various format specifiers to avoid repetition of things like the program name or the argument default_. The available @@ -1527,40 +1275,41 @@ this API may be passed as the ``action`` parameter to type=None, choices=None, required=False, help=None, \ metavar=None) -Action objects are used by an ArgumentParser to represent the information -needed to parse a single argument from one or more strings from the -command line. The Action class must accept the two positional arguments -plus any keyword arguments passed to :meth:`ArgumentParser.add_argument` -except for the ``action`` itself. + Action objects are used by an ArgumentParser to represent the information + needed to parse a single argument from one or more strings from the + command line. The Action class must accept the two positional arguments + plus any keyword arguments passed to :meth:`ArgumentParser.add_argument` + except for the ``action`` itself. -Instances of Action (or return value of any callable to the ``action`` -parameter) should have attributes "dest", "option_strings", "default", "type", -"required", "help", etc. defined. The easiest way to ensure these attributes -are defined is to call ``Action.__init__``. + Instances of Action (or return value of any callable to the ``action`` + parameter) should have attributes "dest", "option_strings", "default", "type", + "required", "help", etc. defined. The easiest way to ensure these attributes + are defined is to call ``Action.__init__``. -Action instances should be callable, so subclasses must override the -``__call__`` method, which should accept four parameters: + Action instances should be callable, so subclasses must override the + ``__call__`` method, which should accept four parameters: -* ``parser`` - The ArgumentParser object which contains this action. + * *parser* - The ArgumentParser object which contains this action. -* ``namespace`` - The :class:`Namespace` object that will be returned by - :meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this - object using :func:`setattr`. + * *namespace* - The :class:`Namespace` object that will be returned by + :meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this + object using :func:`setattr`. -* ``values`` - The associated command-line arguments, with any type conversions - applied. Type conversions are specified with the type_ keyword argument to - :meth:`~ArgumentParser.add_argument`. + * *values* - The associated command-line arguments, with any type conversions + applied. Type conversions are specified with the type_ keyword argument to + :meth:`~ArgumentParser.add_argument`. -* ``option_string`` - The option string that was used to invoke this action. - The ``option_string`` argument is optional, and will be absent if the action - is associated with a positional argument. + * *option_string* - The option string that was used to invoke this action. + The ``option_string`` argument is optional, and will be absent if the action + is associated with a positional argument. -The ``__call__`` method may perform arbitrary actions, but will typically set -attributes on the ``namespace`` based on ``dest`` and ``values``. + The ``__call__`` method may perform arbitrary actions, but will typically set + attributes on the ``namespace`` based on ``dest`` and ``values``. + + Action subclasses can define a ``format_usage`` method that takes no argument + and return a string which will be used when printing the usage of the program. + If such method is not provided, a sensible default will be used. -Action subclasses can define a ``format_usage`` method that takes no argument -and return a string which will be used when printing the usage of the program. -If such method is not provided, a sensible default will be used. The parse_args() method ----------------------- @@ -1755,29 +1504,29 @@ The Namespace object Simple class used by default by :meth:`~ArgumentParser.parse_args` to create an object holding attributes and return it. -This class is deliberately simple, just an :class:`object` subclass with a -readable string representation. If you prefer to have dict-like view of the -attributes, you can use the standard Python idiom, :func:`vars`:: - - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> args = parser.parse_args(['--foo', 'BAR']) - >>> vars(args) - {'foo': 'BAR'} - -It may also be useful to have an :class:`ArgumentParser` assign attributes to an -already existing object, rather than a new :class:`Namespace` object. This can -be achieved by specifying the ``namespace=`` keyword argument:: + This class is deliberately simple, just an :class:`object` subclass with a + readable string representation. If you prefer to have dict-like view of the + attributes, you can use the standard Python idiom, :func:`vars`:: - >>> class C: - ... pass - ... - >>> c = C() - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> parser.parse_args(args=['--foo', 'BAR'], namespace=c) - >>> c.foo - 'BAR' + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo') + >>> args = parser.parse_args(['--foo', 'BAR']) + >>> vars(args) + {'foo': 'BAR'} + + It may also be useful to have an :class:`ArgumentParser` assign attributes to an + already existing object, rather than a new :class:`Namespace` object. This can + be achieved by specifying the ``namespace=`` keyword argument:: + + >>> class C: + ... pass + ... + >>> c = C() + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo') + >>> parser.parse_args(args=['--foo', 'BAR'], namespace=c) + >>> c.foo + 'BAR' Other utilities @@ -1791,12 +1540,12 @@ Sub-commands [option_strings], [dest], [required], \ [help], [metavar]) - Many programs split up their functionality into a number of sub-commands, - for example, the ``svn`` program can invoke sub-commands like ``svn + Many programs split up their functionality into a number of subcommands, + for example, the ``svn`` program can invoke subcommands like ``svn checkout``, ``svn update``, and ``svn commit``. Splitting up functionality this way can be a particularly good idea when a program performs several different functions which require different kinds of command-line arguments. - :class:`ArgumentParser` supports the creation of such sub-commands with the + :class:`ArgumentParser` supports the creation of such subcommands with the :meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally called with no arguments and returns a special action object. This object has a single method, :meth:`~_SubParsersAction.add_parser`, which takes a @@ -1805,18 +1554,18 @@ Sub-commands Description of parameters: - * title - title for the sub-parser group in help output; by default + * *title* - title for the sub-parser group in help output; by default "subcommands" if description is provided, otherwise uses title for positional arguments - * description - description for the sub-parser group in help output, by + * *description* - description for the sub-parser group in help output, by default ``None`` - * prog - usage information that will be displayed with sub-command help, + * *prog* - usage information that will be displayed with sub-command help, by default the name of the program and any positional arguments before the subparser argument - * parser_class - class which will be used to create sub-parser instances, by + * *parser_class* - class which will be used to create sub-parser instances, by default the class of the current parser (e.g. ArgumentParser) * action_ - the basic type of action to be taken when this argument is @@ -1830,15 +1579,15 @@ Sub-commands * help_ - help for sub-parser group in help output, by default ``None`` - * metavar_ - string presenting available sub-commands in help; by default it - is ``None`` and presents sub-commands in form {cmd1, cmd2, ..} + * metavar_ - string presenting available subcommands in help; by default it + is ``None`` and presents subcommands in form {cmd1, cmd2, ..} Some example usage:: >>> # create the top-level parser >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('--foo', action='store_true', help='foo help') - >>> subparsers = parser.add_subparsers(help='sub-command help') + >>> subparsers = parser.add_subparsers(help='subcommand help') >>> >>> # create the parser for the "a" command >>> parser_a = subparsers.add_parser('a', help='a help') @@ -1873,7 +1622,7 @@ Sub-commands usage: PROG [-h] [--foo] {a,b} ... positional arguments: - {a,b} sub-command help + {a,b} subcommand help a a help b b help @@ -1944,12 +1693,12 @@ Sub-commands .. versionadded:: 3.13 - One particularly effective way of handling sub-commands is to combine the use + One particularly effective way of handling subcommands is to combine the use of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so that each subparser knows which Python function it should execute. For example:: - >>> # sub-command functions + >>> # subcommand functions >>> def foo(args): ... print(args.x * args.y) ... @@ -2231,20 +1980,20 @@ Partial parsing .. method:: ArgumentParser.parse_known_args(args=None, namespace=None) -Sometimes a script may only parse a few of the command-line arguments, passing -the remaining arguments on to another script or program. In these cases, the -:meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like -:meth:`~ArgumentParser.parse_args` except that it does not produce an error when -extra arguments are present. Instead, it returns a two item tuple containing -the populated namespace and the list of remaining argument strings. + Sometimes a script may only parse a few of the command-line arguments, passing + the remaining arguments on to another script or program. In these cases, the + :meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like + :meth:`~ArgumentParser.parse_args` except that it does not produce an error when + extra arguments are present. Instead, it returns a two item tuple containing + the populated namespace and the list of remaining argument strings. -:: + :: - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo', action='store_true') - >>> parser.add_argument('bar') - >>> parser.parse_known_args(['--foo', '--badger', 'BAR', 'spam']) - (Namespace(bar='BAR', foo=True), ['--badger', 'spam']) + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo', action='store_true') + >>> parser.add_argument('bar') + >>> parser.parse_known_args(['--foo', '--badger', 'BAR', 'spam']) + (Namespace(bar='BAR', foo=True), ['--badger', 'spam']) .. warning:: :ref:`Prefix matching ` rules apply to @@ -2302,90 +2051,38 @@ Intermixed parsing .. method:: ArgumentParser.parse_intermixed_args(args=None, namespace=None) .. method:: ArgumentParser.parse_known_intermixed_args(args=None, namespace=None) -A number of Unix commands allow the user to intermix optional arguments with -positional arguments. The :meth:`~ArgumentParser.parse_intermixed_args` -and :meth:`~ArgumentParser.parse_known_intermixed_args` methods -support this parsing style. - -These parsers do not support all the argparse features, and will raise -exceptions if unsupported features are used. In particular, subparsers, -and mutually exclusive groups that include both -optionals and positionals are not supported. - -The following example shows the difference between -:meth:`~ArgumentParser.parse_known_args` and -:meth:`~ArgumentParser.parse_intermixed_args`: the former returns ``['2', -'3']`` as unparsed arguments, while the latter collects all the positionals -into ``rest``. :: - - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> parser.add_argument('cmd') - >>> parser.add_argument('rest', nargs='*', type=int) - >>> parser.parse_known_args('doit 1 --foo bar 2 3'.split()) - (Namespace(cmd='doit', foo='bar', rest=[1]), ['2', '3']) - >>> parser.parse_intermixed_args('doit 1 --foo bar 2 3'.split()) - Namespace(cmd='doit', foo='bar', rest=[1, 2, 3]) - -:meth:`~ArgumentParser.parse_known_intermixed_args` returns a two item tuple -containing the populated namespace and the list of remaining argument strings. -:meth:`~ArgumentParser.parse_intermixed_args` raises an error if there are any -remaining unparsed argument strings. - -.. versionadded:: 3.7 - -.. _upgrading-optparse-code: - -Upgrading optparse code ------------------------ - -Originally, the :mod:`argparse` module had attempted to maintain compatibility -with :mod:`optparse`. However, :mod:`optparse` was difficult to extend -transparently, particularly with the changes required to support the new -``nargs=`` specifiers and better usage messages. When most everything in -:mod:`optparse` had either been copy-pasted over or monkey-patched, it no -longer seemed practical to try to maintain the backwards compatibility. - -The :mod:`argparse` module improves on the standard library :mod:`optparse` -module in a number of ways including: + A number of Unix commands allow the user to intermix optional arguments with + positional arguments. The :meth:`~ArgumentParser.parse_intermixed_args` + and :meth:`~ArgumentParser.parse_known_intermixed_args` methods + support this parsing style. -* Handling positional arguments. -* Supporting sub-commands. -* Allowing alternative option prefixes like ``+`` and ``/``. -* Handling zero-or-more and one-or-more style arguments. -* Producing more informative usage messages. -* Providing a much simpler interface for custom ``type`` and ``action``. + These parsers do not support all the argparse features, and will raise + exceptions if unsupported features are used. In particular, subparsers, + and mutually exclusive groups that include both + optionals and positionals are not supported. -A partial upgrade path from :mod:`optparse` to :mod:`argparse`: + The following example shows the difference between + :meth:`~ArgumentParser.parse_known_args` and + :meth:`~ArgumentParser.parse_intermixed_args`: the former returns ``['2', + '3']`` as unparsed arguments, while the latter collects all the positionals + into ``rest``. :: -* Replace all :meth:`optparse.OptionParser.add_option` calls with - :meth:`ArgumentParser.add_argument` calls. - -* Replace ``(options, args) = parser.parse_args()`` with ``args = - parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` - calls for the positional arguments. Keep in mind that what was previously - called ``options``, now in the :mod:`argparse` context is called ``args``. - -* Replace :meth:`optparse.OptionParser.disable_interspersed_args` - by using :meth:`~ArgumentParser.parse_intermixed_args` instead of - :meth:`~ArgumentParser.parse_args`. - -* Replace callback actions and the ``callback_*`` keyword arguments with - ``type`` or ``action`` arguments. - -* Replace string names for ``type`` keyword arguments with the corresponding - type objects (e.g. int, float, complex, etc). + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo') + >>> parser.add_argument('cmd') + >>> parser.add_argument('rest', nargs='*', type=int) + >>> parser.parse_known_args('doit 1 --foo bar 2 3'.split()) + (Namespace(cmd='doit', foo='bar', rest=[1]), ['2', '3']) + >>> parser.parse_intermixed_args('doit 1 --foo bar 2 3'.split()) + Namespace(cmd='doit', foo='bar', rest=[1, 2, 3]) -* Replace :class:`optparse.Values` with :class:`Namespace` and - :exc:`optparse.OptionError` and :exc:`optparse.OptionValueError` with - :exc:`ArgumentError`. + :meth:`~ArgumentParser.parse_known_intermixed_args` returns a two item tuple + containing the populated namespace and the list of remaining argument strings. + :meth:`~ArgumentParser.parse_intermixed_args` raises an error if there are any + remaining unparsed argument strings. -* Replace strings with implicit arguments such as ``%default`` or ``%prog`` with - the standard Python syntax to use dictionaries to format strings, that is, - ``%(default)s`` and ``%(prog)s``. + .. versionadded:: 3.7 -* Replace the OptionParser constructor ``version`` argument with a call to - ``parser.add_argument('--version', action='version', version='')``. Exceptions ---------- @@ -2400,3 +2097,12 @@ Exceptions .. exception:: ArgumentTypeError Raised when something goes wrong converting a command line string to a type. + + +.. rubric:: Guides and Tutorials + +.. toctree:: + :maxdepth: 1 + + ../howto/argparse.rst + ../howto/argparse-optparse.rst From 14b44c58e195c4cdee6594a4aacf8bf95b19fcd7 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 9 Oct 2024 00:46:11 +0200 Subject: [PATCH 063/247] gh-123849: Fix test_sqlite3.test_table_dump when foreign keys are enabled by default (#123859) --- Lib/test/test_sqlite3/test_dump.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_sqlite3/test_dump.py b/Lib/test/test_sqlite3/test_dump.py index d508f238f84fb5..550cea41976441 100644 --- a/Lib/test/test_sqlite3/test_dump.py +++ b/Lib/test/test_sqlite3/test_dump.py @@ -10,6 +10,7 @@ class DumpTests(MemoryDatabaseMixin, unittest.TestCase): def test_table_dump(self): expected_sqls = [ + "PRAGMA foreign_keys=OFF;", """CREATE TABLE "index"("index" blob);""" , """INSERT INTO "index" VALUES(X'01');""" @@ -48,7 +49,7 @@ def test_table_dump(self): expected_sqls = [ "PRAGMA foreign_keys=OFF;", "BEGIN TRANSACTION;", - *expected_sqls, + *expected_sqls[1:], "COMMIT;", ] [self.assertEqual(expected_sqls[i], actual_sqls[i]) From b502573f7f800dbb2e401fa2a7a05eceac692c7a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 9 Oct 2024 09:33:18 +0900 Subject: [PATCH 064/247] gh-124612: Use ghcr.io/python/autoconf instead of public image (#124657) * gh-124612: Use ghcr.io/python/autoconf instead of public image * Update --- Tools/build/regen-configure.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh index e34a36c1a573e5..efc80c8527885c 100755 --- a/Tools/build/regen-configure.sh +++ b/Tools/build/regen-configure.sh @@ -5,12 +5,10 @@ set -e -x # The check_generated_files job of .github/workflows/build.yml must kept in # sync with this script. Use the same container image than the job so the job # doesn't need to run autoreconf in a container. -IMAGE="ubuntu:22.04" -DEPENDENCIES="autotools-dev autoconf autoconf-archive pkg-config" +IMAGE="ghcr.io/python/autoconf:2024.10.06.11200919239" AUTORECONF="autoreconf -ivf -Werror" WORK_DIR="/src" -SHELL_CMD="apt-get update && apt-get -yq install $DEPENDENCIES && cd $WORK_DIR && $AUTORECONF" abs_srcdir=$(cd $(dirname $0)/../..; pwd) @@ -28,4 +26,4 @@ if command -v selinuxenabled >/dev/null && selinuxenabled; then PATH_OPT=":Z" fi -"$RUNTIME" run --rm -v "$abs_srcdir:$WORK_DIR$PATH_OPT" "$IMAGE" /usr/bin/bash -c "$SHELL_CMD" +"$RUNTIME" run --rm -v "$abs_srcdir:$WORK_DIR$PATH_OPT" "$IMAGE" From 78406382c97207b985b5c1d24db244ec398b7e3f Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 8 Oct 2024 22:03:53 -0700 Subject: [PATCH 065/247] gh-101552: Allow pydoc to display signatures in source format (#124669) Co-authored-by: Alex Waygood --- Doc/library/inspect.rst | 25 +++++++-- Doc/whatsnew/3.14.rst | 20 +++++++ Lib/inspect.py | 52 +++++++++++++------ Lib/pydoc.py | 5 +- .../inspect_deferred_annotations.py | 2 + Lib/test/test_inspect/test_inspect.py | 35 ++++++++++++- Lib/test/test_pydoc/test_pydoc.py | 10 ++-- ...-09-27-06-39-32.gh-issue-101552.xYkzag.rst | 4 ++ 8 files changed, 126 insertions(+), 27 deletions(-) create mode 100644 Lib/test/test_inspect/inspect_deferred_annotations.py create mode 100644 Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 853671856b2a14..1eaf1cc5d9a68e 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -694,7 +694,7 @@ and its return annotation. To retrieve a :class:`!Signature` object, use the :func:`!signature` function. -.. function:: signature(callable, *, follow_wrapped=True, globals=None, locals=None, eval_str=False) +.. function:: signature(callable, *, follow_wrapped=True, globals=None, locals=None, eval_str=False, annotation_format=Format.VALUE) Return a :class:`Signature` object for the given *callable*: @@ -725,7 +725,12 @@ function. *globals*, *locals*, and *eval_str* parameters are passed into :func:`!annotationlib.get_annotations` when resolving the annotations; see the documentation for :func:`!annotationlib.get_annotations` - for instructions on how to use these parameters. + for instructions on how to use these parameters. A member of the + :class:`annotationlib.Format` enum can be passed to the + *annotation_format* parameter to control the format of the returned + annotations. For example, use + ``annotation_format=annotationlib.Format.STRING`` to return annotations in string + format. Raises :exc:`ValueError` if no signature can be provided, and :exc:`TypeError` if that type of object is not supported. Also, @@ -733,7 +738,7 @@ function. the ``eval()`` call(s) to un-stringize the annotations in :func:`annotationlib.get_annotations` could potentially raise any kind of exception. - A slash(/) in the signature of a function denotes that the parameters prior + A slash (/) in the signature of a function denotes that the parameters prior to it are positional-only. For more info, see :ref:`the FAQ entry on positional-only parameters `. @@ -746,6 +751,9 @@ function. .. versionchanged:: 3.10 The *globals*, *locals*, and *eval_str* parameters were added. + .. versionchanged:: 3.14 + The *annotation_format* parameter was added. + .. note:: Some callables may not be introspectable in certain implementations of @@ -838,7 +846,7 @@ function. :class:`Signature` objects are also supported by the generic function :func:`copy.replace`. - .. method:: format(*, max_width=None) + .. method:: format(*, max_width=None, quote_annotation_strings=True) Create a string representation of the :class:`Signature` object. @@ -847,8 +855,17 @@ function. If the signature is longer than *max_width*, all parameters will be on separate lines. + If *quote_annotation_strings* is False, :term:`annotations ` + in the signature are displayed without opening and closing quotation + marks if they are strings. This is useful if the signature was created with the + :attr:`~annotationlib.Format.STRING` format or if + ``from __future__ import annotations`` was used. + .. versionadded:: 3.13 + .. versionchanged:: 3.14 + The *unquote_annotations* parameter was added. + .. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False) Return a :class:`Signature` (or its subclass) object for a given callable diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 4d71a24e9cc9ca..c62a3ca5872eef 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -281,6 +281,18 @@ http (Contributed by Yorik Hansen in :gh:`123430`.) +inspect +------- + +* :func:`inspect.signature` takes a new argument *annotation_format* to control + the :class:`annotationlib.Format` used for representing annotations. + (Contributed by Jelle Zijlstra in :gh:`101552`.) + +* :meth:`inspect.Signature.format` takes a new argument *unquote_annotations*. + If true, string :term:`annotations ` are displayed without surrounding quotes. + (Contributed by Jelle Zijlstra in :gh:`101552`.) + + json ---- @@ -356,6 +368,14 @@ pickle of the error. (Contributed by Serhiy Storchaka in :gh:`122213`.) +pydoc +----- + +* :term:`Annotations ` in help output are now usually + displayed in a format closer to that in the original source. + (Contributed by Jelle Zijlstra in :gh:`101552`.) + + symtable -------- diff --git a/Lib/inspect.py b/Lib/inspect.py index 1763ef640bbe04..0c33c6cc995a03 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -140,6 +140,7 @@ import abc +from annotationlib import Format from annotationlib import get_annotations # re-exported import ast import dis @@ -1319,7 +1320,9 @@ def getargvalues(frame): args, varargs, varkw = getargs(frame.f_code) return ArgInfo(args, varargs, varkw, frame.f_locals) -def formatannotation(annotation, base_module=None): +def formatannotation(annotation, base_module=None, *, quote_annotation_strings=True): + if not quote_annotation_strings and isinstance(annotation, str): + return annotation if getattr(annotation, '__module__', None) == 'typing': def repl(match): text = match.group() @@ -2270,7 +2273,8 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True): def _signature_from_function(cls, func, skip_bound_arg=True, - globals=None, locals=None, eval_str=False): + globals=None, locals=None, eval_str=False, + *, annotation_format=Format.VALUE): """Private helper: constructs Signature for the given python function.""" is_duck_function = False @@ -2296,7 +2300,8 @@ def _signature_from_function(cls, func, skip_bound_arg=True, positional = arg_names[:pos_count] keyword_only_count = func_code.co_kwonlyargcount keyword_only = arg_names[pos_count:pos_count + keyword_only_count] - annotations = get_annotations(func, globals=globals, locals=locals, eval_str=eval_str) + annotations = get_annotations(func, globals=globals, locals=locals, eval_str=eval_str, + format=annotation_format) defaults = func.__defaults__ kwdefaults = func.__kwdefaults__ @@ -2379,7 +2384,8 @@ def _signature_from_callable(obj, *, globals=None, locals=None, eval_str=False, - sigcls): + sigcls, + annotation_format=Format.VALUE): """Private helper function to get signature for arbitrary callable objects. @@ -2391,7 +2397,8 @@ def _signature_from_callable(obj, *, globals=globals, locals=locals, sigcls=sigcls, - eval_str=eval_str) + eval_str=eval_str, + annotation_format=annotation_format) if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) @@ -2472,7 +2479,8 @@ def _signature_from_callable(obj, *, # of a Python function (Cython functions, for instance), then: return _signature_from_function(sigcls, obj, skip_bound_arg=skip_bound_arg, - globals=globals, locals=locals, eval_str=eval_str) + globals=globals, locals=locals, eval_str=eval_str, + annotation_format=annotation_format) if _signature_is_builtin(obj): return _signature_from_builtin(sigcls, obj, @@ -2707,13 +2715,17 @@ def replace(self, *, name=_void, kind=_void, return type(self)(name, kind, default=default, annotation=annotation) def __str__(self): + return self._format() + + def _format(self, *, quote_annotation_strings=True): kind = self.kind formatted = self._name # Add annotation and default value if self._annotation is not _empty: - formatted = '{}: {}'.format(formatted, - formatannotation(self._annotation)) + annotation = formatannotation(self._annotation, + quote_annotation_strings=quote_annotation_strings) + formatted = '{}: {}'.format(formatted, annotation) if self._default is not _empty: if self._annotation is not _empty: @@ -2961,11 +2973,13 @@ def __init__(self, parameters=None, *, return_annotation=_empty, @classmethod def from_callable(cls, obj, *, - follow_wrapped=True, globals=None, locals=None, eval_str=False): + follow_wrapped=True, globals=None, locals=None, eval_str=False, + annotation_format=Format.VALUE): """Constructs Signature for the given callable object.""" return _signature_from_callable(obj, sigcls=cls, follow_wrapper_chains=follow_wrapped, - globals=globals, locals=locals, eval_str=eval_str) + globals=globals, locals=locals, eval_str=eval_str, + annotation_format=annotation_format) @property def parameters(self): @@ -3180,19 +3194,24 @@ def __repr__(self): def __str__(self): return self.format() - def format(self, *, max_width=None): + def format(self, *, max_width=None, quote_annotation_strings=True): """Create a string representation of the Signature object. If *max_width* integer is passed, signature will try to fit into the *max_width*. If signature is longer than *max_width*, all parameters will be on separate lines. + + If *quote_annotation_strings* is False, annotations + in the signature are displayed without opening and closing quotation + marks. This is useful when the signature was created with the + STRING format or when ``from __future__ import annotations`` was used. """ result = [] render_pos_only_separator = False render_kw_only_separator = True for param in self.parameters.values(): - formatted = str(param) + formatted = param._format(quote_annotation_strings=quote_annotation_strings) kind = param.kind @@ -3229,16 +3248,19 @@ def format(self, *, max_width=None): rendered = '(\n {}\n)'.format(',\n '.join(result)) if self.return_annotation is not _empty: - anno = formatannotation(self.return_annotation) + anno = formatannotation(self.return_annotation, + quote_annotation_strings=quote_annotation_strings) rendered += ' -> {}'.format(anno) return rendered -def signature(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False): +def signature(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False, + annotation_format=Format.VALUE): """Get a signature object for the passed callable.""" return Signature.from_callable(obj, follow_wrapped=follow_wrapped, - globals=globals, locals=locals, eval_str=eval_str) + globals=globals, locals=locals, eval_str=eval_str, + annotation_format=annotation_format) class BufferFlags(enum.IntFlag): diff --git a/Lib/pydoc.py b/Lib/pydoc.py index eec7b0770f56ca..c863794ea14ef9 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -71,6 +71,7 @@ class or function within a module or module in a package. If the import tokenize import urllib.parse import warnings +from annotationlib import Format from collections import deque from reprlib import Repr from traceback import format_exception_only @@ -212,12 +213,12 @@ def splitdoc(doc): def _getargspec(object): try: - signature = inspect.signature(object) + signature = inspect.signature(object, annotation_format=Format.STRING) if signature: name = getattr(object, '__name__', '') # function are always single-line and should not be formatted max_width = (80 - len(name)) if name != '' else None - return signature.format(max_width=max_width) + return signature.format(max_width=max_width, quote_annotation_strings=False) except (ValueError, TypeError): argspec = getattr(object, '__text_signature__', None) if argspec: diff --git a/Lib/test/test_inspect/inspect_deferred_annotations.py b/Lib/test/test_inspect/inspect_deferred_annotations.py new file mode 100644 index 00000000000000..bb59ef1035b3c1 --- /dev/null +++ b/Lib/test/test_inspect/inspect_deferred_annotations.py @@ -0,0 +1,2 @@ +def f(x: undefined): + pass diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 2ecb7ec1e26e0e..9fa6d23d15f06a 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -1,3 +1,4 @@ +from annotationlib import Format, ForwardRef import asyncio import builtins import collections @@ -22,7 +23,6 @@ import types import tempfile import textwrap -from typing import Unpack import unicodedata import unittest import unittest.mock @@ -46,6 +46,7 @@ from test.test_inspect import inspect_fodder as mod from test.test_inspect import inspect_fodder2 as mod2 from test.test_inspect import inspect_stringized_annotations +from test.test_inspect import inspect_deferred_annotations # Functions tested in this suite: @@ -4622,6 +4623,18 @@ def func( expected_multiline, ) + def test_signature_format_unquote(self): + def func(x: 'int') -> 'str': ... + + self.assertEqual( + inspect.signature(func).format(), + "(x: 'int') -> 'str'" + ) + self.assertEqual( + inspect.signature(func).format(quote_annotation_strings=False), + "(x: int) -> str" + ) + def test_signature_replace_parameters(self): def test(a, b) -> 42: pass @@ -4854,6 +4867,26 @@ def test_signature_eval_str(self): par('b', PORK, annotation=tuple), ))) + def test_signature_annotation_format(self): + ida = inspect_deferred_annotations + sig = inspect.Signature + par = inspect.Parameter + PORK = inspect.Parameter.POSITIONAL_OR_KEYWORD + for signature_func in (inspect.signature, inspect.Signature.from_callable): + with self.subTest(signature_func=signature_func): + self.assertEqual( + signature_func(ida.f, annotation_format=Format.STRING), + sig([par("x", PORK, annotation="undefined")]) + ) + self.assertEqual( + signature_func(ida.f, annotation_format=Format.FORWARDREF), + sig([par("x", PORK, annotation=ForwardRef("undefined"))]) + ) + with self.assertRaisesRegex(NameError, "undefined"): + signature_func(ida.f, annotation_format=Format.VALUE) + with self.assertRaisesRegex(NameError, "undefined"): + signature_func(ida.f) + def test_signature_none_annotation(self): class funclike: # Has to be callable, and have correct diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 776e02f41a1cec..2a4d3ab73db608 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -1073,7 +1073,7 @@ def __init__(self, class A(builtins.object) | A( - | arg1: collections.abc.Callable[[int, int, int], str], + | arg1: Callable[[int, int, int], str], | arg2: Literal['some value', 'other value'], | arg3: Annotated[int, 'some docs about this type'] | ) -> None @@ -1082,7 +1082,7 @@ class A(builtins.object) | | __init__( | self, - | arg1: collections.abc.Callable[[int, int, int], str], + | arg1: Callable[[int, int, int], str], | arg2: Literal['some value', 'other value'], | arg3: Annotated[int, 'some docs about this type'] | ) -> None @@ -1109,7 +1109,7 @@ def func( self.assertEqual(doc, '''Python Library Documentation: function func in module %s func( - arg1: collections.abc.Callable[[typing.Annotated[int, 'Some doc']], str], + arg1: Callable[[Annotated[int, 'Some doc']], str], arg2: Literal[1, 2, 3, 4, 5, 6, 7, 8] ) -> Annotated[int, 'Some other'] ''' % __name__) @@ -1394,8 +1394,8 @@ def foo(data: typing.List[typing.Any], T = typing.TypeVar('T') class C(typing.Generic[T], typing.Mapping[int, str]): ... self.assertEqual(pydoc.render_doc(foo).splitlines()[-1], - 'f\x08fo\x08oo\x08o(data: List[Any], x: int)' - ' -> Iterator[Tuple[int, Any]]') + 'f\x08fo\x08oo\x08o(data: typing.List[typing.Any], x: int)' + ' -> typing.Iterator[typing.Tuple[int, typing.Any]]') self.assertEqual(pydoc.render_doc(C).splitlines()[2], 'class C\x08C(collections.abc.Mapping, typing.Generic)') diff --git a/Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst b/Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst new file mode 100644 index 00000000000000..913a84de5fe6a3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst @@ -0,0 +1,4 @@ +Add an *annoation_format* parameter to :func:`inspect.signature`. Add an +*quote_annotation_strings* parameter to :meth:`inspect.Signature.format`. Use the +new functionality to improve the display of annotations in signatures in +:mod:`pydoc`. Patch by Jelle Zijlstra. From 7f93dbf6fec152888727a0f25a3aa030d1fe27ca Mon Sep 17 00:00:00 2001 From: musvaage <112724366+musvaage@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:04:35 +0200 Subject: [PATCH 066/247] docs: in venv table use executable name (GH-124315) Co-authored-by: musvaage --- Doc/library/venv.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index e2c77963ff3040..5205c6c211d9bf 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -215,7 +215,7 @@ containing the virtual environment): | +------------+--------------------------------------------------+ | | csh/tcsh | :samp:`$ source {}/bin/activate.csh` | | +------------+--------------------------------------------------+ -| | PowerShell | :samp:`$ {}/bin/Activate.ps1` | +| | pwsh | :samp:`$ {}/bin/Activate.ps1` | +-------------+------------+--------------------------------------------------+ | Windows | cmd.exe | :samp:`C:\\> {}\\Scripts\\activate.bat` | | +------------+--------------------------------------------------+ From e0c87c64b1cb4112ed5cfc1ae84ff8e48b1c0340 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Oct 2024 10:15:17 +0200 Subject: [PATCH 067/247] gh-124502: Remove _PyUnicode_EQ() function (#125114) * Replace unicode_compare_eq() with unicode_eq(). * Use unicode_eq() in setobject.c. * Replace _PyUnicode_EQ() with _PyUnicode_Equal(). * Remove unicode_compare_eq() and _PyUnicode_EQ(). --- Include/internal/pycore_unicodeobject.h | 6 +---- Objects/setobject.c | 6 +++-- Objects/unicodeobject.c | 35 +++---------------------- Python/getargs.c | 2 +- 4 files changed, 10 insertions(+), 39 deletions(-) diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 20497ee93016d0..a60372f58295a9 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -252,11 +252,7 @@ extern Py_ssize_t _PyUnicode_InsertThousandsGrouping( extern PyObject* _PyUnicode_FormatLong(PyObject *, int, int, int); -/* Fast equality check when the inputs are known to be exact unicode types - and where the hash values are equal (i.e. a very probable match) */ -extern int _PyUnicode_EQ(PyObject *, PyObject *); - -// Equality check. +// Fast equality check when the inputs are known to be exact unicode types. // Export for '_pickle' shared extension. PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *, PyObject *); diff --git a/Objects/setobject.c b/Objects/setobject.c index 8bff4d99f81b81..9f40e085f06fa6 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -40,6 +40,8 @@ #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_RELAXED() #include "pycore_pyerrors.h" // _PyErr_SetKeyError() #include "pycore_setobject.h" // _PySet_NextEntry() definition + +#include "stringlib/eq.h" // unicode_eq() #include // offsetof() #include "clinic/setobject.c.h" @@ -96,7 +98,7 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) return entry; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && _PyUnicode_EQ(startkey, key)) + && unicode_eq(startkey, key)) return entry; table = so->table; Py_INCREF(startkey); @@ -157,7 +159,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) goto found_active; if (PyUnicode_CheckExact(startkey) && PyUnicode_CheckExact(key) - && _PyUnicode_EQ(startkey, key)) + && unicode_eq(startkey, key)) goto found_active; table = so->table; Py_INCREF(startkey); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 60d4875d3b393e..bd5bb5048fdacc 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -261,7 +261,6 @@ _PyUnicode_InternedSize_Immortal(void) } static Py_hash_t unicode_hash(PyObject *); -static int unicode_compare_eq(PyObject *, PyObject *); static Py_uhash_t hashtable_unicode_hash(const void *key) @@ -275,7 +274,7 @@ hashtable_unicode_compare(const void *key1, const void *key2) PyObject *obj1 = (PyObject *)key1; PyObject *obj2 = (PyObject *)key2; if (obj1 != NULL && obj2 != NULL) { - return unicode_compare_eq(obj1, obj2); + return unicode_eq(obj1, obj2); } else { return obj1 == obj2; @@ -10968,26 +10967,6 @@ unicode_compare(PyObject *str1, PyObject *str2) #undef COMPARE } -static int -unicode_compare_eq(PyObject *str1, PyObject *str2) -{ - int kind; - const void *data1, *data2; - Py_ssize_t len; - int cmp; - - len = PyUnicode_GET_LENGTH(str1); - if (PyUnicode_GET_LENGTH(str2) != len) - return 0; - kind = PyUnicode_KIND(str1); - if (PyUnicode_KIND(str2) != kind) - return 0; - data1 = PyUnicode_DATA(str1); - data2 = PyUnicode_DATA(str2); - - cmp = memcmp(data1, data2, len * kind); - return (cmp == 0); -} int _PyUnicode_Equal(PyObject *str1, PyObject *str2) @@ -10997,7 +10976,7 @@ _PyUnicode_Equal(PyObject *str1, PyObject *str2) if (str1 == str2) { return 1; } - return unicode_compare_eq(str1, str2); + return unicode_eq(str1, str2); } @@ -11213,7 +11192,7 @@ _PyUnicode_EqualToASCIIId(PyObject *left, _Py_Identifier *right) return 0; } - return unicode_compare_eq(left, right_uni); + return unicode_eq(left, right_uni); } PyObject * @@ -11241,7 +11220,7 @@ PyUnicode_RichCompare(PyObject *left, PyObject *right, int op) } } else if (op == Py_EQ || op == Py_NE) { - result = unicode_compare_eq(left, right); + result = unicode_eq(left, right); result ^= (op == Py_NE); return PyBool_FromLong(result); } @@ -11251,12 +11230,6 @@ PyUnicode_RichCompare(PyObject *left, PyObject *right, int op) } } -int -_PyUnicode_EQ(PyObject *aa, PyObject *bb) -{ - return unicode_eq(aa, bb); -} - int PyUnicode_Contains(PyObject *str, PyObject *substr) { diff --git a/Python/getargs.c b/Python/getargs.c index 1b9b39939ae94e..a764343ea9ee3f 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -2064,7 +2064,7 @@ find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key) for (i = 0; i < nkwargs; i++) { PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); assert(PyUnicode_Check(kwname)); - if (_PyUnicode_EQ(kwname, key)) { + if (_PyUnicode_Equal(kwname, key)) { return Py_NewRef(kwstack[i]); } } From 92760bd85b8f48b88df5b81100a757048979de83 Mon Sep 17 00:00:00 2001 From: Furkan Onder Date: Wed, 9 Oct 2024 11:40:06 +0300 Subject: [PATCH 068/247] gh-125150: Skip test_fma_zero_result on NetBSD due to IEE 754-2008 implementation issues (#125151) Skip test_fma_zero_result on NetBSD due to IEE 754-2008 implementation issues --- Lib/test/test_math.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index a3eebc97ada23b..e2e2a419c7778c 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -2722,7 +2722,7 @@ def test_fma_infinities(self): # gh-73468: On some platforms, libc fma() doesn't implement IEE 754-2008 # properly: it doesn't use the right sign when the result is zero. @unittest.skipIf( - sys.platform.startswith(("freebsd", "wasi")) + sys.platform.startswith(("freebsd", "wasi", "netbsd")) or (sys.platform == "android" and platform.machine() == "x86_64"), f"this platform doesn't implement IEE 754-2008 properly") def test_fma_zero_result(self): From 21c04e1a972bd1b6285e0ea41fa107d635bbe43a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 9 Oct 2024 11:42:08 +0300 Subject: [PATCH 069/247] gh-124969: Fix locale.nl_langinfo(locale.ALT_DIGITS) (GH-124974) Now it returns a tuple of up to 100 strings (an empty tuple on most locales). Previously it returned the first item of that tuple or an empty string. --- Doc/library/locale.rst | 6 +-- Lib/test/test__locale.py | 41 ++++++++++++++++++- ...-10-08-12-09-09.gh-issue-124969._VBQLq.rst | 3 ++ Modules/_localemodule.c | 30 +++++++++++++- 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 04035b33d0ed48..5f3c4840b5cc70 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -158,7 +158,8 @@ The :mod:`locale` module defines the following exception and functions: .. function:: nl_langinfo(option) - Return some locale-specific information as a string. This function is not + Return some locale-specific information as a string (or a tuple for + ``ALT_DIGITS``). This function is not available on all systems, and the set of possible options might also vary across platforms. The possible argument values are numbers, for which symbolic constants are available in the locale module. @@ -311,8 +312,7 @@ The :mod:`locale` module defines the following exception and functions: .. data:: ALT_DIGITS - Get a representation of up to 100 values used to represent the values - 0 to 99. + Get a tuple of up to 100 strings used to represent the values 0 to 99. The function temporarily sets the ``LC_CTYPE`` locale to the locale of the category that determines the requested value (``LC_TIME``, diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py index ba2d31f9c1ee9d..02d2acc6d1c417 100644 --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -1,4 +1,4 @@ -from _locale import (setlocale, LC_ALL, LC_CTYPE, LC_NUMERIC, localeconv, Error) +from _locale import (setlocale, LC_ALL, LC_CTYPE, LC_NUMERIC, LC_TIME, localeconv, Error) try: from _locale import (RADIXCHAR, THOUSEP, nl_langinfo) except ImportError: @@ -74,6 +74,17 @@ def accept(loc): 'ps_AF': ('\u066b', '\u066c'), } +known_alt_digits = { + 'C': (0, {}), + 'en_US': (0, {}), + 'fa_IR': (100, {0: '\u06f0\u06f0', 10: '\u06f1\u06f0', 99: '\u06f9\u06f9'}), + 'ja_JP': (100, {0: '\u3007', 10: '\u5341', 99: '\u4e5d\u5341\u4e5d'}), + 'lzh_TW': (32, {0: '\u3007', 10: '\u5341', 31: '\u5345\u4e00'}), + 'my_MM': (100, {0: '\u1040\u1040', 10: '\u1041\u1040', 99: '\u1049\u1049'}), + 'or_IN': (100, {0: '\u0b66', 10: '\u0b67\u0b66', 99: '\u0b6f\u0b6f'}), + 'shn_MM': (100, {0: '\u1090\u1090', 10: '\u1091\u1090', 99: '\u1099\u1099'}), +} + if sys.platform == 'win32': # ps_AF doesn't work on Windows: see bpo-38324 (msg361830) del known_numerics['ps_AF'] @@ -179,6 +190,34 @@ def test_lc_numeric_basic(self): if not tested: self.skipTest('no suitable locales') + @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") + @unittest.skipUnless(hasattr(locale, 'ALT_DIGITS'), "requires locale.ALT_DIGITS") + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "musl libc issue on Emscripten, bpo-46390" + ) + def test_alt_digits_nl_langinfo(self): + # Test nl_langinfo(ALT_DIGITS) + tested = False + for loc, (count, samples) in known_alt_digits.items(): + with self.subTest(locale=loc): + try: + setlocale(LC_TIME, loc) + except Error: + self.skipTest(f'no locale {loc!r}') + continue + with self.subTest(locale=loc): + alt_digits = nl_langinfo(locale.ALT_DIGITS) + self.assertIsInstance(alt_digits, tuple) + if count and not alt_digits and sys.platform == 'darwin': + self.skipTest(f'ALT_DIGITS is not set for locale {loc!r} on macOS') + self.assertEqual(len(alt_digits), count) + for i in samples: + self.assertEqual(alt_digits[i], samples[i]) + tested = True + if not tested: + self.skipTest('no suitable locales') + def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. diff --git a/Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst b/Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst new file mode 100644 index 00000000000000..b5082b90721d42 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst @@ -0,0 +1,3 @@ +Fix ``locale.nl_langinfo(locale.ALT_DIGITS)``. Now it returns a tuple of up +to 100 strings (an empty tuple on most locales). Previously it returned the +first item of that tuple or an empty string. diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index ce77c4072a6aea..0daec646605775 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -666,9 +666,35 @@ _locale_nl_langinfo_impl(PyObject *module, int item) { return NULL; } - PyObject *unicode = PyUnicode_DecodeLocale(result, NULL); + PyObject *pyresult; +#ifdef ALT_DIGITS + if (item == ALT_DIGITS) { + /* The result is a sequence of up to 100 NUL-separated strings. */ + const char *s = result; + int count = 0; + for (; count < 100 && *s; count++) { + s += strlen(s) + 1; + } + pyresult = PyTuple_New(count); + if (pyresult != NULL) { + for (int i = 0; i < count; i++) { + PyObject *unicode = PyUnicode_DecodeLocale(result, NULL); + if (unicode == NULL) { + Py_CLEAR(pyresult); + break; + } + PyTuple_SET_ITEM(pyresult, i, unicode); + result += strlen(result) + 1; + } + } + } + else +#endif + { + pyresult = PyUnicode_DecodeLocale(result, NULL); + } restore_locale(oldloc); - return unicode; + return pyresult; } } PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant"); From 53930cbe47529c4de9177538c98ffdb354b9854e Mon Sep 17 00:00:00 2001 From: Alexander Kanavin Date: Wed, 9 Oct 2024 11:16:08 +0200 Subject: [PATCH 070/247] gh-107562: make_ssl_certs.py: produce test certificates that expire far in the future by default (GH-107594) This allows testing Y2038 with system time set to after that, so that actual Y2038 issues can be exposed, and not masked by expired certificate errors. Signed-off-by: Alexander Kanavin --- Lib/test/certdata/make_ssl_certs.py | 4 ++-- Lib/test/test_ssl.py | 1 + .../next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst diff --git a/Lib/test/certdata/make_ssl_certs.py b/Lib/test/certdata/make_ssl_certs.py index 198c64035c5044..18e614496385fd 100644 --- a/Lib/test/certdata/make_ssl_certs.py +++ b/Lib/test/certdata/make_ssl_certs.py @@ -9,8 +9,8 @@ from subprocess import * startdate = "20180829142316Z" -enddate_default = "20371028142316Z" -days_default = "7000" +enddate_default = "25251028142316Z" +days_default = "140000" req_template = """ [ default ] diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 216aa84a8c147b..b93fa0ed99f8ce 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -383,6 +383,7 @@ def test_random(self): ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0) def test_parse_cert(self): + self.maxDiff = None # note that this uses an 'unofficial' function in _ssl.c, # provided solely for this test, to exercise the certificate # parsing code diff --git a/Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst b/Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst new file mode 100644 index 00000000000000..cc368d4bdffbd2 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst @@ -0,0 +1,3 @@ +Test certificates have been updated to expire far in the future. This allows +testing Y2038 with system time set to after that, so that actual Y2038 +issues can be exposed, and not masked by expired certificate errors. From d20c43d8e270016d743af6e8e0f8267e396a71f4 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 9 Oct 2024 11:17:02 +0200 Subject: [PATCH 071/247] gh-107562: Update test certificates to expire far in the future (GH-125104) Generated with Lib/test/certdata/make_ssl_certs.py using openssl-3.2.2-3.fc40.x86_64 (Fedora 40). --- Lib/test/certdata/allsans.pem | 252 +++++++++++------------ Lib/test/certdata/capath/b1930218.0 | 48 ++--- Lib/test/certdata/capath/ceff1710.0 | 48 ++--- Lib/test/certdata/cert3.pem | 62 +++--- Lib/test/certdata/idnsans.pem | 250 +++++++++++----------- Lib/test/certdata/keycert.passwd.pem | 126 ++++++------ Lib/test/certdata/keycert.pem | 122 +++++------ Lib/test/certdata/keycert.pem.reference | 6 +- Lib/test/certdata/keycert2.pem | 122 +++++------ Lib/test/certdata/keycert3.pem | 240 ++++++++++----------- Lib/test/certdata/keycert3.pem.reference | 4 +- Lib/test/certdata/keycert4.pem | 240 ++++++++++----------- Lib/test/certdata/keycertecc.pem | 122 +++++------ Lib/test/certdata/nosan.pem | 228 ++++++++++---------- Lib/test/certdata/pycacert.pem | 150 +++++++------- Lib/test/certdata/pycakey.pem | 76 +++---- Lib/test/certdata/revocation.crl | 22 +- Lib/test/certdata/ssl_cert.pem | 46 ++--- Lib/test/certdata/ssl_key.passwd.pem | 80 +++---- Lib/test/certdata/ssl_key.pem | 76 +++---- 20 files changed, 1163 insertions(+), 1157 deletions(-) diff --git a/Lib/test/certdata/allsans.pem b/Lib/test/certdata/allsans.pem index 02f2c2e6346ef8..f6a63b9219d246 100644 --- a/Lib/test/certdata/allsans.pem +++ b/Lib/test/certdata/allsans.pem @@ -1,42 +1,42 @@ -----BEGIN PRIVATE KEY----- -MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCczEVv5D2UDtn6 -DMmZ/uCWCLyL+K5xTZp/5j3cyISoaTuU1Ku3kD97eLgpHj4Fgk5ZJi21zsQqepCj -jAhBk6tj6RYUcnMbb8MuxUkQMEDW+5LfSyp+HCaetlHosWdhEDqX4kpJ5ajBwNRt -07mxQExtC4kcno0ut9rG5XzLN29XpCpRHlFFrntOgQAEoiz9/fc8qaTgb37RgGYP -Qsxh7PcRDRe4ZGx1l06Irr8Y+2W50zWCfkwCS3DaLDOKIjSOfPHNqmfcfsTpzrj8 -330cdPklrMIuiBv+iGklCjkPZJiEhxvY2k6ERM4HAxxuPCivrH5MCeMNYvBVUcLr -GROm7JRXRllI/XubwwoAaAb+y+dZtCZ9AnzHIb+nyKiJxWAjzjR+QPL6jHrVWBVA -WTc83YP5FvxUXMfY3sVv9tNSCV3cpYOW5+iXcQzLuczXnOLRYk7p9wkb0/hk9KuK -4BMA90eBhvFMCFgHJ1/xJg2nFmBHPo/xbcwPG/ma5T/McA8mAlECAwEAAQKCAYAB -m29nxPNjod5Wm4xydWQYbZj/J0qkcyru/i1qpqyDbGa1sRNcg5A/A/8BPuPcWxhR -/hvwVeD5XX2/i2cnQuv6D3DQP1cSNCxQPanwzknP2k7IVqUmG0RDErPWuoDIhCnR -ljp0NPQsnj0fLhEkcbgG0xwx7KceUDigGsiTbatIvvBHGhQzrmTpqlVVdtMWvGRt -HQEJYuMuIw6IwALHyy3CITv5wh/Bec5OhNoFF8iUZceR4ZkGWf8bYWIa25xlzH6K -4rhOOh1G2ObHHTjhZq4mGXTHY1MEkAxXKWlR3DJc0Lh5E1UETSI6WBHWRb08iwQ5 -AkLOPyMpt08xHFWbJqywvlxenpri+gjY3xbXqGNhyDYWHZqlQmJVnzxoUOuuHi2R -dO86IckUc4Thjbm7a6AilL9t8juNZvyeQUVgtVi25uPkm/cK6r5vo8y4UOUU41EN -NOathlF69gh93il4t6zJW9jPV2WENv1H/vhKUWKW6cabX3vy4rANwy3q4V//GDEC -gcEAuniGCHaEdSjV2sUHyt/yrCLbU6+eLTfNk6AQyXJk6Wrvj6g3gx90ewEq5i/C -ukmSKDslr9pupq8Z/UNfYHZfJfpwEsYvIZ8DdFSd62/h66DhIoEn1v3Lwt+aexgX -yGJHF0BG9JA2CU5Z5NGjlnQYqQBobO9uZMq62l15Ig1MAMHGL0ZYVvOqGZD7XvtC -4UnclK5kjp51Vd5rydEQxyi5qkyLl9Q6T0FQXOphGIOd8ifYeUGe7YC72cFPevdx -wDXZAoHBANdDVvCMrjmzdrS6td39/2nHTeerFPbsOe2LIQYzqjeEe6GWqd2NL9NZ -bk3/cAuVgbWtdvSQQhhmSqOC7JZic4hbZb3lK6v/sr4F/Zu0CfAu80swWFMeS7vq -eQeYzN4w4dKpJArvU3ll7N9AlZhdlYkbPf0WdeOIjZawdAOxNtNe0O+j+5MsXR59 -qkULatumhcKUnqxFCiVHzy21CVJtRzrtu6oGoSdFbmG82eSJ1rPXiuuDnCyzjyMW -iClYRM4NOQKBwERnO/vUxihYT4LOLlqcpl/A9aYQUT0TMGWMHTxYq2343WJceeiu -3ELXHc6NDKjbnjMF54BH57lbmHQQh+dR5PuAkCZC7z0tIM5G0Bty0nRmcs/+gwfZ -2Cpnbjrjjq3iZ2O/H4hNcpUdWdqXkKP7eKReUvBLMLrmp369NVdpe0z3yGTFMFjN -T8PLLHsePt14A+PCyX6L4E0cp3vEJpx4cwtmwvpyTuWN9xXuoKmmdoVDWqS4jr1f -MQnjYO2h4ed5mQKBwGVttWli4DUP+r7tuwP+ynptDqg6VIaEiEcFZ2okre+63QYm -l6NtAzvyx6a41XKf355bPdG+p2YXzNN+vTue6BE3/5iagxloQjCHYhgbnRMvDDRB -c1y2ybihoqWRufZ30fARAoqkehCZliMbq2E/t1YDIBJAowuzLAP04LVcqxitdIV2 -HvQZ00aqr7AY0SDuNdiZbqp9XWpzi4td4iaUlxuNKP/UX9rBPGGROpoU2LWkujB+ -svfdI3TFCSNyE/mDAQKBwQCP++WZKxExrSFRk3W+TcHKHZb2pusfoPWE7WH6EnDW -dkTZpa3PZaf0xgeglmNBv4Paxw2eMPsIhyNv62XY/6GbY6VJWRyx/s+NsazeP4ji -xUOufnwTePjYw6x0pcl6BknZrHn8LCJU741h0yTum8cDdNfRKdc0AMy0gVXk4ZTG -2cAtbEcWb3J+a5kYf6mp5yx3BNwtewkGZhc2VuQ9mQNbMmOOS/pHQQTRWcxsQwyt -GPAhMKawjrL1KFmu7vIqDSw= +MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCYEY+lIwS/w+gA +U5PfxSeL4qMF5TtFkrifL0oQaCjWFb8jeX2Rb1tKaObyrYmTURVWbMkI1LJOQWYt +GlANo2mvf4VD1wZZ/x/Tmylxe3A7itSTZgZuGXLHtFP9wk7yS46BlVcNq3ZoOi7k +k8NxTiUqgsmLg3Nj+Ifk8OI7c1BcP2pa1wZO/l3PTWqtFSLsFEvOK5N6ZPqILAUi +5vEkOiFefxVHHvD4N3IWSFgSwiDi9KhntdRwa+axsZxjq/o70FjQO5q5Quym9aDq +qo47PMykEb1gdTBQK1mPliMKsLi5zycI/ypm1PEcH53+9/F+U2B1bmvA/9PBx8T7 +hUyclBbQHCmdcXIYCgFr5AbGS3jFeVPiF7hCPj1k/jcpayXZAtWmqJTlkXKGbM68 +AgM/DHO0fGCYGRUw2vhV3ZIRCm0BqwforeFh+2oMyZjDjvo/uZjZNazdpcwvOy0c +lFkORwVI0zTIixXYSV4xN1BX821JCuhYubro89m+MSjxO14qgs0CAwEAAQKCAYAZ +txqF7+qNLSlN6NRASnw6BQzRYebIiJus25fYN2z0awAEFTbdQan75sprLlpt7Y/A +qivC0QkH/7oyFVmFPOWR1mwoQTPjQyfUJlB3Tsr3Xq488MtUkfwddkqfxlyIT6ud +ES6D8sNWs8QbRjuOLQtO6YgAji2UscH1PqDbMdBckSLAks0Pzab6d9p6w3DA4FvD +VQ4e6/WL0nnZ4ZjUqfnbm3zzJnHUX7fsubYfEfHyvzG9O/vdOPntgZ3zIvFxbPVc +/Dp8MRNgfQoRgAsc7VBQQifFNvva9SjvRsXwE7zQLQh9JszFpHWqIMevGwjdH8dO +1hHESqkRHL0sYwsqoGqbaHFrJVEA2Ljuxs/UsH6G2U6NuDVaYkqM8UwH0+EqGFtF +9qP8oh6Yvp+szI5yET4brW0Rlk8r2UqvQ5iSSl8SSWsNKR2wRs0PM0aNm13TDJmt +NOuxd/0ranG+NvBMdtLCwsoEplYDaaczYv9gbKHT64OlFAdGBkOytbS7eqOojmcC +gcEA0uQb9bPKbiMYSEJMAalOlruzvMiHBRW420IEuGyHJtocn/RK804Jj6gzu+WD +GT81rB9NXAt/3s6WDMSdrGrrBh/CQZJs50ok9hej0f6gsq1JNsWJ/c10rU/mqrTn +s++pdaRqbd+bgM/N6h79tJi3j4SgB9rJqjC+7qWlDJFWZOoDR59elc10xDA0AE0a +K6UvsJJGk4/v715K1Uh2qU5HYupuijNc0m3z2OMZ6zxTNNUdbSL4XF5X9e2+BwMQ +YrRzAoHBALiYeYWsmHGRdg++/p/9SE86YwyEYr+zrUiWenIPC1W5WQlkdFQqALmg +kjcXAXFFouC/DnKG65YOfGq772ekFuw06Lm4DEotQP02pESfAP9ulVufK2yJtbxi +m0PeN3JRrs/H72VW9hUSxCafNRyBeZ6nsfzEfEkPOdc+lRGeMHT9C7r7Y1asNk8A +Zl7wKZgv+Yvn8xhHWQj5z/T6K2z5CXFn6FERc0qV8+DggE9m3CjaaNxft6IodfHD +h1iakNtbvwKBwQCpWr/NRy131r0IQh0xdFoFGAUVxF8RSUli4hhSVe0O2TcFiLOr +wW5SK/wnlv75hlY+vABuu1lbfsDmzfnk3RORnm1sJP9JmbQm4AMRfw5jjl7uGiJf +a9+X0kNlsNMlH4ARVhCV3WzOO5KbwXlxzvYRzaqJxDwQbQbXNLRfbFNZxMcPfD8D +w7NSXXdVCpXKmOO8QytkEsHWkv07W+7WtWMEX0iXuPmAjwW0lWNaEd6r3by8yMlz +u9udRedFUEOXUFsCgcAX0g00c75EQXoTtBjVenC/UJCBh//aLwx4Znqsh0Z2LHHR +5XWher4XNiJIG57jCBJpoB30J3b1KS9i8peFL0aJ+pXhiV+EnuxZAJkYBdCyJYn+ +hb6rxeV+xta0XlOXW/UL+QfqcttUgtRvC3JmGEsibw9nx88l+mIDZZ8E4/3qytCd +s1zxTU3AyhNrwuALNH2mUSssgeB6aQot2a6K5GQUj00KUQ8om8sZxL6qAGL+npiT +f4KJ2WDG7u1jQKbat68CgcBONTGp3M3pdwc3OV/PMFq1+h1/BuyW/5qUtbsvXkrD +DZyXGY2SxJFMipakzOppusaQOYmO+VXKVDRJm8UG6fa2cdXjwm2kDxHB5E+v59VI ++uM8ErX6L52I0+rdoOU6AwpXyiVW5AXzMInOGHF4B7zJ1SA25RwVG44LbDw1cehW +MALXUdVCaegmvCCFq5TQlrlaEktxWk6Th92mXWbNbwUHlIGpcjEkASFvt90aBXWZ +w0YCQFVxx/K95nzKyRTjHTQ= -----END PRIVATE KEY----- Certificate: Data: @@ -47,38 +47,38 @@ Certificate: Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Validity Not Before: Aug 29 14:23:16 2018 GMT - Not After : Oct 28 14:23:16 2037 GMT + Not After : Oct 28 14:23:16 2525 GMT Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=allsans Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: - 00:9c:cc:45:6f:e4:3d:94:0e:d9:fa:0c:c9:99:fe: - e0:96:08:bc:8b:f8:ae:71:4d:9a:7f:e6:3d:dc:c8: - 84:a8:69:3b:94:d4:ab:b7:90:3f:7b:78:b8:29:1e: - 3e:05:82:4e:59:26:2d:b5:ce:c4:2a:7a:90:a3:8c: - 08:41:93:ab:63:e9:16:14:72:73:1b:6f:c3:2e:c5: - 49:10:30:40:d6:fb:92:df:4b:2a:7e:1c:26:9e:b6: - 51:e8:b1:67:61:10:3a:97:e2:4a:49:e5:a8:c1:c0: - d4:6d:d3:b9:b1:40:4c:6d:0b:89:1c:9e:8d:2e:b7: - da:c6:e5:7c:cb:37:6f:57:a4:2a:51:1e:51:45:ae: - 7b:4e:81:00:04:a2:2c:fd:fd:f7:3c:a9:a4:e0:6f: - 7e:d1:80:66:0f:42:cc:61:ec:f7:11:0d:17:b8:64: - 6c:75:97:4e:88:ae:bf:18:fb:65:b9:d3:35:82:7e: - 4c:02:4b:70:da:2c:33:8a:22:34:8e:7c:f1:cd:aa: - 67:dc:7e:c4:e9:ce:b8:fc:df:7d:1c:74:f9:25:ac: - c2:2e:88:1b:fe:88:69:25:0a:39:0f:64:98:84:87: - 1b:d8:da:4e:84:44:ce:07:03:1c:6e:3c:28:af:ac: - 7e:4c:09:e3:0d:62:f0:55:51:c2:eb:19:13:a6:ec: - 94:57:46:59:48:fd:7b:9b:c3:0a:00:68:06:fe:cb: - e7:59:b4:26:7d:02:7c:c7:21:bf:a7:c8:a8:89:c5: - 60:23:ce:34:7e:40:f2:fa:8c:7a:d5:58:15:40:59: - 37:3c:dd:83:f9:16:fc:54:5c:c7:d8:de:c5:6f:f6: - d3:52:09:5d:dc:a5:83:96:e7:e8:97:71:0c:cb:b9: - cc:d7:9c:e2:d1:62:4e:e9:f7:09:1b:d3:f8:64:f4: - ab:8a:e0:13:00:f7:47:81:86:f1:4c:08:58:07:27: - 5f:f1:26:0d:a7:16:60:47:3e:8f:f1:6d:cc:0f:1b: - f9:9a:e5:3f:cc:70:0f:26:02:51 + 00:98:11:8f:a5:23:04:bf:c3:e8:00:53:93:df:c5: + 27:8b:e2:a3:05:e5:3b:45:92:b8:9f:2f:4a:10:68: + 28:d6:15:bf:23:79:7d:91:6f:5b:4a:68:e6:f2:ad: + 89:93:51:15:56:6c:c9:08:d4:b2:4e:41:66:2d:1a: + 50:0d:a3:69:af:7f:85:43:d7:06:59:ff:1f:d3:9b: + 29:71:7b:70:3b:8a:d4:93:66:06:6e:19:72:c7:b4: + 53:fd:c2:4e:f2:4b:8e:81:95:57:0d:ab:76:68:3a: + 2e:e4:93:c3:71:4e:25:2a:82:c9:8b:83:73:63:f8: + 87:e4:f0:e2:3b:73:50:5c:3f:6a:5a:d7:06:4e:fe: + 5d:cf:4d:6a:ad:15:22:ec:14:4b:ce:2b:93:7a:64: + fa:88:2c:05:22:e6:f1:24:3a:21:5e:7f:15:47:1e: + f0:f8:37:72:16:48:58:12:c2:20:e2:f4:a8:67:b5: + d4:70:6b:e6:b1:b1:9c:63:ab:fa:3b:d0:58:d0:3b: + 9a:b9:42:ec:a6:f5:a0:ea:aa:8e:3b:3c:cc:a4:11: + bd:60:75:30:50:2b:59:8f:96:23:0a:b0:b8:b9:cf: + 27:08:ff:2a:66:d4:f1:1c:1f:9d:fe:f7:f1:7e:53: + 60:75:6e:6b:c0:ff:d3:c1:c7:c4:fb:85:4c:9c:94: + 16:d0:1c:29:9d:71:72:18:0a:01:6b:e4:06:c6:4b: + 78:c5:79:53:e2:17:b8:42:3e:3d:64:fe:37:29:6b: + 25:d9:02:d5:a6:a8:94:e5:91:72:86:6c:ce:bc:02: + 03:3f:0c:73:b4:7c:60:98:19:15:30:da:f8:55:dd: + 92:11:0a:6d:01:ab:07:e8:ad:e1:61:fb:6a:0c:c9: + 98:c3:8e:fa:3f:b9:98:d9:35:ac:dd:a5:cc:2f:3b: + 2d:1c:94:59:0e:47:05:48:d3:34:c8:8b:15:d8:49: + 5e:31:37:50:57:f3:6d:49:0a:e8:58:b9:ba:e8:f3: + d9:be:31:28:f1:3b:5e:2a:82:cd Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: @@ -90,9 +90,9 @@ Certificate: X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: - 31:5E:C0:5E:2F:47:FF:8B:92:F9:EE:3D:B1:87:D0:53:75:3B:B1:48 + 73:0D:4E:1F:4A:EC:F2:53:0F:53:FC:85:6F:CF:82:CD:A3:E8:11:8D X509v3 Authority Key Identifier: - keyid:F3:EC:94:8E:F2:8E:30:C4:8E:68:C2:BF:8E:6A:19:C0:C1:9F:76:65 + keyid:C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server serial:CB:2D:80:99:5A:69:52:5B Authority Information Access: @@ -103,65 +103,65 @@ Certificate: URI:http://testca.pythontest.net/testca/revocation.crl Signature Algorithm: sha256WithRSAEncryption Signature Value: - 72:42:a6:fc:ee:3c:21:47:05:33:e8:8c:6b:27:07:4a:ed:e2: - 81:47:96:79:43:ff:0f:ef:5a:06:aa:4c:01:70:5b:21:c4:b7: - 5d:17:29:c8:10:02:c3:08:7b:8c:86:56:9e:e9:7c:6e:a8:b6: - 26:13:9e:1e:1f:93:66:85:67:63:9e:08:fb:55:39:56:82:f5: - be:0c:38:1e:eb:c4:54:b2:a7:7b:18:55:bb:00:87:43:50:50: - bb:e1:29:10:cf:3d:c9:07:c7:d2:5d:b6:45:68:1f:d6:de:00: - 96:3e:29:73:f6:22:70:21:a2:ba:68:28:94:ec:37:bc:a7:00: - 70:58:4e:d1:48:ae:ef:8d:11:a4:6e:10:2f:92:83:07:e2:76: - ac:bf:4f:bb:d6:9f:47:9e:a4:02:03:16:f8:a8:0a:3d:67:17: - 31:44:0e:68:d0:d3:24:d5:e7:bf:67:30:8f:88:97:92:0a:1e: - d7:74:df:7e:7b:4c:c6:d9:c3:84:92:2b:a0:89:11:08:4c:dd: - 32:49:df:36:23:d4:63:56:e4:f1:68:5a:6f:a0:c3:3c:e2:36: - ee:f3:46:60:78:4d:76:a5:5a:4a:61:c6:f8:ae:18:68:c2:8d: - 0e:2f:76:50:bb:be:b9:56:f1:04:5c:ac:ad:d7:d6:a4:1e:45: - 45:52:f4:10:a2:0f:9b:e3:d9:73:17:b6:52:42:a6:5b:c9:e9: - 8d:60:74:68:d0:1f:7a:ce:01:8e:9e:55:cb:cf:64:c1:cc:9a: - 72:aa:b4:5f:b5:55:13:41:10:51:a0:2c:a5:5b:43:12:ca:cc: - b7:c4:ac:f2:6f:72:fd:0d:50:6a:d6:81:c1:91:93:21:fe:de: - 9a:be:e5:3c:2a:98:95:a1:42:f8:f2:5c:75:c6:f1:fd:11:b1: - 22:26:33:5b:43:63:21:06:61:d2:cd:04:f3:30:c6:a8:3f:17: - d3:05:a3:87:45:2e:52:1e:51:88:e3:59:4c:78:51:b0:7b:b4: - 58:d9:27:22:6e:8c + a5:3d:12:87:b9:3b:3e:9c:1c:59:fb:d5:38:22:49:61:f3:c3: + 11:53:4b:4e:63:af:f2:3d:ef:24:67:45:bc:74:5c:4a:65:c5: + b4:bb:fe:84:b8:b6:ca:7d:fc:aa:ff:80:ae:67:1f:cb:c3:cd: + 8f:f9:75:8c:f9:d3:3f:db:f6:81:d8:06:42:c3:5d:a9:1e:a3: + 81:7d:57:ac:97:d9:bd:c8:ce:1e:ec:74:d7:94:d5:df:b1:ad: + ce:84:14:5c:8c:45:a4:a8:eb:67:ab:16:57:61:15:86:ae:11: + 1e:b5:10:42:de:84:76:88:9b:37:12:aa:a6:77:42:75:b4:c0: + 04:b3:75:45:e0:d7:aa:34:e3:07:c5:ed:f8:4e:f0:39:99:1f: + 5b:d8:4e:0c:ad:64:6d:09:07:3f:e3:e1:9f:1b:65:07:96:59: + 9a:b5:f1:4d:c3:ec:f7:32:a1:05:94:d1:0b:18:54:3c:67:cf: + 38:f5:2b:ec:cb:bd:79:be:f7:1b:b7:71:3f:c6:44:80:7f:00: + dc:3d:a0:07:c0:b5:1c:fb:52:f6:a0:f8:92:c6:c6:73:07:c5: + ca:0b:04:7c:55:51:e3:ba:93:32:17:bd:61:ae:cf:13:e4:5e: + 03:b2:51:11:c7:68:f5:08:b6:0e:57:49:11:3c:e3:f4:0e:e1: + 96:20:44:28:31:94:11:44:50:cf:17:70:8d:9c:14:c5:ed:94: + 4d:ba:94:9b:db:8b:9f:55:a1:5e:0a:90:bb:a0:0e:0d:3b:a0: + dd:4d:47:d1:cf:d0:47:6b:ff:6f:af:e4:83:40:73:e6:3a:59: + 40:bd:4f:3a:21:22:63:27:5d:02:26:67:89:1d:2f:19:c5:77: + e6:b5:67:4a:dd:b5:0e:de:46:34:57:c7:03:84:5d:cd:34:08: + 8f:47:c9:4d:7f:04:c0:4f:ff:68:52:bb:ae:84:0e:54:ce:5c: + 27:71:0f:a2:3f:9f:7a:49:a8:fa:0a:45:cf:96:42:a7:65:23: + b9:3e:40:eb:46:7b -----BEGIN CERTIFICATE----- -MIIHDTCCBXWgAwIBAgIJAMstgJlaaVJfMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIHDzCCBXegAwIBAgIJAMstgJlaaVJfMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaMF0xCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj -MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2Fs -bHNhbnMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCczEVv5D2UDtn6 -DMmZ/uCWCLyL+K5xTZp/5j3cyISoaTuU1Ku3kD97eLgpHj4Fgk5ZJi21zsQqepCj -jAhBk6tj6RYUcnMbb8MuxUkQMEDW+5LfSyp+HCaetlHosWdhEDqX4kpJ5ajBwNRt -07mxQExtC4kcno0ut9rG5XzLN29XpCpRHlFFrntOgQAEoiz9/fc8qaTgb37RgGYP -Qsxh7PcRDRe4ZGx1l06Irr8Y+2W50zWCfkwCS3DaLDOKIjSOfPHNqmfcfsTpzrj8 -330cdPklrMIuiBv+iGklCjkPZJiEhxvY2k6ERM4HAxxuPCivrH5MCeMNYvBVUcLr -GROm7JRXRllI/XubwwoAaAb+y+dZtCZ9AnzHIb+nyKiJxWAjzjR+QPL6jHrVWBVA -WTc83YP5FvxUXMfY3sVv9tNSCV3cpYOW5+iXcQzLuczXnOLRYk7p9wkb0/hk9KuK -4BMA90eBhvFMCFgHJ1/xJg2nFmBHPo/xbcwPG/ma5T/McA8mAlECAwEAAaOCAt4w -ggLaMIIBMAYDVR0RBIIBJzCCASOCB2FsbHNhbnOgHgYDKgMEoBcMFXNvbWUgb3Ro -ZXIgaWRlbnRpZmllcqA1BgYrBgEFAgKgKzApoBAbDktFUkJFUk9TLlJFQUxNoRUw -E6ADAgEBoQwwChsIdXNlcm5hbWWBEHVzZXJAZXhhbXBsZS5vcmeCD3d3dy5leGFt -cGxlLm9yZ6RnMGUxCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJh -eDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xGDAWBgNVBAMM -D2Rpcm5hbWUgZXhhbXBsZYYXaHR0cHM6Ly93d3cucHl0aG9uLm9yZy+HBH8AAAGH -EAAAAAAAAAAAAAAAAAAAAAGIBCoDBAUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW -MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQx -XsBeL0f/i5L57j2xh9BTdTuxSDB9BgNVHSMEdjB0gBTz7JSO8o4wxI5owr+OahnA -wZ92ZaFRpE8wTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5dGhvbiBTb2Z0d2Fy -ZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2VydmVyggkAyy2AmVpp -UlswgYMGCCsGAQUFBwEBBHcwdTA8BggrBgEFBQcwAoYwaHR0cDovL3Rlc3RjYS5w -eXRob250ZXN0Lm5ldC90ZXN0Y2EvcHljYWNlcnQuY2VyMDUGCCsGAQUFBzABhilo -dHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9vY3NwLzBDBgNVHR8E -PDA6MDigNqA0hjJodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9y -ZXZvY2F0aW9uLmNybDANBgkqhkiG9w0BAQsFAAOCAYEAckKm/O48IUcFM+iMaycH -Su3igUeWeUP/D+9aBqpMAXBbIcS3XRcpyBACwwh7jIZWnul8bqi2JhOeHh+TZoVn -Y54I+1U5VoL1vgw4HuvEVLKnexhVuwCHQ1BQu+EpEM89yQfH0l22RWgf1t4Alj4p -c/YicCGiumgolOw3vKcAcFhO0Uiu740RpG4QL5KDB+J2rL9Pu9afR56kAgMW+KgK -PWcXMUQOaNDTJNXnv2cwj4iXkgoe13TffntMxtnDhJIroIkRCEzdMknfNiPUY1bk -8Whab6DDPOI27vNGYHhNdqVaSmHG+K4YaMKNDi92ULu+uVbxBFysrdfWpB5FRVL0 -EKIPm+PZcxe2UkKmW8npjWB0aNAfes4Bjp5Vy89kwcyacqq0X7VVE0EQUaAspVtD -EsrMt8Ss8m9y/Q1QataBwZGTIf7emr7lPCqYlaFC+PJcdcbx/RGxIiYzW0NjIQZh -0s0E8zDGqD8X0wWjh0UuUh5RiONZTHhRsHu0WNknIm6M +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowXTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4 +MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEQMA4GA1UEAwwH +YWxsc2FuczCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAJgRj6UjBL/D +6ABTk9/FJ4viowXlO0WSuJ8vShBoKNYVvyN5fZFvW0po5vKtiZNRFVZsyQjUsk5B +Zi0aUA2jaa9/hUPXBln/H9ObKXF7cDuK1JNmBm4Zcse0U/3CTvJLjoGVVw2rdmg6 +LuSTw3FOJSqCyYuDc2P4h+Tw4jtzUFw/alrXBk7+Xc9Naq0VIuwUS84rk3pk+ogs +BSLm8SQ6IV5/FUce8Pg3chZIWBLCIOL0qGe11HBr5rGxnGOr+jvQWNA7mrlC7Kb1 +oOqqjjs8zKQRvWB1MFArWY+WIwqwuLnPJwj/KmbU8Rwfnf738X5TYHVua8D/08HH +xPuFTJyUFtAcKZ1xchgKAWvkBsZLeMV5U+IXuEI+PWT+NylrJdkC1aaolOWRcoZs +zrwCAz8Mc7R8YJgZFTDa+FXdkhEKbQGrB+it4WH7agzJmMOO+j+5mNk1rN2lzC87 +LRyUWQ5HBUjTNMiLFdhJXjE3UFfzbUkK6Fi5uujz2b4xKPE7XiqCzQIDAQABo4IC +3jCCAtowggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBv +dGhlciBpZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2h +FTAToAMCAQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4 +YW1wbGUub3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRo +cmF4MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UE +AwwPZGlybmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAA +AYcQAAAAAAAAAAAAAAAAAAAAAYgEKgMEBTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l +BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYE +FHMNTh9K7PJTD1P8hW/Pgs2j6BGNMH0GA1UdIwR2MHSAFMAKKyhD3l/JfUflR5s2 +8mWMZzvioVGkTzBNMQswCQYDVQQGEwJYWTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3 +YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1jYS1zZXJ2ZXKCCQDLLYCZ +WmlSWzCBgwYIKwYBBQUHAQEEdzB1MDwGCCsGAQUFBzAChjBodHRwOi8vdGVzdGNh +LnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9weWNhY2VydC5jZXIwNQYIKwYBBQUHMAGG +KWh0dHA6Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL29jc3AvMEMGA1Ud +HwQ8MDowOKA2oDSGMmh0dHA6Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNh +L3Jldm9jYXRpb24uY3JsMA0GCSqGSIb3DQEBCwUAA4IBgQClPRKHuTs+nBxZ+9U4 +Iklh88MRU0tOY6/yPe8kZ0W8dFxKZcW0u/6EuLbKffyq/4CuZx/Lw82P+XWM+dM/ +2/aB2AZCw12pHqOBfVesl9m9yM4e7HTXlNXfsa3OhBRcjEWkqOtnqxZXYRWGrhEe +tRBC3oR2iJs3Eqqmd0J1tMAEs3VF4NeqNOMHxe34TvA5mR9b2E4MrWRtCQc/4+Gf +G2UHllmatfFNw+z3MqEFlNELGFQ8Z8849Svsy715vvcbt3E/xkSAfwDcPaAHwLUc ++1L2oPiSxsZzB8XKCwR8VVHjupMyF71hrs8T5F4DslERx2j1CLYOV0kRPOP0DuGW +IEQoMZQRRFDPF3CNnBTF7ZRNupSb24ufVaFeCpC7oA4NO6DdTUfRz9BHa/9vr+SD +QHPmOllAvU86ISJjJ10CJmeJHS8ZxXfmtWdK3bUO3kY0V8cDhF3NNAiPR8lNfwTA +T/9oUruuhA5UzlwncQ+iP596Saj6CkXPlkKnZSO5PkDrRns= -----END CERTIFICATE----- diff --git a/Lib/test/certdata/capath/b1930218.0 b/Lib/test/certdata/capath/b1930218.0 index aa9dbbe294f829..6d773ee5b32432 100644 --- a/Lib/test/certdata/capath/b1930218.0 +++ b/Lib/test/certdata/capath/b1930218.0 @@ -1,27 +1,27 @@ -----BEGIN CERTIFICATE----- -MIIEgDCCAuigAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIEgjCCAuqgAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg -Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCAaIwDQYJKoZI -hvcNAQEBBQADggGPADCCAYoCggGBANCgm7G5O3nuMS+4URwBde0JWUysyL9qCvh6 -CPAl4yV7avjE2KqgYAclsM9zcQVSaL8Gk64QYZa8s2mBGn0Z/CCGj5poG+3N4mxh -Z8dOVepDBiEb6bm+hF/C2uuJiOBCpkVJKtC5a4yTyUQ7yvw8lH/dcMWt2Es73B74 -VUu1J4b437CDz/cWN78TFzTUyVXtaxbJf60gTvAe2Ru/jbrNypbvHmnLUWZhSA3o -eaNZYdQQjeANOwuFttWFEt2lB8VL+iP6VDn3lwvJREceVnc8PBMBC2131hS6RPRT -NVbZPbk+NV/bM5pPWrk4RMkySf5m9h8al6rKTEr2uF5Af/sLHfhbodz4wC7QbUn1 -0kbUkFf+koE0ri04u6gXDOHlP+L3JgVUUPVksxxuRP9vqbQDlukOwojYclKQmcZB -D0aQWbg+b9Linh02gpXTWIoS8+LYDSBRI/CQLZo+fSaGsqfX+ShgA+N3x4gEyf6J -d3AQT8Ogijv0q0J74xSS2K4W1qHefQIDAQABo2MwYTAdBgNVHQ4EFgQU8+yUjvKO -MMSOaMK/jmoZwMGfdmUwHwYDVR0jBBgwFoAU8+yUjvKOMMSOaMK/jmoZwMGfdmUw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD -ggGBAIsAVHKzjevzrzSf1mDq3oQ/jASPGaa+AmfEY8V040c3WYOUBvFFGegHL9ZO -S0+oPccHByeS9H5zT4syGZRGeiXE2cQnsBFjOmCLheFzTzQ7a6Q0jEmOzc9PsmUn -QRmw/IAxePJzapt9cTRQ/Hio2gW0nFs6mXprXe870+k7MwESZc9eB9gZr9VT6vAQ -rMS2Jjw0LnTuZN0dNnWJRACwDf0vswHMGosCzWzogILKv4LXAJ3YNhXSBzf8bHMd -2qgc6CCOMnr+bScW5Fhs6z7w/iRSKXG4lntTS0UgVUBehhvsyUaRku6sk2WRLpS2 -tqzoozSJpBoSDU1EpVLti5HuL6avpJUl+c7HW6cA05PKtDxdTfexPMxttEW+gu0Y -kMiG0XVRUARM6E/S1lCqdede/6F7Jxkca0ksbE1rY8w7cwDzmSbQgofTqTactD25 -SGiokvAnjgzNFXZChIDJP6N+tN3X+Kx2umCXPFofTt5x7gk5EN0x1WhXXRrlQroO -aOZF0w== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5dGhvbiBTb2Z0d2Fy +ZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2VydmVyMIIBojANBgkq +hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA5rri5MHCDBw+Yti5XFcuUriDxYg65pp6 +9WQWM+s3bi9782gDRWVHXXEQWcorGwBsgRRh9IZZP+r9eDcWnUPxxPZpjMUpBoie +JiIErATYhzRIOetr8guSqsNuY1FRa8Kt/1zIL7IbnCCKQD6iL2rqyNk3Q1zc7ZLi +2UDSYZ9xivXtObqoXj61IWMQ2G+04hEBCxDou/ti70hVvPXSnKtorpUlGfKXfRrc +ZuqIXobky8tpTV6wo/tsMeQoYF6Q8dQuEFDhhfANXL3dRSQIGT4ck2aPK9pTfQQc +DkLEaF6mzakY7afNatDRhrqQ/7dM3sdDJG3HHGucgefhG1clkKkOyVbz9mteLbQu +QFCbQmPS1pkcONzPKyyncvHHXmM0dkj0PogTnoYWUy90+4cBjSKkaDPuE2x6BhRU +VhdXV5g00AtmCeOICfilFRwQc9CIUJleGGU7/zEnG17GqkH9LS8Yp8Dyq8citQtp +0nPRu9AcPfqkNWLNM4bHoCMPuWrV0m2NAgMBAAGjYzBhMB0GA1UdDgQWBBTACiso +Q95fyX1H5UebNvJljGc74jAfBgNVHSMEGDAWgBTACisoQ95fyX1H5UebNvJljGc7 +4jAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF +AAOCAYEAvONWIgPkXLln/5S8dZwAhbDVnMTDKWZei7KppjCGcRpr8gDFgqtfUAQq +++24TLkAG0lXkhHNorzLD6i0YfgUyqDsQBe6VaHEvKayWu/0IBB3R9CgxVi5bLUQ +e4VKQ6P7LAG5dxewvqDurq5NZ4ZIiVeGeOo87fBBNY1xaFX58umsMtTGou/sVObE +jiz9vapgVmUzleoQxnQE6ypumxH2YQCq/ezyC7FLEc2T69+Yrky0BwRK5e//Ulh1 +9T6kceFKclypj9SqiPBqcbTDAF+ZbteRr2yYDWTCJMeeBRFoXiRi4y5F7KM08qOd +TeUyGC90/BHxNlBPoEApaFxDTCNsXXLE7FJ269yyvB+mxAZmm1zHzMry0SVP3qUf +jeQMSbbPhUChuR/GxxkVB2M0k9BXoFpw7K9KHHIXHXSjbDFFCzN6obhG28cOZExv +t5kEgkMf4FnWmSEnKAlArvzEI6qgDAgFKpIc2yOe0dVjrjkToxKIWkM8Sm4y8ISf ++QkMkee4 -----END CERTIFICATE----- diff --git a/Lib/test/certdata/capath/ceff1710.0 b/Lib/test/certdata/capath/ceff1710.0 index aa9dbbe294f829..6d773ee5b32432 100644 --- a/Lib/test/certdata/capath/ceff1710.0 +++ b/Lib/test/certdata/capath/ceff1710.0 @@ -1,27 +1,27 @@ -----BEGIN CERTIFICATE----- -MIIEgDCCAuigAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIEgjCCAuqgAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg -Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCAaIwDQYJKoZI -hvcNAQEBBQADggGPADCCAYoCggGBANCgm7G5O3nuMS+4URwBde0JWUysyL9qCvh6 -CPAl4yV7avjE2KqgYAclsM9zcQVSaL8Gk64QYZa8s2mBGn0Z/CCGj5poG+3N4mxh -Z8dOVepDBiEb6bm+hF/C2uuJiOBCpkVJKtC5a4yTyUQ7yvw8lH/dcMWt2Es73B74 -VUu1J4b437CDz/cWN78TFzTUyVXtaxbJf60gTvAe2Ru/jbrNypbvHmnLUWZhSA3o -eaNZYdQQjeANOwuFttWFEt2lB8VL+iP6VDn3lwvJREceVnc8PBMBC2131hS6RPRT -NVbZPbk+NV/bM5pPWrk4RMkySf5m9h8al6rKTEr2uF5Af/sLHfhbodz4wC7QbUn1 -0kbUkFf+koE0ri04u6gXDOHlP+L3JgVUUPVksxxuRP9vqbQDlukOwojYclKQmcZB -D0aQWbg+b9Linh02gpXTWIoS8+LYDSBRI/CQLZo+fSaGsqfX+ShgA+N3x4gEyf6J -d3AQT8Ogijv0q0J74xSS2K4W1qHefQIDAQABo2MwYTAdBgNVHQ4EFgQU8+yUjvKO -MMSOaMK/jmoZwMGfdmUwHwYDVR0jBBgwFoAU8+yUjvKOMMSOaMK/jmoZwMGfdmUw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD -ggGBAIsAVHKzjevzrzSf1mDq3oQ/jASPGaa+AmfEY8V040c3WYOUBvFFGegHL9ZO -S0+oPccHByeS9H5zT4syGZRGeiXE2cQnsBFjOmCLheFzTzQ7a6Q0jEmOzc9PsmUn -QRmw/IAxePJzapt9cTRQ/Hio2gW0nFs6mXprXe870+k7MwESZc9eB9gZr9VT6vAQ -rMS2Jjw0LnTuZN0dNnWJRACwDf0vswHMGosCzWzogILKv4LXAJ3YNhXSBzf8bHMd -2qgc6CCOMnr+bScW5Fhs6z7w/iRSKXG4lntTS0UgVUBehhvsyUaRku6sk2WRLpS2 -tqzoozSJpBoSDU1EpVLti5HuL6avpJUl+c7HW6cA05PKtDxdTfexPMxttEW+gu0Y -kMiG0XVRUARM6E/S1lCqdede/6F7Jxkca0ksbE1rY8w7cwDzmSbQgofTqTactD25 -SGiokvAnjgzNFXZChIDJP6N+tN3X+Kx2umCXPFofTt5x7gk5EN0x1WhXXRrlQroO -aOZF0w== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5dGhvbiBTb2Z0d2Fy +ZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2VydmVyMIIBojANBgkq +hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA5rri5MHCDBw+Yti5XFcuUriDxYg65pp6 +9WQWM+s3bi9782gDRWVHXXEQWcorGwBsgRRh9IZZP+r9eDcWnUPxxPZpjMUpBoie +JiIErATYhzRIOetr8guSqsNuY1FRa8Kt/1zIL7IbnCCKQD6iL2rqyNk3Q1zc7ZLi +2UDSYZ9xivXtObqoXj61IWMQ2G+04hEBCxDou/ti70hVvPXSnKtorpUlGfKXfRrc +ZuqIXobky8tpTV6wo/tsMeQoYF6Q8dQuEFDhhfANXL3dRSQIGT4ck2aPK9pTfQQc +DkLEaF6mzakY7afNatDRhrqQ/7dM3sdDJG3HHGucgefhG1clkKkOyVbz9mteLbQu +QFCbQmPS1pkcONzPKyyncvHHXmM0dkj0PogTnoYWUy90+4cBjSKkaDPuE2x6BhRU +VhdXV5g00AtmCeOICfilFRwQc9CIUJleGGU7/zEnG17GqkH9LS8Yp8Dyq8citQtp +0nPRu9AcPfqkNWLNM4bHoCMPuWrV0m2NAgMBAAGjYzBhMB0GA1UdDgQWBBTACiso +Q95fyX1H5UebNvJljGc74jAfBgNVHSMEGDAWgBTACisoQ95fyX1H5UebNvJljGc7 +4jAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF +AAOCAYEAvONWIgPkXLln/5S8dZwAhbDVnMTDKWZei7KppjCGcRpr8gDFgqtfUAQq +++24TLkAG0lXkhHNorzLD6i0YfgUyqDsQBe6VaHEvKayWu/0IBB3R9CgxVi5bLUQ +e4VKQ6P7LAG5dxewvqDurq5NZ4ZIiVeGeOo87fBBNY1xaFX58umsMtTGou/sVObE +jiz9vapgVmUzleoQxnQE6ypumxH2YQCq/ezyC7FLEc2T69+Yrky0BwRK5e//Ulh1 +9T6kceFKclypj9SqiPBqcbTDAF+ZbteRr2yYDWTCJMeeBRFoXiRi4y5F7KM08qOd +TeUyGC90/BHxNlBPoEApaFxDTCNsXXLE7FJ269yyvB+mxAZmm1zHzMry0SVP3qUf +jeQMSbbPhUChuR/GxxkVB2M0k9BXoFpw7K9KHHIXHXSjbDFFCzN6obhG28cOZExv +t5kEgkMf4FnWmSEnKAlArvzEI6qgDAgFKpIc2yOe0dVjrjkToxKIWkM8Sm4y8ISf ++QkMkee4 -----END CERTIFICATE----- diff --git a/Lib/test/certdata/cert3.pem b/Lib/test/certdata/cert3.pem index 4ab0f5ff133e3f..a11dc614657d2f 100644 --- a/Lib/test/certdata/cert3.pem +++ b/Lib/test/certdata/cert3.pem @@ -1,34 +1,34 @@ -----BEGIN CERTIFICATE----- -MIIF8TCCBFmgAwIBAgIJAMstgJlaaVJcMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIF8zCCBFugAwIBAgIJAMstgJlaaVJcMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj -MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxv -Y2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKAqKHEL7aDt -3swl8hQF8VaK4zDGDRaF3E/IZTMwCN7FsQ4ejSiOe3E90f0phHCIpEpv2OebNenY -IpOGoFgkh62r/cthmnhu8Mn+FUIv17iOq7WX7B30OSqEpnr1voLX93XYkAq8LlMh -P79vsSCVhTwow3HZY7krEgl5WlfryOfj1i1TODSFPRCJePh66BsOTUvV/33GC+Qd -pVZVDGLowU1Ycmr/FdRvwT+F39Dehp03UFcxaX0/joPhH5gYpBB1kWTAQmxuqKMW -9ZZs6hrPtMXF/yfSrrXrzTdpct9paKR8RcufOcS8qju/ISK+1P/LXg2b5KJHedLo -TTIO3yCZ4d1odyuZBP7JDrI05gMJx95gz6sG685Qc+52MzLSTwr/Qg+MOjQoBy0o -8fRRVvIMEwoN0ZDb4uFEUuwZceUP1vTk/GGpNQt7ct4ropn6K4Zta3BUtovlLjZa -IIBhc1KETUqjRDvC6ACKmlcJ/5pY/dbH1lOux+IMFsh+djmaV90b3QIDAQABo4IB -wDCCAbwwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA4GA1UdDwEB/wQEAwIFoDAdBgNV -HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E -FgQUP7HpT6C+MGY+ChjID0caTzRqD0IwfQYDVR0jBHYwdIAU8+yUjvKOMMSOaMK/ -jmoZwMGfdmWhUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcoIJAMst -gJlaaVJbMIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly90ZXN0 -Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1BggrBgEFBQcw -AYYpaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2NzcC8wQwYD -VR0fBDwwOjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0 -Y2EvcmV2b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGBAMo0usXQzycxMtYN -JzC42xfftzmnu7E7hsQx/fur22MazJCruU6rNEkMXow+cKOnay+nmiV7AVoYlkh2 -+DZ4dPq8fWh/5cqmnXvccr2jJVEXaOjp1wKGLH0WfLXcRLIK4/fJM6NRNoO81HDN -hJGfBrot0gUKZcPZVQmouAlpu5OGwrfCkHR8v/BdvA5jE4zr+g/x+uUScE0M64wu -okJCAAQP/PkfQZxjePBmk7KPLuiTHFDLLX+2uldvUmLXOQsJgqumU03MBT4Z8NTA -zqmtEM65ceSP8lo8Zbrcy+AEkCulFaZ92tyjtbe8oN4wTmTLFw06oFLSZzuiOgDV -OaphdVKf/pvA6KBpr6izox0KQFIE5z3AAJZfKzMGDDD20xhy7jjQZNMAhjfsT+k4 -SeYB/6KafNxq08uoulj7w4Z4R/EGpkXnU96ZHYHmvGN0RnxwI1cpYHCazG8AjsK/ -anN9brBi5twTGrn+D8LRBqF5Yn+2MKkD0EdXJdtIENHP+32sPQ== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowXzELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4 +MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJ +bG9jYWxob3N0MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA7jZwqmFq +ILsyiAdz8DrKEcyPMIDXccd0YiCUiLRSEpQIAeF5GMzwaYuZxUfBgqquyFEEPomM +HWWt8h+l9dSHZawseIA3UBUhTnoJxuNaKr+xsARBb6usZaMKaGhsPuf/P7CV/1VO +OKy/f34jFU23oTITEv8+Z00mEgAle7EV58FuE+pdjne+xczwY52hRQza+RiKIg+J +jUid+bdObZYhnM9CMhOUxkepCBBTSB+bYXh6CSeCQuLi8licHiacQ8ddJ41kcCjf +7V5vBZx0DzEQFJdsDNO0GRCNcn81K9NP6BtnaT5z8jYfuqdpXfCUtINvz3dqUC/D +rZjNnA3DeRPqghFtVFSCef/2nfKVHKEMMkSAUTiW2pKr+hXFU3YE6IKKuVbvk+k1 +RS0iEr1b6bFdDLU/x/f/U7Qp6jsJYhPLPJG9zY0E/Hu9lRzXeN21TxOA3kPl5WzK +Cs1fhjpkh0n80jmQfZEnEphneWA/O/N02y/P+zZ9REUHVqmosRiN+vgRAgMBAAGj +ggHAMIIBvDAUBgNVHREEDTALgglsb2NhbGhvc3QwDgYDVR0PAQH/BAQDAgWgMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1Ud +DgQWBBQWIsmqINT0ju2cprsj9fIpRO3yHjB9BgNVHSMEdjB0gBTACisoQ95fyX1H +5UebNvJljGc74qFRpE8wTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5dGhvbiBT +b2Z0d2FyZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2VydmVyggkA +yy2AmVppUlswgYMGCCsGAQUFBwEBBHcwdTA8BggrBgEFBQcwAoYwaHR0cDovL3Rl +c3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2EvcHljYWNlcnQuY2VyMDUGCCsGAQUF +BzABhilodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9vY3NwLzBD +BgNVHR8EPDA6MDigNqA0hjJodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rl +c3RjYS9yZXZvY2F0aW9uLmNybDANBgkqhkiG9w0BAQsFAAOCAYEAQ4IfGLTLerdO +rMNlLrdXOvB4s7IgPr17JPfnF8xiwLhj8C4wDFS+yZR8VNRABm6SnXIsRPXjwUo/ +JuQhyrrvT6NQVu6JXNxbmLwM6dsWmPBMP2W52eAuvYOexxv3T4dfdf9nXQr/zvoL +8dWLWCMrkie4Ff9mwvlo4u1koErgQousNWpnZPXLqQA3IFbdOgJu2A+0Xf+Sow1l +/C6rTje8ftZbHFV4oG6pLlUxz2HwG0z+/mB1dujZofUU8EMzTVIFvjP/2jGUvQ3l +Taju0fOSNMI2kTc6bewg37Oeol3Q8KHi/7eFzgnjyEpqk6Su7MFnQveOL2TK13Zy +vz/vZP8Q3aI+LfWqAs8x8G2Ta1ZMsIiVVNzUrNzBiCeL2ZxOZpP43V50QSaa7+jI +RlzV9PzNzGfHM2IucJvROd40/a2duUhh54lTYmLwQGxoL+HaQGEqUK/JQW2YFq/L +YwPsBJngOZhgrqpqV5slcwMWv3jI1y/r/GR/x3iMNBVbZkCYhuYK -----END CERTIFICATE----- diff --git a/Lib/test/certdata/idnsans.pem b/Lib/test/certdata/idnsans.pem index 07a42422af1fd3..ebd7250cb4eae9 100644 --- a/Lib/test/certdata/idnsans.pem +++ b/Lib/test/certdata/idnsans.pem @@ -1,42 +1,42 @@ -----BEGIN PRIVATE KEY----- -MIIG/AIBADANBgkqhkiG9w0BAQEFAASCBuYwggbiAgEAAoIBgQCp6zt40WB3K7yj -BGugnRuqI3ApftThZWDIpvW0cVmN0nqQxsO6CCnS4dS7SYhGFiIqWjNVc2WG0gv7 -nC5DFguqbndNZk9/SjX8EOxKz4ANjd61WnTkDO5Tbiiyd+TuEBxhmbEF69bF9dtd -1Sgo8jmM7j+aa6ClYh/49bx+blJDF76EGSrmB1q+obMeZURhPXNBeoiqKR83x5Hc -LTJYMocvb6m8uABwuSka13Gb3QGu06p5ldK6TDK38HsoOy6MFO5F1PrkakG/eBHO -jcBOGPfNmTwWOqvwlcQWykr4QspWS+yTzdkgZ+mxar/yQuq7wuYSNaEfGH5yoYtV -WIgKwwZRDPqpSQuVe+J+MWLPQ6RTM+rXIHVzHtPk1f8DrgN+hSepJy/sVBBEQCzj -nyB+scn76ETWch3iyVoMj3oVOGs0b4XTDMmUw/DmEt5TDah7TqE3G+fpBIbgMSjx -MzUQZl27izmM9nQCJRAosNoNwXqlM754K9WcY6gT8kkcj1CfTmMCAwEAAQKCAYAz -9ZdHkDsf5fN2pAznXfOOOOz8+2hMjmwkn42GAp1gdWr+Z5GFiyaC8oTTSp6N1AnZ -iqCk8jcrHYMFi1JIOG8TzFjWBcGsinxsmp4vGDmvq2Ddcw5IiD2+rHJsdKZAOBP9 -snpD9cTE3zQYAu0XbE617krrxRqoSBO/1SExRjoIgzPCgFGyarBQl/DGjC/3Tku2 -y6oL4qxFqdTMD9QTzUuycUJlz5xu2+gaaaQ3hcMUe2xnZq28Qz3FKpf2ivZmZqWf -4+AIe0lRosmFoLAFjIyyuGCkWZ2t9KDIZV0OOS4+DvVOC/Um9r4VojeikripCGKY -2FzkkuQP3jz6pJ1UxCDg7YXZdR2IbcS18F1OYmLViU8oLDR6T01s0Npmp39dDazf -A4U+WyV3o1ydiSpwAiN8pJadmr5BHrCSmawV8ztW5yholufrO+FR5ze2+QG99txm -6l7lUI8Nz01lYG6D10MjaQ9INk2WSjBPVNbfsTl73/hR76/319ctfOINRMHilJ0C -gcEAvFgTdc5Qf9E7xEZE5UtpSTPvZ24DxQ7hmGW3pTs6+Nw4ccknnW0lLkWvY4Sf -gXl4TyTTUhe6PAN3UHzbjN2vdsTmAVUlnkNH40ymF8FgRGFNDuvuCZvf5ZWNddSl -6Vu/e5TFPDAqS8rGnl23DgXhlT+3Y0/mrftWoigdOxgximLAsmmqp/tANGi9jqE1 -3L0BN+xKqMMKSXkMtuzJHuini8MaWQgQcW/4czh4ArdesMzuVrstOD8947XHreY9 -pesVAoHBAOb0y/AFEdR+mhk/cfqjTzsNU2sS9yHlzMVgecF8BA26xcfAwg4d47VS -+LK8fV6KC4hHk4uQWjQzCG2PYXBbFT52xeJ3EC8DwWxJP09b4HV/1mWxXl5htjnr -dfyTmXKvEe5ZBpKGWc8i7s7jBi7R5EpgIfc586iNRyjYAk60dyG0iP13SurRvXBg -ID25VR4wABl3HQ3Hhv61dqC9FPrdHZQJdysfUqNrAFniWsSR2eyG5i4S1uHa3G+i -MzBTOuBRlwKBwBNXUBhG6YlWqTaMqMKLLfKwfKM4bvargost1uAG5xVrN/inWYQX -EzxfN5WWpvKa0Ln/5BuICD3ldTk0uS8MDNq7eYslfUl1S0qSMnQ6DXK4MzuXCsi9 -0w42f2JcRfVi0JUWP/LgV1eVKTRWF1g/Tl0PP/vY1q2DI/BfAjFxWJUHcxZfN4Es -kflP0Dd3YpqaZieiAkC2VrYY0i9uvXCJH7uAe5Is+9NKVk8uu1Q8FGM/iDIr4obm -J6rcnfbDsAz7yQKBwGtIbW9qO3UU9ioiQaTmtYg90XEclzXk1HEfNo+9NvjVuMfo -b3w1QDBbgXEtg6MlxuOgNBaRkIVM625ROzcA6GZir9tZ6Wede/z8LW+Ew0hxgLsu -YCLBiu9uxBj2y0HttwubySTJSfChToNGC/o1v7EY5M492kSCk/qSFMhQpkI+5Z+w -CVn44eHQlUl2zOY/79vka9eZxsiMrLVP/+3kRrgciYG7hByrOLeIIRfMlIl9xHDE -iZLSorEsjFC3aNMIswKBwFELC2fvlziW9rECQcGXnvc1DPmZcxm1ATFZ93FpKleF -TjLIWSdst0PmO8CSIuEZ2ZXPoK9CMJyQG+kt3k7IgZ1xKXg9y6ThwbznurXp1jaW -NjEnYtFMBK9Ur3oaAsrG2XwZ2PMvnI/Yp8tciGvjJlzSM8gHJ9BL8Yf+3gIJi/0D -KtaF9ha9J/SDDZdEiLIQ4LvSqYmlUgsCgiUvY3SVwCh8xDfBWD1hKw9vUiZu5cnJ -81hAHFgeD4f+C8fLols/sA== +MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDeGGysqNqsz64+ +xsN+CUZDfCgPPhzUK0lDUlkEkp0ZeFeQm3+po2Y82gvJIValO5ChiXjPxSgJwoto +SHe4QZ8fWAlkX1d19A8xjjetx1K3dqZstqe3mPP7HQvfJlRkmAtVhFaUj1+SUx9K +s4HB4Lk2hqKUoq3TlRMpeSfJTXaHThVP7KZPWBzfM7pdpGYnznBpxgfymNrpTcXN +CjeR6lUlj/TExHiYLj4E0aODR/SUz0tBNdCQRcRDw+OyREe6Rk32Krl34Pr1dNKe +ER0tulhM2wRFsqw0a8vNs13I30BH4aXAr5bGgLCF2tXbP3KoeoR/GkQSWV14KrhT +xhKD3QEJ8gHjoHYKr4IdcFYcTakbI9E3THsQjQTUMJ/Xygza7OOr6pNPKY10tYfp +7WhyyY7cB/C/rHnUY0f58IZlRdMYgcLCUl7wzUxSVEMyr9Ary8XZZlxuO629k2ud +AIGwIi2TVq+UK0kNPZyGicGHMeEhoNc3YDMB/zYeqMr4KryI+mkCAwEAAQKCAYA4 +EENSnHdC+1P5bdRIew/dFjjIjD3bwyeF0oI9GMOGe+3ix5YE3QYAY2xpM7y7Dhu2 +40x3akXunMjzJKPwA8SmtWL9juG1mUvCjyt39yJmxJFDTSJuQrKIF694/6R7FjR6 +PGNcsgqGlewGv+SH6/HlFTxyN9SYXf/NztMfyimbAzd3Cv56dfwnzdeELu1IrCCN +WtuDvlk4XpUJasRXVadzyXCYwR3OEJJARik4CRBxBhjxl6OT38Co+IiAZiMTHw6z +jXeRuvyxXyYB76BQs9uCt05c5JV1I2OT1aKdpC0EbHlJEzJhmxrpdfBeoVdJUVVg +4b0QoocZE89KXOVmjmIKExxmjOjxH6o6qfxvDQWLspADD4D+69Zqjj6hFAfn3EUW +hcq3RHwuUheCE6i2xRtWPnA1ygqWN9mdNojX1+EXIv0Dh29kFWHpMUC29WWm9JA6 +Arx2UrtvoWGYotKxTDxZ0SV5ws/LzGjvMaT/dbXZHjywnB7sPfpcE9b91p8Q6VcC +gcEA+Wr44ZzyMirF9FYYA+KEBL91khmffhXzCDkRXqd1j2BCQWETWqvrUuAx+kwh +FZ5AABdip96w8Eaj8XBWb1c81mJUbOimbcqiV6B4GokCI/7u3FkOMPFRNBq41R/M +43JH6QLHNxhXI4OlZsxv5WHmR5N88kXEHhofBoSn14EHtdkK/Hu8ly1Wux4/da83 +2wanwlysmQkk1CnpJVT0st7HrKHP8YWDbcBvH+xysHOIOs22q3gvAF2rsdORidpR +fZnHAoHBAOP03brYpLU1xa5LHQz/B7uWfgJm3l7wRQ627YOfUBe4IjnH2y/kNKjv +ROVjaooB2gtya6Z6xVuY1m4LzUfYuRN1FdX1Np4NjvfgPNFViX+0HoxyAytXn++V +Iy1tCpL6X43Iqrj/VxBcX09vIpbsprW2d3dcIo/45abkAO6Uoa6HUmZoqrqrBA7b +LnuhEfBAyyN42OiXbHDqif7XAWC30yY6k0FfDaOSLiBkAOKZ9lkf7ei3eNr4SdOa +Tf5a/RVKTwKBwB7YfOkiCM3tfkfGcffhBqSzrO2hn5jvS/wjWqOTIDXYGLmPMN6Q +zmyUb3nd+mV7Cb05JylNoCJHCjVsyDPC3TJCPOCvMQ349nTR0qitcwdSmuXDWb7x +yTIhb+Rjp2olkwEdJ9gHeZdZy5XYCKqcnecSNWyc9jEm19lthHhha7uwmOw6vUsQ +/13q0rxSLB05SHwADBRtDhHzEPNd+1k3tggChv3+ng9vsg6HpnNuBlYHZOT12xI3 +g2ldme0rg9J9twKBwA4R1gGrT3czy3C3iCJ+Ny732e0yBjWb5NdEqSI/mgTsw4gH +ctrg3fMzWXBDE5dTB+8+77AF0dqWc121csUldj7iMifTi7xzn8hi2b4d5m+wYVZP +zyxEq0VxUguCuG1b8Lvij879S5Vh7iwL8vmXv65lhbgjQqraNOp5FimjmNsZ1Rcn +DKqa1ZRJKPROe7n1ddRJqDGq7vGFOGE3Sgl7Lxgj82TMhh37bsdnBLr3v8G+e8Oq +V1ZEjuH1myzA1vASdwKBwQDcMHbUKeoJUxyIlABFsWxhm0MKwL5ZRgo7rhH01rF2 +TF3mbAEHHsAEfkHgBVRooifbxglxUDy1olIyRk+kqs1gmXZA0UmE9lUqoX5+n/j8 +pgbCc3sV53x7JJ4BCnAn49XTOnTi2ILeQ3MvTqcj+sDKo+0T4Zq0r5d8ZrMikKbO +HJ4MMBGth645QKhgpb0XgltvSn8aceS4uTxIKrbNpZVnWj/VzuOYoXQmKnZko9p1 +dbyjt6PMeVXWj0tz8FB2DGE= -----END PRIVATE KEY----- Certificate: Data: @@ -47,38 +47,38 @@ Certificate: Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Validity Not Before: Aug 29 14:23:16 2018 GMT - Not After : Oct 28 14:23:16 2037 GMT + Not After : Oct 28 14:23:16 2525 GMT Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=idnsans Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: - 00:a9:eb:3b:78:d1:60:77:2b:bc:a3:04:6b:a0:9d: - 1b:aa:23:70:29:7e:d4:e1:65:60:c8:a6:f5:b4:71: - 59:8d:d2:7a:90:c6:c3:ba:08:29:d2:e1:d4:bb:49: - 88:46:16:22:2a:5a:33:55:73:65:86:d2:0b:fb:9c: - 2e:43:16:0b:aa:6e:77:4d:66:4f:7f:4a:35:fc:10: - ec:4a:cf:80:0d:8d:de:b5:5a:74:e4:0c:ee:53:6e: - 28:b2:77:e4:ee:10:1c:61:99:b1:05:eb:d6:c5:f5: - db:5d:d5:28:28:f2:39:8c:ee:3f:9a:6b:a0:a5:62: - 1f:f8:f5:bc:7e:6e:52:43:17:be:84:19:2a:e6:07: - 5a:be:a1:b3:1e:65:44:61:3d:73:41:7a:88:aa:29: - 1f:37:c7:91:dc:2d:32:58:32:87:2f:6f:a9:bc:b8: - 00:70:b9:29:1a:d7:71:9b:dd:01:ae:d3:aa:79:95: - d2:ba:4c:32:b7:f0:7b:28:3b:2e:8c:14:ee:45:d4: - fa:e4:6a:41:bf:78:11:ce:8d:c0:4e:18:f7:cd:99: - 3c:16:3a:ab:f0:95:c4:16:ca:4a:f8:42:ca:56:4b: - ec:93:cd:d9:20:67:e9:b1:6a:bf:f2:42:ea:bb:c2: - e6:12:35:a1:1f:18:7e:72:a1:8b:55:58:88:0a:c3: - 06:51:0c:fa:a9:49:0b:95:7b:e2:7e:31:62:cf:43: - a4:53:33:ea:d7:20:75:73:1e:d3:e4:d5:ff:03:ae: - 03:7e:85:27:a9:27:2f:ec:54:10:44:40:2c:e3:9f: - 20:7e:b1:c9:fb:e8:44:d6:72:1d:e2:c9:5a:0c:8f: - 7a:15:38:6b:34:6f:85:d3:0c:c9:94:c3:f0:e6:12: - de:53:0d:a8:7b:4e:a1:37:1b:e7:e9:04:86:e0:31: - 28:f1:33:35:10:66:5d:bb:8b:39:8c:f6:74:02:25: - 10:28:b0:da:0d:c1:7a:a5:33:be:78:2b:d5:9c:63: - a8:13:f2:49:1c:8f:50:9f:4e:63 + 00:de:18:6c:ac:a8:da:ac:cf:ae:3e:c6:c3:7e:09: + 46:43:7c:28:0f:3e:1c:d4:2b:49:43:52:59:04:92: + 9d:19:78:57:90:9b:7f:a9:a3:66:3c:da:0b:c9:21: + 56:a5:3b:90:a1:89:78:cf:c5:28:09:c2:8b:68:48: + 77:b8:41:9f:1f:58:09:64:5f:57:75:f4:0f:31:8e: + 37:ad:c7:52:b7:76:a6:6c:b6:a7:b7:98:f3:fb:1d: + 0b:df:26:54:64:98:0b:55:84:56:94:8f:5f:92:53: + 1f:4a:b3:81:c1:e0:b9:36:86:a2:94:a2:ad:d3:95: + 13:29:79:27:c9:4d:76:87:4e:15:4f:ec:a6:4f:58: + 1c:df:33:ba:5d:a4:66:27:ce:70:69:c6:07:f2:98: + da:e9:4d:c5:cd:0a:37:91:ea:55:25:8f:f4:c4:c4: + 78:98:2e:3e:04:d1:a3:83:47:f4:94:cf:4b:41:35: + d0:90:45:c4:43:c3:e3:b2:44:47:ba:46:4d:f6:2a: + b9:77:e0:fa:f5:74:d2:9e:11:1d:2d:ba:58:4c:db: + 04:45:b2:ac:34:6b:cb:cd:b3:5d:c8:df:40:47:e1: + a5:c0:af:96:c6:80:b0:85:da:d5:db:3f:72:a8:7a: + 84:7f:1a:44:12:59:5d:78:2a:b8:53:c6:12:83:dd: + 01:09:f2:01:e3:a0:76:0a:af:82:1d:70:56:1c:4d: + a9:1b:23:d1:37:4c:7b:10:8d:04:d4:30:9f:d7:ca: + 0c:da:ec:e3:ab:ea:93:4f:29:8d:74:b5:87:e9:ed: + 68:72:c9:8e:dc:07:f0:bf:ac:79:d4:63:47:f9:f0: + 86:65:45:d3:18:81:c2:c2:52:5e:f0:cd:4c:52:54: + 43:32:af:d0:2b:cb:c5:d9:66:5c:6e:3b:ad:bd:93: + 6b:9d:00:81:b0:22:2d:93:56:af:94:2b:49:0d:3d: + 9c:86:89:c1:87:31:e1:21:a0:d7:37:60:33:01:ff: + 36:1e:a8:ca:f8:2a:bc:88:fa:69 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: @@ -90,9 +90,9 @@ Certificate: X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: - 5B:93:42:58:B0:B4:18:CC:41:4C:15:EB:42:33:66:77:4C:71:2F:42 + C8:06:99:B7:E8:8F:EC:4F:3D:5C:89:6A:06:F5:77:2E:B0:E0:6A:9E X509v3 Authority Key Identifier: - keyid:F3:EC:94:8E:F2:8E:30:C4:8E:68:C2:BF:8E:6A:19:C0:C1:9F:76:65 + keyid:C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server serial:CB:2D:80:99:5A:69:52:5B Authority Information Access: @@ -103,64 +103,64 @@ Certificate: URI:http://testca.pythontest.net/testca/revocation.crl Signature Algorithm: sha256WithRSAEncryption Signature Value: - 5f:d8:9b:dc:22:55:80:47:e1:9b:04:3e:46:53:9b:e5:a7:4a: - 8f:eb:53:01:39:d5:04:f6:cf:dc:48:84:8a:a9:c3:a5:35:22: - 2f:ab:74:77:ec:a6:fd:b1:e6:e6:74:82:38:54:0b:27:36:e6: - ec:3d:fe:92:1a:b2:7a:35:0d:a3:e5:7c:ff:e5:5b:1a:28:4b: - 29:1f:99:1b:3e:11:e9:e2:e0:d7:da:06:4f:e3:7b:8c:ad:30: - f4:39:24:e8:ad:2a:0e:71:74:ab:ed:62:e9:9f:85:7e:6a:b0: - bb:53:b4:d7:6b:b8:da:54:15:5c:9a:41:cf:61:f1:ab:67:d6: - 27:5c:0c:a3:d7:41:e7:27:3e:58:89:d6:1f:3f:2a:52:cc:13: - 0b:4b:e6:d6:ba:a0:c7:fd:e3:17:a4:b8:da:cc:cb:88:70:21: - 3b:70:df:09:40:6c:e7:02:81:08:80:b0:36:77:fb:44:c5:cf: - bf:19:54:7c:d1:4e:1f:a2:44:9e:d8:56:0e:bf:4b:0b:e0:84: - 6f:bc:f6:c6:7f:35:7a:17:ca:83:b3:82:c6:4e:d3:f3:d8:30: - 05:fd:6d:3c:8a:ab:63:55:6f:c5:18:ba:66:fe:e2:35:04:2b: - ae:76:34:f0:56:18:e8:54:db:83:b2:1b:93:0a:25:81:81:f0: - 25:ca:0a:95:be:8e:2f:05:3f:6c:e7:de:d1:7c:b8:a3:71:7c: - 6f:8a:05:c3:69:eb:6f:e6:76:8c:11:e1:59:0b:12:53:07:42: - 84:e8:89:ee:ab:7d:28:81:48:e8:79:d5:cf:a2:05:a4:fd:72: - 2c:7d:b4:1c:08:90:4e:0d:10:05:d1:9a:c0:69:4c:0a:14:39: - 17:fb:4d:5b:f6:42:bb:46:27:23:0f:5e:57:5b:b8:ae:9b:a3: - 0e:23:59:41:63:41:a4:f1:69:df:b3:a3:5c:10:d5:63:30:74: - a8:3c:0c:8e:1c:6b:10:e1:13:27:02:26:9b:fd:88:93:7e:91: - 9c:f9:c2:07:27:a4 + 40:d1:6d:8e:a2:0b:91:4b:a8:c4:08:d0:f3:f9:8b:d0:a3:0b: + dc:00:22:8c:f1:2e:2b:e5:e6:b4:6e:ce:9d:cf:59:32:66:6c: + bb:0e:3b:1d:9c:05:d2:eb:a6:29:f8:74:4f:dc:83:3b:32:5a: + 2c:67:86:61:25:bc:bd:19:eb:20:c6:30:69:0e:4c:b2:e3:18: + ca:9e:fe:40:bc:1c:ad:8b:03:f5:04:be:90:ce:27:27:2f:83: + 14:57:8d:4f:a0:db:46:ce:e0:7d:e2:cf:7d:ea:0c:fd:8d:00: + 27:0a:db:0d:5f:e7:1e:52:25:1f:64:b9:30:5f:07:1a:10:a3: + 69:35:0e:dc:f8:23:f7:34:07:ce:c8:92:94:39:4d:d5:c3:ab: + 33:aa:f9:67:be:66:18:ac:67:14:5f:93:5f:68:48:04:ed:1e: + c9:74:28:b2:47:34:49:11:e4:7b:38:32:e5:dc:40:13:b4:69: + 75:39:43:db:7c:4a:f0:2b:94:cd:01:ba:4d:9b:9e:68:b3:ee: + 03:9e:7f:9c:0c:cf:9c:5c:cb:d4:33:d5:f0:e3:21:54:9a:13: + 6f:eb:1a:0f:f3:8b:e8:ef:eb:34:ba:09:77:39:2a:8a:4b:e1: + 7e:9f:b5:05:be:95:b6:92:5d:4c:35:47:38:64:38:5e:27:b8: + f9:34:94:2f:57:16:b0:f5:6a:21:3f:09:34:b9:dd:f8:d1:47: + 2c:c7:5e:7f:63:49:f4:5b:f4:d9:ea:66:fc:aa:64:27:f0:72: + d7:94:6f:86:0f:e7:3b:b3:d4:d9:30:67:b8:a2:c3:f7:4d:07: + 44:b3:70:67:dd:b1:21:ac:7c:2a:04:7b:2c:1d:df:0b:82:a9: + fb:df:88:72:47:1c:f5:5d:a3:f7:52:22:2d:ea:f4:2a:45:4f: + 9b:9d:63:95:59:f3:79:05:2b:f1:5b:3b:62:71:69:90:30:d7: + 7a:b2:c8:ec:68:e5:94:bb:97:00:d0:95:a7:fd:04:6c:f7:8b: + 28:c1:96:9b:6a:94 -----BEGIN CERTIFICATE----- -MIIGvTCCBSWgAwIBAgIJAMstgJlaaVJgMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIGvzCCBSegAwIBAgIJAMstgJlaaVJgMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaMF0xCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj -MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2lk -bnNhbnMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCp6zt40WB3K7yj -BGugnRuqI3ApftThZWDIpvW0cVmN0nqQxsO6CCnS4dS7SYhGFiIqWjNVc2WG0gv7 -nC5DFguqbndNZk9/SjX8EOxKz4ANjd61WnTkDO5Tbiiyd+TuEBxhmbEF69bF9dtd -1Sgo8jmM7j+aa6ClYh/49bx+blJDF76EGSrmB1q+obMeZURhPXNBeoiqKR83x5Hc -LTJYMocvb6m8uABwuSka13Gb3QGu06p5ldK6TDK38HsoOy6MFO5F1PrkakG/eBHO -jcBOGPfNmTwWOqvwlcQWykr4QspWS+yTzdkgZ+mxar/yQuq7wuYSNaEfGH5yoYtV -WIgKwwZRDPqpSQuVe+J+MWLPQ6RTM+rXIHVzHtPk1f8DrgN+hSepJy/sVBBEQCzj -nyB+scn76ETWch3iyVoMj3oVOGs0b4XTDMmUw/DmEt5TDah7TqE3G+fpBIbgMSjx -MzUQZl27izmM9nQCJRAosNoNwXqlM754K9WcY6gT8kkcj1CfTmMCAwEAAaOCAo4w -ggKKMIHhBgNVHREEgdkwgdaCB2lkbnNhbnOCH3huLS1rbmlnLTVxYS5pZG4ucHl0 -aG9udGVzdC5uZXSCLnhuLS1rbmlnc2dzc2NoZW4tbGNiMHcuaWRuYTIwMDMucHl0 -aG9udGVzdC5uZXSCLnhuLS1rbmlnc2djaGVuLWI0YTNkdW4uaWRuYTIwMDgucHl0 -aG9udGVzdC5uZXSCJHhuLS1ueGFzbXE2Yi5pZG5hMjAwMy5weXRob250ZXN0Lm5l -dIIkeG4tLW54YXNtbTFjLmlkbmEyMDA4LnB5dGhvbnRlc3QubmV0MA4GA1UdDwEB -/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/ -BAIwADAdBgNVHQ4EFgQUW5NCWLC0GMxBTBXrQjNmd0xxL0IwfQYDVR0jBHYwdIAU -8+yUjvKOMMSOaMK/jmoZwMGfdmWhUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQK -DB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNh -LXNlcnZlcoIJAMstgJlaaVJbMIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKG -MGh0dHA6Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNl -cjA1BggrBgEFBQcwAYYpaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0 -Y2Evb2NzcC8wQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250 -ZXN0Lm5ldC90ZXN0Y2EvcmV2b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGB -AF/Ym9wiVYBH4ZsEPkZTm+WnSo/rUwE51QT2z9xIhIqpw6U1Ii+rdHfspv2x5uZ0 -gjhUCyc25uw9/pIasno1DaPlfP/lWxooSykfmRs+Eeni4NfaBk/je4ytMPQ5JOit -Kg5xdKvtYumfhX5qsLtTtNdruNpUFVyaQc9h8atn1idcDKPXQecnPliJ1h8/KlLM -EwtL5ta6oMf94xekuNrMy4hwITtw3wlAbOcCgQiAsDZ3+0TFz78ZVHzRTh+iRJ7Y -Vg6/SwvghG+89sZ/NXoXyoOzgsZO0/PYMAX9bTyKq2NVb8UYumb+4jUEK652NPBW -GOhU24OyG5MKJYGB8CXKCpW+ji8FP2zn3tF8uKNxfG+KBcNp62/mdowR4VkLElMH -QoToie6rfSiBSOh51c+iBaT9cix9tBwIkE4NEAXRmsBpTAoUORf7TVv2QrtGJyMP -XldbuK6bow4jWUFjQaTxad+zo1wQ1WMwdKg8DI4caxDhEycCJpv9iJN+kZz5wgcn -pA== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowXTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4 +MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEQMA4GA1UEAwwH +aWRuc2FuczCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAN4YbKyo2qzP +rj7Gw34JRkN8KA8+HNQrSUNSWQSSnRl4V5Cbf6mjZjzaC8khVqU7kKGJeM/FKAnC +i2hId7hBnx9YCWRfV3X0DzGON63HUrd2pmy2p7eY8/sdC98mVGSYC1WEVpSPX5JT +H0qzgcHguTaGopSirdOVEyl5J8lNdodOFU/spk9YHN8zul2kZifOcGnGB/KY2ulN +xc0KN5HqVSWP9MTEeJguPgTRo4NH9JTPS0E10JBFxEPD47JER7pGTfYquXfg+vV0 +0p4RHS26WEzbBEWyrDRry82zXcjfQEfhpcCvlsaAsIXa1ds/cqh6hH8aRBJZXXgq +uFPGEoPdAQnyAeOgdgqvgh1wVhxNqRsj0TdMexCNBNQwn9fKDNrs46vqk08pjXS1 +h+ntaHLJjtwH8L+sedRjR/nwhmVF0xiBwsJSXvDNTFJUQzKv0CvLxdlmXG47rb2T +a50AgbAiLZNWr5QrSQ09nIaJwYcx4SGg1zdgMwH/Nh6oyvgqvIj6aQIDAQABo4IC +jjCCAoowgeEGA1UdEQSB2TCB1oIHaWRuc2Fuc4IfeG4tLWtuaWctNXFhLmlkbi5w +eXRob250ZXN0Lm5ldIIueG4tLWtuaWdzZ3NzY2hlbi1sY2Iwdy5pZG5hMjAwMy5w +eXRob250ZXN0Lm5ldIIueG4tLWtuaWdzZ2NoZW4tYjRhM2R1bi5pZG5hMjAwOC5w +eXRob250ZXN0Lm5ldIIkeG4tLW54YXNtcTZiLmlkbmEyMDAzLnB5dGhvbnRlc3Qu +bmV0giR4bi0tbnhhc21tMWMuaWRuYTIwMDgucHl0aG9udGVzdC5uZXQwDgYDVR0P +AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB +Af8EAjAAMB0GA1UdDgQWBBTIBpm36I/sTz1ciWoG9XcusOBqnjB9BgNVHSMEdjB0 +gBTACisoQ95fyX1H5UebNvJljGc74qFRpE8wTTELMAkGA1UEBhMCWFkxJjAkBgNV +BAoMHVB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXIt +Y2Etc2VydmVyggkAyy2AmVppUlswgYMGCCsGAQUFBwEBBHcwdTA8BggrBgEFBQcw +AoYwaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2EvcHljYWNlcnQu +Y2VyMDUGCCsGAQUFBzABhilodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rl +c3RjYS9vY3NwLzBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vdGVzdGNhLnB5dGhv +bnRlc3QubmV0L3Rlc3RjYS9yZXZvY2F0aW9uLmNybDANBgkqhkiG9w0BAQsFAAOC +AYEAQNFtjqILkUuoxAjQ8/mL0KML3AAijPEuK+XmtG7Onc9ZMmZsuw47HZwF0uum +Kfh0T9yDOzJaLGeGYSW8vRnrIMYwaQ5MsuMYyp7+QLwcrYsD9QS+kM4nJy+DFFeN +T6DbRs7gfeLPfeoM/Y0AJwrbDV/nHlIlH2S5MF8HGhCjaTUO3Pgj9zQHzsiSlDlN +1cOrM6r5Z75mGKxnFF+TX2hIBO0eyXQoskc0SRHkezgy5dxAE7RpdTlD23xK8CuU +zQG6TZueaLPuA55/nAzPnFzL1DPV8OMhVJoTb+saD/OL6O/rNLoJdzkqikvhfp+1 +Bb6VtpJdTDVHOGQ4Xie4+TSUL1cWsPVqIT8JNLnd+NFHLMdef2NJ9Fv02epm/Kpk +J/By15Rvhg/nO7PU2TBnuKLD900HRLNwZ92xIax8KgR7LB3fC4Kp+9+Ickcc9V2j +91IiLer0KkVPm51jlVnzeQUr8Vs7YnFpkDDXerLI7GjllLuXANCVp/0EbPeLKMGW +m2qU -----END CERTIFICATE----- diff --git a/Lib/test/certdata/keycert.passwd.pem b/Lib/test/certdata/keycert.passwd.pem index 187021b8eeb9fa..1739a3525fee2b 100644 --- a/Lib/test/certdata/keycert.passwd.pem +++ b/Lib/test/certdata/keycert.passwd.pem @@ -1,69 +1,69 @@ -----BEGIN ENCRYPTED PRIVATE KEY----- -MIIHbTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIc17oH9riZswCAggA -MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDwi0Mkj59S0hplpnDSNHwPBIIH -EFGdZuO4Cwzg0bspLhE1UpBN5cBq1rKbf4PyVtCczIqJt3KjO3H5I4KdQd9zihkN -A1qzMiqVZOnQZw1eWFXMdyWuCgvNe1S/PRLWY3iZfnuZ9gZXQvyMEHy4JU7pe2Ib -GNm9mzadzJtGv0YZ05Kkza20zRlOxC/cgaNUV6TPeTSwW9CR2bylxw0lTFKBph+o -uFGcAzhqQuw9vsURYJf1f1iE7bQsnWU2kKmb9cx6kaUXiGJpkUMUraBL/rShoHa0 -eet6saiFnK3XGMCIK0mhS9s92CIQV5H9oQQPo/7s6MOoUHjC/gFoWBXoIDOcN9aR -ngybosCLtofY2m14WcHXvu4NJnfnKStx73K3dy3ZLr2iyjnsqGD1OhqGEWOVG/ho -QiZEhZ+9sOnqWI2OuMhMoQJNvrLj7AY4QbdkahdjNvLjDAQSuMI2uSUDFDNfkQdy -hqF/iiEM28PmSHCapgCpzR4+VfEfXBoyBCqs973asa9qhrorfnBVxXnvsqmKNLGH -dymtEPei9scpoftE5T9TPqQj46446bXk23Xpg8QIFa8InQC2Y+yZqqlqvzCAbN6S -Qcq1DcTSAMnbmBXVu9hPmJYIYOlBMHL8JGbsGrkVOhLiiIou4w3G+DyAvIwPj6j9 -BHLqa7HgUnUEC+zL4azVHOSMqmDsOiF3w9fkBWNSkOyNoZpe+gBjbxq7sp+GjAJv -1CemRC3LSoNzLcjRG2IEGs1jlEHSSfijvwlE4lEy3JVc+QK8BOkKXXDVhY1SQHcS -pniEnj95RFVmAujdFDBoUgySyxK/y6Ju/tHPpSTG9VMNbJTKTdBWAVWWHVJzBFhR -0Ug62VrBK7fmfUdH1b37aIxqsPND2De6WLm0RX+7r3XPDJ7hm+baKCchI5CvnG19 -ky8InhMbU4qV+9LceMETmNKKDkhKl4Zx/Y3nab7DG9s/RZfrTdCHojc9Va/t0Ykp -qlVrvdj/893CdI78SW3VjWBJGWfKMyT16hBMY3TPz6ulbFXk6Pul/KcLLWslghS+ -GKZjyBe96UwfH4C7WjuIB+zo+De3Wr8xOCdJR5zwEutBMM+L/Wul8B6wIEGS71kB -TN/CAoeIgHLQFbcw4YE80dllTnSEsqF+ahVTTcCt3iLUaOgeTUxteMbXY9+nekSX -x8aUcvkMhbU9omdEowFr5/HIMKXo4UXat4fIGgh2pG8v8fA46hZXkhWUh/PhbnQw -StXzn4fA13erqVI679kHMmOIQebv4oqdcwkImrH5fEsACNjQbkYZF5fD4z+1GHkA -e2eGqejVT+OV14I8qfx9oqs2f8aqijH8fYLU0TymE7p53DYZy4WvDwk22I4rMzoQ -sGkOZwfKUYpdBI2t6tEf1ROBjoNG0E2Onq+5iooibN08rKXKAQMWsK+2vNHNHwBW -49vRheQNnRqSuLY+b7QAjA0KuRWo9YptCbnXyF/Aw64jMfAGjggDLoaZfALGZk3n -P+ZoL9xc7rYRpIca44BeYI6AhHFcWWIOX7Sm69FvmyHlfsgTAXVgY1lQPuGy68Au -PHSkgUyydDtkrfb2W2gJuqD/+h+9X2z+o/+nETYPCZm3sH5xvTY/DTcTx9kTpXxx -YQBaFTt12eVX7wZVr5K3u9M371rg+SeXC2SzL4T6APHD52cxbA1jgM0JFh3KJTuk -fADxIzM1NdzYQ45J6i2w+/Fh4VPnXZ0oiUSwE094XTBlvhI6zHgar2Q0Qx1P51vB -odd9XzyDLULuIzei0DYjTIg0KhE+wAGq1I5qtiMhmy5TdCKKNA9WGb1Pq38zpyjU -wGmztzSzCEjfLyhChaUObVRRxEfD5ioxKer/fczOhKQe8FXmGy5u/04tVmmEyNOO -JkkDtZy+UbKuJ257QnY72wPjgtHNy+S4Iv7zHUbNJNhxk+xBlRcmRNWCEM20LBSO -Tj4S9gyan+gH2+WFxy8FaENUhM+vHFEeJcjQIBFBeWICmSmdkh/r0YK1UVJ9NLfR -l0HiKm3lKg+kNCexTAPLMt2rGZ4PAKVnhVaxtuHMYYDpl2GYmyH73B9BfcPdA/Zx -GUBmd9hwcLz9SuUg+fjHcogZRRRlcZlKhw3zUCsqHSCQXZCQm7mBlG/5C/7cM7wQ -IRtsNospLStOg51gv21ClQ+uWx30XEcwmnIfVoLl1vMaguuf1u5u3dWBD/UgmqiP -1Ym8jv0BF/AS+u/CtUpwe7ZWxFT0vbyi10xxIF7O07fwFa+5dME3ycZwcyiE95K1 -ftcHlGOIhuVBMSNZXC4I9LM+7IWy+hanUcK+v5RvwBDSJV3fnAOdfrka1L/HyEEb -x/FYKEiU/TAjXDw2NtZ2itpADTSG5KbdJSwPr01Ak7aE+QYe7TIKJhBDZXGQlqq8 -1wv77zyv7V5Xq2cxSEKgSqzB9fhYZCASe8+HWlV2T+Sd +MIIHdTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQEKGM7Z40p3TpyCvl +LTPLsQICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEJAwQy7HESbbXMoF +KXadaz8EggcQBlxqFXmWQ3YlUuWTTc+dUcmikIUmI8gUSB2doBxQWLkTzaNuQ/hj +uV/eU7VkNFswxrU1j+EEkoCAtClWrQ2aKTyQSM4YfhgN1vQJdOD8DypHtd0TaRS3 +VCSkJODqcWaCEc/Ypgb1KnB6UWhit1waPq4NVCZdiSF/ueRK9/iMlIRaejg61Qn+ +LVLcegWw47zTtCZKuZqFAO3PcvfC0cresGc6hrQrb9tjUyI9qCR6MeZSrHUJQ/Pb +T9e7OREQxCLxWEUb0/tMJH5k9HoG7waU5lELOyjGKXsflEIs+uBaWIssWp69KGLi +yas7BHZc8kxJNtigFQlmECZjoKvRxJWN4fOknxI8T+ttBovOtsIlVvocBfmH+Z2m +7a5VMBxD8Phk6zU4Pk0L2S6EIUCIYGS+kgHibgxZ58/QcoDZBrKOaJ/Md+Lhk2Rn +2JCuPe8CBTkB3V+xAJdaz7JAcgxz4TqwXFXA249lfYb8qY9XXcr67O83Cxwb95lu +skmxnhAKOwKIrhS1nKiefuwN5qOiA+nuPbJFadCOO5cdOSriG3s80ugDDvlPN8k6 +4b7XLulB38R2PdH/OHuF05QGQ3kOUbJWatMig+/09LNo9FiMaCczdIXQ6LGxcHc1 +G1Y3BqK17z3yULqHvxU4tIbj5Elt+X1mfKIfifmXBUujbz5rR1pBTfpnk+DFGcHZ +B/cXWFP0tDJAE7mvna3HimNDQMP58NbhZwFtFdU3H9R5n4R5MsYQ6+a+amQ0pZ1Y +XAaQ/iEg0WY8CEFO8zEvB9R05zMm6vycNtN8CbfBq9CJ0OaR1ymMW8pRVagsLDuh +D0T5ZtWZctE2+ImlwlpGDs91CX3zDxvW/3Bwf40PF4x7LJMt/tFzqQEovokvzhUw +0jX/kf42QhvydnDoxqczdVZOfbjHELA21U+JAeAAj9jhcCEYd50c2BVt4jhST6dP +pzNAqxc1RGwTU3K3nZkWKt4hMXPDGjb0pVqiOuPz/718Nsd6ck+Ko90gFX13mPLC +6FLPGjNUmE6f3TKjbRrQz3+IWMncCyo/JSWA85rldxD0XAem64h+2XppFWJsxJD5 +nH2prLckQUWBLljWNIQQyVuAWo0TVq3NCXDFGaP6GHNrZo9zZxDhxcp6v2Me3Mir +few9aQNb59Q1/A0qwiCf26Oe8JYTD14UCez41imxD+w721SO8jzLR80+ReemdwzE +B9fXh3T/lrCIDNB+F+GWA9wQUz8mzArKbhqQhl5gk39dnLahc4aN7GrkwL4hjhKW +O3X5bBdhhRlcub9SbXFC+tx/w6G/0roGMSvD7h8G/mw3QcUUwwDvOuI7qAqQ8FC+ +xcGWeHUiTGxp2t2gz8DSaeL2TbBMbHe+tRBmKlmmIrAq3AEllWzyze9ta5ZYt46P +njZzS+vbbA0mfcFAId7tQOjQ2/ygZePs5hg91revLzNMDRJ1IeBHnrVUuDA5D1HR +iFW+hhj1Lx1s0XAJBJcDos8xy/LZlRDLxJSHrMktZOELTYh7UZw4S2PNkOPms4kP +V4G6D/0wZh0t+T9zpH57ivLdyBQ2fsFwx3X3JfQkYmoFlwCz+uUb368TunQ/yZZY +fVh9Q9ndk6y6aor0wkORsBefVv3eN+2BDt6ZUpYu3Liim+W4C/SiKVfQ+5yDb/qe +KmX7kcmr/f13BWvEOUN4fzCMiw/N0aAgEejZQTwMgivvGSMcNaBiLfdvM6hmy7NE +uvgpLtK5v+YRcOLwiaVH7UL6Q61CJ+pcDNRvbJT/iVwidYUO16zTVR6NrtPhM62a +Ziq3Q77HD4D2KCRPEo3Xivc5RwITHeDgKHwpLRB00jiZ3iR0Wm5lI5VbyWLnmQ4x +CDPAZetJZGBkbhTmUVbL0m3HNLHfF9g+LWA23L9mRNCKRemL0c0UJRRJPaNDIx8p +8h27al4xI8nFav0TZLxmSw7mqnzyE7YAoe4EsmedOSXktHWN06dnczHu8AWrgNjY +Izv9XUmy9V5vsRG/lg09FyG/eZSgfs9rdmL/qeFXbbl2J33YTqrt6O3ZaEsgg42r +piZztung8Xro3VlFSAXZGrl7Z0AWwzaOvwreCxbAG1WtBmGgLrs98z627XgfBFYA +BPvJwn9f2GZzixiN6M8c2M5XueDE/Vpn4A/GKLJ8RXXxKtbGRXFfdF/M6mEgcpa1 +9pxAhzNTPaOp+SFbm/cFa43HZYZgDg1D9zth2ZII0ZITd5OpEaSNOsrOrhqXeVQU +isBpybgPqVQ50xUuRUyoHYAZClVe6+PBYVbvlXBlTWhSPY3leUm4AYt+fjZ4VFlb +p4I2KRmd68zXXwl2spkEsC96e9k28kHta55dO32gSwaXUUHRKnFmKB24jsleF6n3 +BOKxzsO9jr6vi0jUqZXvaCnmYWqS84wZH/1S1pgotaWdMQ/KT27xwHk= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIEgzCCAuugAwIBAgIUU+FIM/dUbCklbdDwNPd2xemDAEwwDQYJKoZIhvcNAQEL +MIIEhTCCAu2gAwIBAgIUTxhwRX6zBQc3+l3imDklEbqcDpIwDQYJKoZIhvcNAQEL BQAwXzELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYD VQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJbG9jYWxo -b3N0MB4XDTIzMTEyNTA0MjEzNloXDTQzMDEyNDA0MjEzNlowXzELMAkGA1UEBhMC -WFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJbG9jYWxob3N0MIIBojANBgkqhkiG -9w0BAQEFAAOCAY8AMIIBigKCAYEAzXTIl1su11AGu6sDPsoxqcRGyAX0yjxIcswF -vj+eW/fBs2GcBby95VEOKpJPKRYYB7fAEAjAKK59zFdsDX/ynxPZLqyLQocBkFVq -tclhCRZu//KZND+uQuHSx3PjGkSvK/nrGjg5T0bkM4SFeb0YdLb+0aDTKGozUC82 -oBAilNcrFz1VXpEF0qUe9QeKQhyd0MaW5T1oSn+U3RAj2MXm3TGExyZeaicpIM5O -HFlnwUxsYSDZo0jUj342MbPOZh8szZDWi042jdtSA3i8uMSplEf4O8ZPmX0JCtrz -fVjRVdaKXIjrhMNWB8K44q6AeyhqJcVHtOmPYoHDm0qIjcrurt0LZaGhmCuKimNd -njcPxW0VQmDIS/mO5+s24SK+Mpznm5q/clXEwyD8FbrtrzV5cHCE8eNkxjuQjkmi -wW9uadK1s54tDwRWMl6DRWRyxoF0an885UQWmbsgEB5aRmEx2L0JeD0/q6Iw1Nta -As8DG4AaWuYMrgZXz7XvyiMq3IxVAgMBAAGjNzA1MBQGA1UdEQQNMAuCCWxvY2Fs -aG9zdDAdBgNVHQ4EFgQUl2wd7iWE1JTZUVq2yFBKGm9N36owDQYJKoZIhvcNAQEL -BQADggGBAF0f5x6QXFbgdyLOyeAPD/1DDxNjM68fJSmNM/6vxHJeDFzK0Pja+iJo -xv54YiS9F2tiKPpejk4ujvLQgvrYrTQvliIE+7fUT0dV74wZKPdLphftT9uEo1dH -TeIld+549fqcfZCJfVPE2Ka4vfyMGij9hVfY5FoZL1Xpnq/ZGYyWZNAPbkG292p8 -KrfLZm/0fFYAhq8tG/6DX7+2btxeX4MP/49tzskcYWgOjlkknyhJ76aMG9BJ1D7F -/TIEh5ihNwRTmyt023RBz/xWiN4xBLyIlpQ6d5ECKmFNFr0qnEui6UovfCHUF6lZ -qcAQ5VFQQ2CayNlVmQ+UGmWIqANlacYWBt7Q6VqpGg24zTMec1/Pqd6X07ScSfrm -MAtywrWrU7p1aEkN5lBa4n/XKZHGYMjor/YcMdF5yjdSrZr274YYO1pafmTFwRwH -5o16c8WPc0aPvTFbkGIFT5ddxYstw+QwsBtLKE2lJ4Qfmxt0Ew/0L7xkbK1BaCOo -EGD2IF7VDQ== +b3N0MCAXDTI0MTAwODExNTExMloYDzI0MDgwMTI5MTE1MTEyWjBfMQswCQYDVQQG +EwJYWTEXMBUGA1UEBwwOQ2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBT +b2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDDAlsb2NhbGhvc3QwggGiMA0GCSqG +SIb3DQEBAQUAA4IBjwAwggGKAoIBgQDwcIAYm12nmQTGB3caFn7alDe3LSliEfNC +2ZTR+5sh1eucQPbzgFM5SR4soKGElwI68Eg7g1kwqu3zmrI/FAiQI/RrUHyBZiEt +nFBPM44vY02XjUlJ9nBtgP7QjpRz6ZP0z1DrrojpYLVwg9cR0khTqD5cg2jvTB05 +yL9lQNk295/rMuueC9FaAQ+Y5la0ub7Lbe8gkYPotYliGx5qqCQmsXeTsxCpvQD7 +u0vBF9/nxlwywwzKGXabcN9YQhSECCC4c+eYjqoRgvAaF48xEnokxenzBIqZ82BR +kFo+zfNR+VhJRctNiZ6Ppa1Ise1H3LjZMDfY1S89QOLYsFXUp8L7ZMVE27Bej+Sq +4wEJ3soK/k1kr0YauqJ0lCEKkUPD9OeNHmczeakjj11tgtctsYbwgDSUYGA3w+DC +KD1aSfeuR3Hj89cSsVRrRrPFFih46Tr2PpTNoK6MtPH3RPJKV+Db8E1V2mXmNE0M +Lg6ramSHsD9iZXTLhG2JO+/876k3N3kCAwEAAaM3MDUwFAYDVR0RBA0wC4IJbG9j +YWxob3N0MB0GA1UdDgQWBBR459BlAel5MqCtG0DrvVtMZlQfuTANBgkqhkiG9w0B +AQsFAAOCAYEAaTFWjK/LFzOo+0TWqTTj4WC4N3I8JFrHnlqFJlpchYTW2z92SU1G +iEzFjWzuDNjp5KM9BqlmGtzXZvy6MItGkYsjPRdPVU0rbCmyTho6y77kTyiEG12V +UAJ1in3FOQfDwLPcp7wQRgCQq3iZlv7pwXp2Lm5fzu8kZPnxmTVdiKQun9Ps7uKq +BoM0fM2K14MxVO4Wc0SERnaPszE7xAhkIcs+NRT/gHYdTBlPhao83S3LOOdtCqCP +pNUOEaShlwI5bVsDPUXNX/eS0MYFNlsYTb5rCxK8jf3W3KNjKTOzN94pHiQOhpkg +xMPPi3m03/9oKTVXBtHI2A+u3ukheKE6sBXCLdv/GEs9zYI49zmpQxNWz5EOumWL +k+W/vPv7cD6LeHxxp+nCbEJi1gZtYb3gMY1sLkMNxcOu0QHTqHfme+k7VKWm8anO +3ogGdGtPuPAD/qjMwg3ChSDLl5Ur/E9UPlD4yM/7KtUD7mLv+jbddA62EiA9MxVB +t+yt7pOwOA66 -----END CERTIFICATE----- diff --git a/Lib/test/certdata/keycert.pem b/Lib/test/certdata/keycert.pem index a30d15ca4d61a6..43ad52c2af507b 100644 --- a/Lib/test/certdata/keycert.pem +++ b/Lib/test/certdata/keycert.pem @@ -1,67 +1,67 @@ -----BEGIN PRIVATE KEY----- -MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDNdMiXWy7XUAa7 -qwM+yjGpxEbIBfTKPEhyzAW+P55b98GzYZwFvL3lUQ4qkk8pFhgHt8AQCMAorn3M -V2wNf/KfE9kurItChwGQVWq1yWEJFm7/8pk0P65C4dLHc+MaRK8r+esaODlPRuQz -hIV5vRh0tv7RoNMoajNQLzagECKU1ysXPVVekQXSpR71B4pCHJ3QxpblPWhKf5Td -ECPYxebdMYTHJl5qJykgzk4cWWfBTGxhINmjSNSPfjYxs85mHyzNkNaLTjaN21ID -eLy4xKmUR/g7xk+ZfQkK2vN9WNFV1opciOuEw1YHwrjiroB7KGolxUe06Y9igcOb -SoiNyu6u3QtloaGYK4qKY12eNw/FbRVCYMhL+Y7n6zbhIr4ynOebmr9yVcTDIPwV -uu2vNXlwcITx42TGO5COSaLBb25p0rWzni0PBFYyXoNFZHLGgXRqfzzlRBaZuyAQ -HlpGYTHYvQl4PT+rojDU21oCzwMbgBpa5gyuBlfPte/KIyrcjFUCAwEAAQKCAYAO -M1r0+TCy4Z1hhceu5JdLql0RELZTbxi71IW2GVwW87gv75hy3hGLAs/1mdC+YIBP -MkBka1JqzWq0/7rgcP5CSAMsInFqqv2s7fZ286ERGXuZFbnInnkrNsQUlJo3E9W+ -tqKtGIM/i0EVHX0DRdJlqMtSjmjh43tB+M1wAUV+n6OjEtJue5wZK+AIpBmGicdP -qZY+6IBnm8tcfzPXFRCoq7ZHdIu0jxnc4l2MQJK3DdL04KoiStOkSl8xDsI+lTtq -D3qa41LE0TY8X2jJ/w6KK3cUeK7F4DQYs+kfCKWMVPpn0/5u6TbC1F7gLvkrseph -7cIgrruNNs9iKacnR1w3U72R+hNxHsNfo4RGHFa192p/Mfc+kiBd5RNR/M9oHdeq -U6T/+KM+QyF5dDOyonY0QjwfAcEx+ZsV72nj8AerjM907I6dgHo/9YZ2S1Dt/xuG -ntD+76GDzmrOvXmmpF0DsTn+Wql7AC4uzaOjv6PVziqz03pR61RpjPDemyJEWMkC -gcEA7BkGGX3enBENs3X6BYFoeXfGO/hV7/aNpA6ykLzw657dqwy2b6bWLiIaqZdZ -u0oiY6+SpOtavkZBFTq4bTVD58FHL0n73Yvvaft507kijpYBrxyDOfTJOETv+dVG -XiY8AUSAE6GjPi0ebuYIVUxoDnMeWDuRJNvTck4byn1hJ1aVlEhwXNxt/nAjq48s -5QDuR6Z9F8lqEACRYCHSMQYFm35c7c1pPsHJnElX8a7eZ9lT7HGPXHaf/ypMkOzo -dvJNAoHBAN7GhDomff/kSgQLyzmqKqQowTZlyihnReapygwr8YpNcqKDqq6VlnfH -Jl1+qtSMSVI0csmccwJWkz1WtSjDsvY+oMdv4gUK3028vQAMQZo+Sh7OElFPFET3 -UmL+Nh73ACPgpiommsdLZQPcIqpWNT5NzO+Jm5xa+U9ToVZgQ7xjrqee5NUiMutr -r7UWAz7vDWu3x7bzYRRdUJxU18NogGbFGWJ1KM0c67GUXu2E7wBQdjVdS78UWs+4 -XBxKQkG2KQKBwQCtO+M82x122BB8iGkulvhogBjlMd8klnzxTpN5HhmMWWH+uvI1 -1G29Jer4WwRNJyU6jb4E4mgPyw7AG/jssLOlniy0Jw32TlIaKpoGXwZbJvgPW9Vx -tgnbDsIiR3o9ZMKMj42GWgike4ikCIc+xzRmvdMbHIHwUJfCfEtp9TtPGPnh9pDz -og3XLsMNg52GXnt3+VI6HOCE41XH+qj2rZt5r2tSVXEOyjQ7R5mOzSeFfXJVwDFX -v/a/zHKnuB0OAdUCgcBLrxPTEaqy2eMPdtZHM/mipbnmejRw/4zu7XYYJoG7483z -SlodT/K7pKvzDYqKBVMPm4P33K/x9mm1aBTJ0ZqmL+a9etRFtEjjByEKuB89gLX7 -uzTb7MrNF10lBopqgK3KgpLRNSZWWNXrtskMJ5eVICdkpdJ5Dyst+RKR3siEYzU9 -+yxxAFpeQsqB8gWORva/RsOR8yNjIMS3J9fZqlIdGA8ktPr0nEOyo96QQR5VdACE -5rpKI2cqtM6OSegynOkCgcAnr2Xzjef6tdcrxrQrq0DjEFTMoCAxQRa6tuF/NYHV -AK70Y4hBNX84Bvym4hmfbMUEuOCJU+QHQf/iDQrHXPhtX3X2/t8M+AlIzmwLKf2o -VwCYnZ8SqiwSaWVg+GANWLh0JuKn/ZYyR8urR79dAXFfp0UK+N39vIxNoBisBf+F -G8mca7zx3UtK2eOW8WgGHz+Y20VZy0m/nkNekd1ZTXoSGhL+iN4XsTRn1YQIn69R -kNdcwhtZZ3dpChUdf+w/LIc= +MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDwcIAYm12nmQTG +B3caFn7alDe3LSliEfNC2ZTR+5sh1eucQPbzgFM5SR4soKGElwI68Eg7g1kwqu3z +mrI/FAiQI/RrUHyBZiEtnFBPM44vY02XjUlJ9nBtgP7QjpRz6ZP0z1DrrojpYLVw +g9cR0khTqD5cg2jvTB05yL9lQNk295/rMuueC9FaAQ+Y5la0ub7Lbe8gkYPotYli +Gx5qqCQmsXeTsxCpvQD7u0vBF9/nxlwywwzKGXabcN9YQhSECCC4c+eYjqoRgvAa +F48xEnokxenzBIqZ82BRkFo+zfNR+VhJRctNiZ6Ppa1Ise1H3LjZMDfY1S89QOLY +sFXUp8L7ZMVE27Bej+Sq4wEJ3soK/k1kr0YauqJ0lCEKkUPD9OeNHmczeakjj11t +gtctsYbwgDSUYGA3w+DCKD1aSfeuR3Hj89cSsVRrRrPFFih46Tr2PpTNoK6MtPH3 +RPJKV+Db8E1V2mXmNE0MLg6ramSHsD9iZXTLhG2JO+/876k3N3kCAwEAAQKCAYAK +Ap0KqTlCd4fv2LK4NtSMNByHt00gRKAMmfNstJ12UKoxBLFjXOXaHjWv5PYkh4bz +vjo7pBHMCWnDuR6Pqr1ahuyvpRex6XcbJ4VebsaOKYO6+gphlm2C2ZqCQ1Vh6Akd +aZ40Wb1gfgK/zvVezBLvzLLf9iahw9j5pWZ2iDci5zdUuvd9Sn+qUB3+nyRf/NW5 +MXgBsp07zIcOOxPOm/Z5V+0jDJL2hiRq1pbmUKClTShcgqtfJKU//niF+6ZQAuiJ +LBPaKIdPXyxLYnkyq2IgjPU0ZwxzdP0a2k72kvImd25Daj7elhGr3++IR+nFzt6h +vqflOfmKDF3zZPyUVI3YXjxo/FrOwGbLMHuuHBgE9txH/mOl1gByrxP+Ax18i3Bf +spSLeUvtaf/w/MopyspPoJBRbAM06PUHQI2v9xq3BZL/gHe2CdJPds2WzpaaVFG4 +oJWNrE3s6CowLqUkqzB7LqJ4ReZ6xe6SpkRotdmVknlIKgDenTFeEUEEVyBiFQEC +gcEA/F1GAaBG0e9vB+AOHZ96SLlZVzObSBYq2kVwUhhGItNnyU9c3fWPIrGREKQa +lw5dsvjl58ij5uEtJoPZf5BsJ0q6xHAs/kKxfpNfZAeoKAV96Z6MVcY+6WOyGjPF +aQo+GgSrCPIciW//WXZrWI1t0M2G0vZ5CFNohnKod+cSgV03PAActlyM2H+r7dtm +MpAD3EPWeeA75saKj/x0SOzuL/wzXKR8BZ6CINZ6r61Tcbk2mDwOHPhUrHeCwjoU +nhy5AoHBAPPnP2FSXFCPXD1Z1hFInCFgm41j7LEyBTVLlnqUrRk7i18fi/WcwwLH ++XvM5DcONY/V3sh7a3tZeHN1P70tRxLE0oO51D4tP5im/oZ6L+hszSYXX7lCbJSR +tni6nU1dssW3nmswfUn01Oh+B0rBGon3RQB6x4beTAW0piVxg9Ic2HYucS1Scrqw +afiFQ5KWklnMYJKInPFzlCwMdgBCuue1dZoJstU9nLQALNNSpGXB2X0+7j9D/qkz +Caw5MfgQwQKBwQDzdCvP78XCSuBq0XvsmefG9n+4fwGDFld6v9gualpmyFjsPJKT +UYwm5PPUAOvh46sCt9hatRVg6sO6zyFoTXP4p7/rN2hAVSiTuiog/r369elVEW3C +ZYBVeKbdXipIPehRA0XYWHCtKY1Fydae07kn4M37AGkcXhKM+VmKajFQ+RMK3/TS +/A+n3+qFiM1bY9FFkW/7nRVMeSY850dq/p59TihibA91AEf6084BYg0IvatsSys2 +SV6uDpDnPE6dhYkCgcBECtAwq1RbmRLnfqdsnPAJk7Txhd3jNQwk6RhqzA1aS7U+ +7UMTWw9AOF+OPQOxpEInBUgob931RGmI9D263eXFA6mi2/Ws/tyODpBVHcM9uRSm +OsEWosQ90kSwe4ckrS4RYH9OcfGR7z5yOa55GVP5B0V1s8r0AhH9SX9MVNWsiSWO +GriyJx0gndSCY1MNkvnzGUQbvQbjiRXeD//fZL5Vo9bSCUCdopmT0bSvo49/X8v3 +19WJSsPBmh5psG8TQEECgcEA64CqZpPux35LeLQsKe0fYeNfAncqiaIoRbAvxKCi +SQf27SD8HK+sfvhvYY7bP7TMEeM7B/O2/AqBQQP0UARIGJg2AknBQT0A7//yJu+o +v4FHy2XKh+RMAx7QrdvnQ4CfrjvjQIaAcN1HrdTKWwgQZZImRf57nUCMm82ktZ2k +vYEJTXMkT8CY0DSeGtPmX5ynk7cauHTdZrkPGhZ3Hr6GAFomOammnnytv2wc+5FA +Ap+d65UgF4KjGY4rtsS+jOHn -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIEgzCCAuugAwIBAgIUU+FIM/dUbCklbdDwNPd2xemDAEwwDQYJKoZIhvcNAQEL +MIIEhTCCAu2gAwIBAgIUTxhwRX6zBQc3+l3imDklEbqcDpIwDQYJKoZIhvcNAQEL BQAwXzELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYD VQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJbG9jYWxo -b3N0MB4XDTIzMTEyNTA0MjEzNloXDTQzMDEyNDA0MjEzNlowXzELMAkGA1UEBhMC -WFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJbG9jYWxob3N0MIIBojANBgkqhkiG -9w0BAQEFAAOCAY8AMIIBigKCAYEAzXTIl1su11AGu6sDPsoxqcRGyAX0yjxIcswF -vj+eW/fBs2GcBby95VEOKpJPKRYYB7fAEAjAKK59zFdsDX/ynxPZLqyLQocBkFVq -tclhCRZu//KZND+uQuHSx3PjGkSvK/nrGjg5T0bkM4SFeb0YdLb+0aDTKGozUC82 -oBAilNcrFz1VXpEF0qUe9QeKQhyd0MaW5T1oSn+U3RAj2MXm3TGExyZeaicpIM5O -HFlnwUxsYSDZo0jUj342MbPOZh8szZDWi042jdtSA3i8uMSplEf4O8ZPmX0JCtrz -fVjRVdaKXIjrhMNWB8K44q6AeyhqJcVHtOmPYoHDm0qIjcrurt0LZaGhmCuKimNd -njcPxW0VQmDIS/mO5+s24SK+Mpznm5q/clXEwyD8FbrtrzV5cHCE8eNkxjuQjkmi -wW9uadK1s54tDwRWMl6DRWRyxoF0an885UQWmbsgEB5aRmEx2L0JeD0/q6Iw1Nta -As8DG4AaWuYMrgZXz7XvyiMq3IxVAgMBAAGjNzA1MBQGA1UdEQQNMAuCCWxvY2Fs -aG9zdDAdBgNVHQ4EFgQUl2wd7iWE1JTZUVq2yFBKGm9N36owDQYJKoZIhvcNAQEL -BQADggGBAF0f5x6QXFbgdyLOyeAPD/1DDxNjM68fJSmNM/6vxHJeDFzK0Pja+iJo -xv54YiS9F2tiKPpejk4ujvLQgvrYrTQvliIE+7fUT0dV74wZKPdLphftT9uEo1dH -TeIld+549fqcfZCJfVPE2Ka4vfyMGij9hVfY5FoZL1Xpnq/ZGYyWZNAPbkG292p8 -KrfLZm/0fFYAhq8tG/6DX7+2btxeX4MP/49tzskcYWgOjlkknyhJ76aMG9BJ1D7F -/TIEh5ihNwRTmyt023RBz/xWiN4xBLyIlpQ6d5ECKmFNFr0qnEui6UovfCHUF6lZ -qcAQ5VFQQ2CayNlVmQ+UGmWIqANlacYWBt7Q6VqpGg24zTMec1/Pqd6X07ScSfrm -MAtywrWrU7p1aEkN5lBa4n/XKZHGYMjor/YcMdF5yjdSrZr274YYO1pafmTFwRwH -5o16c8WPc0aPvTFbkGIFT5ddxYstw+QwsBtLKE2lJ4Qfmxt0Ew/0L7xkbK1BaCOo -EGD2IF7VDQ== +b3N0MCAXDTI0MTAwODExNTExMloYDzI0MDgwMTI5MTE1MTEyWjBfMQswCQYDVQQG +EwJYWTEXMBUGA1UEBwwOQ2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBT +b2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDDAlsb2NhbGhvc3QwggGiMA0GCSqG +SIb3DQEBAQUAA4IBjwAwggGKAoIBgQDwcIAYm12nmQTGB3caFn7alDe3LSliEfNC +2ZTR+5sh1eucQPbzgFM5SR4soKGElwI68Eg7g1kwqu3zmrI/FAiQI/RrUHyBZiEt +nFBPM44vY02XjUlJ9nBtgP7QjpRz6ZP0z1DrrojpYLVwg9cR0khTqD5cg2jvTB05 +yL9lQNk295/rMuueC9FaAQ+Y5la0ub7Lbe8gkYPotYliGx5qqCQmsXeTsxCpvQD7 +u0vBF9/nxlwywwzKGXabcN9YQhSECCC4c+eYjqoRgvAaF48xEnokxenzBIqZ82BR +kFo+zfNR+VhJRctNiZ6Ppa1Ise1H3LjZMDfY1S89QOLYsFXUp8L7ZMVE27Bej+Sq +4wEJ3soK/k1kr0YauqJ0lCEKkUPD9OeNHmczeakjj11tgtctsYbwgDSUYGA3w+DC +KD1aSfeuR3Hj89cSsVRrRrPFFih46Tr2PpTNoK6MtPH3RPJKV+Db8E1V2mXmNE0M +Lg6ramSHsD9iZXTLhG2JO+/876k3N3kCAwEAAaM3MDUwFAYDVR0RBA0wC4IJbG9j +YWxob3N0MB0GA1UdDgQWBBR459BlAel5MqCtG0DrvVtMZlQfuTANBgkqhkiG9w0B +AQsFAAOCAYEAaTFWjK/LFzOo+0TWqTTj4WC4N3I8JFrHnlqFJlpchYTW2z92SU1G +iEzFjWzuDNjp5KM9BqlmGtzXZvy6MItGkYsjPRdPVU0rbCmyTho6y77kTyiEG12V +UAJ1in3FOQfDwLPcp7wQRgCQq3iZlv7pwXp2Lm5fzu8kZPnxmTVdiKQun9Ps7uKq +BoM0fM2K14MxVO4Wc0SERnaPszE7xAhkIcs+NRT/gHYdTBlPhao83S3LOOdtCqCP +pNUOEaShlwI5bVsDPUXNX/eS0MYFNlsYTb5rCxK8jf3W3KNjKTOzN94pHiQOhpkg +xMPPi3m03/9oKTVXBtHI2A+u3ukheKE6sBXCLdv/GEs9zYI49zmpQxNWz5EOumWL +k+W/vPv7cD6LeHxxp+nCbEJi1gZtYb3gMY1sLkMNxcOu0QHTqHfme+k7VKWm8anO +3ogGdGtPuPAD/qjMwg3ChSDLl5Ur/E9UPlD4yM/7KtUD7mLv+jbddA62EiA9MxVB +t+yt7pOwOA66 -----END CERTIFICATE----- diff --git a/Lib/test/certdata/keycert.pem.reference b/Lib/test/certdata/keycert.pem.reference index f9a82f35f340dd..5528b98fff9377 100644 --- a/Lib/test/certdata/keycert.pem.reference +++ b/Lib/test/certdata/keycert.pem.reference @@ -2,9 +2,9 @@ (('localityName', 'Castle Anthrax'),), (('organizationName', 'Python Software Foundation'),), (('commonName', 'localhost'),)), - 'notAfter': 'Jan 24 04:21:36 2043 GMT', - 'notBefore': 'Nov 25 04:21:36 2023 GMT', - 'serialNumber': '53E14833F7546C29256DD0F034F776C5E983004C', + 'notAfter': 'Jan 29 11:51:12 2408 GMT', + 'notBefore': 'Oct 8 11:51:12 2024 GMT', + 'serialNumber': '4F1870457EB3050737FA5DE298392511BA9C0E92', 'subject': ((('countryName', 'XY'),), (('localityName', 'Castle Anthrax'),), (('organizationName', 'Python Software Foundation'),), diff --git a/Lib/test/certdata/keycert2.pem b/Lib/test/certdata/keycert2.pem index c7c4aa74583c8a..63e2181ed83e78 100644 --- a/Lib/test/certdata/keycert2.pem +++ b/Lib/test/certdata/keycert2.pem @@ -1,67 +1,67 @@ -----BEGIN PRIVATE KEY----- -MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCyAUXjczgUEn7m -mOwDMi/++wDRxqJAJ2f7F9ADxTuOm+EtdpfYr4mBn8Uz9e3I+ZheG5y3QZ1ddBYA -9YTfcUL0on8UXLOOBVZCetxsQXoSAuDMPV0IXeEgtZZDXe7STqKSQeYk7Cz+VtHe -lZ8j7oOOcx5sJgpbaD+OGJnPoAdB8l8nQfxqAG45sW4P6gfLKoJLviKctDe5pvgi -JC8tvytg/IhESKeefLZ4ix2dNjj2GNUaL+khU6UEuM1kJHcPVjPoYc+y8fop/qhQ -0ithBhO2OvJ+YmOFdCE67SyCwU3p8zJpN+XkwbHttgmNg4OSs7H6V7E52/CsTNTA -SthBHXtxqaM+vjbGARrz2Fpc/n+LwRt7MGIR0gVtntTgnP0HoeHskhAIeDtaPrZ6 -zHdl3aDwgAecVebTEBT5YPboz+X1lWdOrRD2JW3bqXSRIN3E4qz5IMuNx3VvhpSR -eFZzR6QIbxQqzO/Vp93Ivy8hPZ6WMgfSYWs7CGtu4NP79PJfdMsCAwEAAQKCAYAc -e3yp2NlbyNvaXRTCrCim5ZXrexuiJUwLjvNfbxNJDeM5iZThfLEFd0GwP0U1l86M -HGH2pr6d4gHVVHPW5wIeL9Qit3SZoHv9djhH8DAuqpw6wgTdXlw0BipNjD23FBMK -URYYyVuntM+vDITi1Hrjc8Ml7e5RUvx8aa5O3R3cLQKRvwq7EWeRvrTMQhfOJ/ai -VQGnzmRuRevFVsHf0YuI4M+TEYcUooL2BdiOu8rggfezUYA9r2sjtshSok0UvKeb -79pNzWmg9EWVeFk+A0HQpyLq+3EVyB5UZ3CZRkT0XhEm1B7mpKrtcGMjaumNAam7 -jkhidGdhT/PV9BB1TttcqwTf+JH9P9sSpY9ZTA1LkkeWe9Rwqpxjjssqxxl6Xnds -+wUfuovVvHuBinsO+5PLE5UQByn21WcIBNnPCAMvALy/68T7z8+ATJ+I2CqBXuM2 -z5663hNrvdCu93PpK4j/k/1l3NTrthaorbnPhkmNYHQkBicpAfFQywrv6enD+30C -gcEA7Vlw76og4oxI7SSD6gTfo85OqTLp2CUZhNNxzYiUOOssRnGHBKsGZ8p0OhLN -vk9/SgbeHL5jsmnyd8ZuYWmsOQHRWgg1zO3S25iuq+VAo4cL/7IynoJ0RP5xP0Pw -QD+xJLZQp0XuLUtXnlc6dM5Hg7tOTthOP9UxA1i57lzpYfkRnKmSeWi+4IDJymOt -WoWnEK7Yr7qSg6aScLWRyIvAPVmKF9LToSFaTq0eOD0GIwAQxqNbIwN3U0UJ5Ruc -KRBVAoHBAL/+DNGqnEzhhWS6zqZp2eH90YR+b3R4yOK4PROm2AVA3h1GhIAiWX68 -PvKYZK9dZ9EdAswlFf9PVQYIXUraR3az0UiIywnNMri+kO1ZxwofGvljrOfRRLg0 -B46wuHi6dVgTWzjTl503G9+FpAYNHv184xsr1tne0pf2TKEnN7oyQciCV8qtr8vV -HrL46uaD0w1fcXIXbO3F/7ErLsvsgLzKfxR5BeQo6Fq0GmzD+lCmzVNirtfl2CZj -2ukROXUQnwKBwQDR1CqFlm/wGHk4PPnp31ke5XqhFoOpNFM1HAEV5VK0ZyQDOsZU -mCXXiCHsXUdKodk0RpIB80cMKaHTxbc7o0JAO50q7OszOmUZAggZq1jTuMYgzRb3 -DvlfLVpMxfEVu7kNbagr2STRIjRZpV/md569lM+L4Kp8wCrOfJgTZExm8txhFYCK -mNF2hCThKfHNfy7NDuY9pMF2ZcI8pig1lWbkVc5BdX7miifeOinnKfvM4XfzQ+OE -NsI8+WHgC+KoYukCgcBwrOpdCmHchOZCbZfl9m1Wwh16QrGqi1BqLnI53EsfGijA -yaftgzs+s7/FpEZC3PCWuw3vPTyhr69YcQQ/b8dNFM8YYJ+4SuMfpUds5Kl5eTPd -dO/+xMQtzus4hOJeiB9h50o8GYH7VGJZVhcjLgQoBGlMgvf+uVSitnvWgCumbORK -hqR7YF+xoov3wToquubcDE2KBdF54h/jnFJEf7I2GilmnHgmpRNoWBbCCmoXdy09 -aMbwEgY+0Y+iBOfRmkUCgcEAoHJLw7VnZQGQQL4l3lnoGU9o06RPkNbpda9G/Ptz -v+K7DXmHiLFVDszvZaPVreohuc0tKdrT0cZpZ21h0GQD4B6JX66R/y6CCAr0QpdA -pFZO9sc5ky6RJ4xZCoCsNJzORNUb36cagEzBWExb7Jz2v6gNa044K5bs3CVv5h15 -rJtTxZNn/gcnIk+gt//67WUnKLS4PR5PVCCqYhSbhFwx/OvVTJmflIBUinAclf2Q -M4mhHOfwBicqYzzEYbOE9Vk9 +MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCtFmmyQ+HjjeBX +UE61fTenp2C9cvHzZSTFvKNeKZ2ZVZzH1HFnMBlTXGlXybSi2PhfxNYo5JrNGW4v +ZADh/eIFOONvPebQBONi4B1188Mb1RHgyIMtl/gOLF+L9DkStFb2eJ3fFInjNh5b +yhhpcOH1AmPCsiLeCAO3qc9qeChmJ4hAy1xmx74yQkOGzu0hKZ9d5QNNemCpPKTh +J+X8+PCY+FRObAdKJ56er2BjkdaUB/Mp6BBLokYs917VdnH6TiicqfrUsjh36XpO +G35/bW9jsQRpbeGkMIW6vn9GEYT79d4+FWdl9SxTfcSy7tn35/SvtIYDByWLc4IJ +izTuFV91pGmsXSav4YVF1hLC5cy8iEfKrdAl1kzamHfHKuY+P+sbwSQHPn5Z5xyU +Vr+odU0t7+YExBKLG8zHkQ+h2bwEeFy6H9uYQZFhBLOHrkkWSPYLKjzch6DyNkTp ++5cGWLOkcs8Xt0mjG2gzUlgwIYWHkq7wE9jxz3/tJ3MGf2CNDxsCAwEAAQKCAYAU +x+HCxFb6LLjS4tJrBHCf0VRSX9rf/7Ri2oYRXRUN1B3cTrZFeZyLdJyKggNiSy3E +GcF4lrxl2Xgaz8/cp3rxE5EYHv93hCQPZUbu4r2kZCLJsRPcGn3D/dyEKhCGyAi/ +fgsTkxyxnyK/9HXqhYyrZNu4rrh0SH63GKJ4GZsIFhZME95b0f6/e/3YJpSJFxKK +LF+xd/rjoWNOS62s1JqA/czpaXDqnJ0frNX5aQixLHnWUy/5qgRGNnY3/LOB0MuU +EjFizRSJp6gQQ64dIFgiMyUMi+Z6fw6xkTpN5EbmgFCwmaja1/hp9UZ+atlVpJsO +SB+OhF2wxB+bX2phGHJ9DD4RY/di1YKPvmH0+LITq4JiJWwJLgoCm7krzfVxZFZN +lgZPvdNw/Yt/Y3bN31FMw8DwRCThnL+MH83E58iCWQq2zKS1RssBBwFacI6Wf1ed +442NPIH47oi5qRKUxYHze6kFssSs4TkbR++VYHXLbTLjqfePLP92ZFxdOstx5jEC +gcEA48mx39dwr1oSk4uR+q8aDZIjPT+9D0IxcdAmL968QgG98hF2Tx7s5alR4y+9 +2FueR5fSqRweJfaDn77j5DVNXLD5jBz73pdwIkfqJHLfcsN7NnzCz3mxU9WP2F7R +W8KD3C2MtzGwQwOI3GT20+wJaA7p5n5zKR7AC0RxhC3U4zwH5nSjtY70A3dWXkn3 +F0j+B6ak0P0oN9VQUuvk5zw0IZ32uxef7poiHvFZpl1DQSgX/edT1CIT1s0nmVFl +w1ojAoHBAMKGX+TobGZfZFj/I7oIVQ7023pi516fZx/R0Y0FTmZzIKsdt3wrPmar +3K5dZGasNd0wzUsxX+vSjMtI1oERuPd4Rs6YqQHpX892uJ7L41/oBcFCc+Fk7jBY +TiRg/8/gOTaQe1nDR52K/R0sqBatRqInNMBDcBsVguBC4dTqP8CQ0CnEjAOYsk1s +1nYPKcfM36BUXBmSlnvUPWMm8KCT9Kko9ylHVq+d+ziDebfYpy6fTvti2NM31wTM +1prasEUaqQKBwQDQX14+5MapMd1SaVelmW5cwbVIvzjEb4npkj6MhdVzEELg4IZ4 +hFKzGDvXdoHVHKJi3YiQuC8ADUyE4kt4JCZbx2zQdmcVTTT/tweCRi8PvbDFvEU9 +JBZKGU+X38zmgr66uFRD9MlH1EDrU9TTMdW9Af+HoV7ZW87Tv82T25UmNXEIqORl +HpsrXIx+fmzxOQ1glFmq8BpNUO5EnJPtz43kvqrIpSjhTNAvvBqFbEUsom+oDWgK +4w2A7nTt9J8BoD8CgcBkYKa3HmBhazQC4JV097u8nglrXAH8R9EVEFZLqMNOBnaD +FjCKeF4Y6PJVX4fhm1eoLfihpnbS37EbbRiTPavutzgCf7AmdmCkU6Ts/FT2NmpR +0ZKuakCm3cpk51DZ2eBsEZ41MZmQ6Bm4pkSOfxeFsSl9VM9SioUgaCLUlZQUMCXa +h7ugV3kajuETxrtOiJ+UwjNMVuIkP971fTCKDA8iAyuXN2K5+JGcFewHPFr4qeg9 +vEIarCPeLD1JZzOyVRECgcEAhqeXfmFezNKGvr7qCflJe92LF9MStgJ7yE0OfADy +B+RZKeOwoqOO3VFR1piAn/DzrC2K9q+Of61gw+KWQOgMnsigqZ2mFLGChRjWhb7S +3G0DGOb4+DD9RR6wlFPFXSwVxSWGKrqNhOJik/IzVWvYxOOFjVt1adXZ3GftnYsv +nZCsS94H4kMiXr6UkbkjjxnZ1WkE9DaQJU27Mw1dtwb1ECzO0rty9B9L6b80MYW/ +nMhJV6sanCUex4nAChHD+VR7 -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIEjDCCAvSgAwIBAgIUQ2S3jJ5nve5k5956sgsrWY3vw9MwDQYJKoZIhvcNAQEL +MIIEjjCCAvagAwIBAgIUCP/QP57z62jCsjf6l0ft/yzDxOkwDQYJKoZIhvcNAQEL BQAwYjELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYD VQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEVMBMGA1UEAwwMZmFrZWhv -c3RuYW1lMB4XDTIzMTEyNTA0MjEzN1oXDTQzMDEyNDA0MjEzN1owYjELMAkGA1UE -BhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRob24g -U29mdHdhcmUgRm91bmRhdGlvbjEVMBMGA1UEAwwMZmFrZWhvc3RuYW1lMIIBojAN -BgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAsgFF43M4FBJ+5pjsAzIv/vsA0cai -QCdn+xfQA8U7jpvhLXaX2K+JgZ/FM/XtyPmYXhuct0GdXXQWAPWE33FC9KJ/FFyz -jgVWQnrcbEF6EgLgzD1dCF3hILWWQ13u0k6ikkHmJOws/lbR3pWfI+6DjnMebCYK -W2g/jhiZz6AHQfJfJ0H8agBuObFuD+oHyyqCS74inLQ3uab4IiQvLb8rYPyIREin -nny2eIsdnTY49hjVGi/pIVOlBLjNZCR3D1Yz6GHPsvH6Kf6oUNIrYQYTtjryfmJj -hXQhOu0sgsFN6fMyaTfl5MGx7bYJjYODkrOx+lexOdvwrEzUwErYQR17camjPr42 -xgEa89haXP5/i8EbezBiEdIFbZ7U4Jz9B6Hh7JIQCHg7Wj62esx3Zd2g8IAHnFXm -0xAU+WD26M/l9ZVnTq0Q9iVt26l0kSDdxOKs+SDLjcd1b4aUkXhWc0ekCG8UKszv -1afdyL8vIT2eljIH0mFrOwhrbuDT+/TyX3TLAgMBAAGjOjA4MBcGA1UdEQQQMA6C -DGZha2Vob3N0bmFtZTAdBgNVHQ4EFgQU5wVOIuQD/Jxmam/97g91+igosWQwDQYJ -KoZIhvcNAQELBQADggGBAFv5gW5x4ET5NXEw6vILlOtwxwplEbU/x6eUVR/AXtEz -jtq9zIk2svX/JIzSLRQnjJmb/nCDCeNcFMkkgIiB64I3yMJT9n50fO4EhSGEaITZ -vYAw0/U6QXw+B1VS1ijNA44X2zvC+aw1q9W+0SKtvnu7l16TQ654ey0Qh9hOF1HS -AZQ46593T9gaZMeexz4CShoBZ80oFOJezfNhyT3FK6tzXNbkVoJDhlLvr/ep81GG -mABUGtKQYYMhuSSp0TDvf7jnXxtQcZI5lQOxZp0fnWUcK4gMVJqFVicwY8NiOhAG -6TlvXYP4COLAvGmqBB+xUhekIS0jVzaMyek+hKK0sT/OE+W/fR5V9YT5QlHFJCf5 -IUIfDCpBZrBpsOTwsUm8eL0krLiBjYf0HgH5oFBc7aF4w1kuUJjlsJ68bzO9mLEF -HXDaOWbe00+7BMMDnyuEyLN8KaAGiN8x0NQRX+nTAjCdPs6E0NftcXtznWBID6tA -j5m7qjsoGurj6TlDsBJb1A== +c3RuYW1lMCAXDTI0MTAwODExNTExMloYDzI0MDgwMTI5MTE1MTEyWjBiMQswCQYD +VQQGEwJYWTEXMBUGA1UEBwwOQ2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhv +biBTb2Z0d2FyZSBGb3VuZGF0aW9uMRUwEwYDVQQDDAxmYWtlaG9zdG5hbWUwggGi +MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCtFmmyQ+HjjeBXUE61fTenp2C9 +cvHzZSTFvKNeKZ2ZVZzH1HFnMBlTXGlXybSi2PhfxNYo5JrNGW4vZADh/eIFOONv +PebQBONi4B1188Mb1RHgyIMtl/gOLF+L9DkStFb2eJ3fFInjNh5byhhpcOH1AmPC +siLeCAO3qc9qeChmJ4hAy1xmx74yQkOGzu0hKZ9d5QNNemCpPKThJ+X8+PCY+FRO +bAdKJ56er2BjkdaUB/Mp6BBLokYs917VdnH6TiicqfrUsjh36XpOG35/bW9jsQRp +beGkMIW6vn9GEYT79d4+FWdl9SxTfcSy7tn35/SvtIYDByWLc4IJizTuFV91pGms +XSav4YVF1hLC5cy8iEfKrdAl1kzamHfHKuY+P+sbwSQHPn5Z5xyUVr+odU0t7+YE +xBKLG8zHkQ+h2bwEeFy6H9uYQZFhBLOHrkkWSPYLKjzch6DyNkTp+5cGWLOkcs8X +t0mjG2gzUlgwIYWHkq7wE9jxz3/tJ3MGf2CNDxsCAwEAAaM6MDgwFwYDVR0RBBAw +DoIMZmFrZWhvc3RuYW1lMB0GA1UdDgQWBBSAf/Z+TUHMOcr020NGG4geSnlNhTAN +BgkqhkiG9w0BAQsFAAOCAYEAIia0ULQmC510p78HZbiOb2BV8q+0AY0l6Cn/FRIL +Voqy7uB5oEYdDisla8epmBTU35+JmfrRHbP6IuSqKdcGj8VqsjZljhntSrB7rw4O +IqjbnxnfEuREjY2w+WGLvvdtVGXCBgfRmIItORFKpoOvLzLIi1lXeDq8QL97K4nM +tPsZpzILCBCoXmhh0MweCCNe1HSD8q6EbSDjVoxraBl0YK/l1ID08Fi5fwdddRX7 +txfx5NtoWWbsLZY0GdBtQmRCifs7P9lyhjUd87bJGd8WCBE4IzLwJiHEyNPI4WHe +8jmvKD/zO7mKxT9/jF7IBqwTHgQQ1uaRGytiXjRlfPu4Ez8ASR6rP7Hlua7h0Ba7 +OcDPcgM8rzN4zcfsvZ+8Cd84HXFjHhV6ZdRPbBWFWd8TlDufrWNuY4SyOtkyfE5E +lWcoRnkBGBaooZNcd72ZwZVO0gAS31bgs8ju+k02GIDLkuZSRNPeFsRQbcMu1Mhc +cFteFsqniLhzpkWJVQQgeGlV -----END CERTIFICATE----- diff --git a/Lib/test/certdata/keycert3.pem b/Lib/test/certdata/keycert3.pem index 20d9bd14e9678f..097dc9f8e88091 100644 --- a/Lib/test/certdata/keycert3.pem +++ b/Lib/test/certdata/keycert3.pem @@ -1,42 +1,42 @@ -----BEGIN PRIVATE KEY----- -MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCgKihxC+2g7d7M -JfIUBfFWiuMwxg0WhdxPyGUzMAjexbEOHo0ojntxPdH9KYRwiKRKb9jnmzXp2CKT -hqBYJIetq/3LYZp4bvDJ/hVCL9e4jqu1l+wd9DkqhKZ69b6C1/d12JAKvC5TIT+/ -b7EglYU8KMNx2WO5KxIJeVpX68jn49YtUzg0hT0QiXj4eugbDk1L1f99xgvkHaVW -VQxi6MFNWHJq/xXUb8E/hd/Q3oadN1BXMWl9P46D4R+YGKQQdZFkwEJsbqijFvWW -bOoaz7TFxf8n0q616803aXLfaWikfEXLnznEvKo7vyEivtT/y14Nm+SiR3nS6E0y -Dt8gmeHdaHcrmQT+yQ6yNOYDCcfeYM+rBuvOUHPudjMy0k8K/0IPjDo0KActKPH0 -UVbyDBMKDdGQ2+LhRFLsGXHlD9b05PxhqTULe3LeK6KZ+iuGbWtwVLaL5S42WiCA -YXNShE1Ko0Q7wugAippXCf+aWP3Wx9ZTrsfiDBbIfnY5mlfdG90CAwEAAQKCAYAA -ogoE4FoxD5+YyPGa+KcKg4QAVlgI5cCIJC+aMy9lyfw4JRDDv0RnnynsSTS3ySJ1 -FNoTmD5vTSZd1ONfVc2fdxWKrzkQDsgu1C07VLsShKXTEuWg/K0ZKOsLg1scY0Qc -GB4BnNrGA1SgKg3WJiEfqr2S/pvxSGVK2krsHAdwOytGhJStSHWEUjbDLKEsMjNG -AHOBCL5VSXS00aM55NeWuanCGH36l/J4kMvgpHB9wJE1twFGuHCUvtgEHtzPH9fQ -plmI0QDREm6UE6Qh01lxmwx3Xc5ASBURmxs+bxpk94BPRpj8/eF2HPiJalrkJksj -Xk3QQ7k23v6XnmHKV3QqpjUgJTdbuMoTrVMu14cIH6FtXfwVhtthPnCI8rk5Lh8N -cqLC7HT+NE1JyygzuMToOHMmSJTQ8L6BTIaRCZjvGTPYaZfFgeMHvvhAJtP5zAcc -xQzyCyNBU8RdPGT8tJTyDUIRs20poqe7dKrPEIocKJX7tvNSI2QxkQ96Adxo1gEC -gcEAvI8m6QCDGgDWI8yTH9EvZQwq+tF8I+WMC+jbPuDwKg5ZKC7VjRO//9JzPY+c -TxmLnQu64OkECHbu7pswDBbtnPMbodF9inYEY5RkfufEjEMJGEdkoBJWnNx78EkV -bcffWik0wXwdt6jd1CAnjmS9qaPz0T1NV8m5rQQn5JUYXlC9eB2kOojZYLbZBl3g -xUSRbIqHC7h8HuyAU26EPiprHsIxrOpbxABFOdvo2optr50U7X10Eqb4mRQ4z22W -ojJdAoHBANlzJjjEgGVB9W50pJqkTw8wXiTUG8AmhqrVvqEttLPcWpK6QwRkRC+i -5N1iUObf/kOlun2gNfHF6gM68Ja9wb2eGvE5sApq9hPpyYF0LS3g8BbJ9GOs6NU9 -BfM1CkPrDCdc4kzlUpDibvc6Fc9raCqvrZRlKEukqQS8dumVdb74IaPsP6q8sZMz -jibOk0eUrbx2c5vEnd0W8zMeNCuCwO1oXbfenPp/GLX9ZRlolWS/3cQoZYOSQc9J -lFQYkxL3gQKBwQCy3Pwk9AZoqTh4dvtsqArUSImQqRygFIQXXAh1ifxneHrcYijS -jVSIwEHuuIamhe3oyBK6fG8F9IPLtUwLe8hkJDwm8Misiiy5pS77LrFD9+btr/Nk -4GBmpcOveDQqkflt1j6j9y9dY4MhUGsVaLx86fhDmGoAh2tpEtMgwsl91gsUoNGD -cQL6+he+MVkg510nX/Sgipy63M8R1Xj+W1CHueBTTXBE6ZjBPLiSbdOETXZnnaR4 -eQjCdOs64JKOQ0UCgcBZ4kFAYel48aTT/Z801QphCus/afX2nXY5E5Vy5oO1fTZr -RFcDb7bHwhu8bzFl3d0qdUz7NMhXoimzIB/nD5UQHlSgtenQxJnnbVIAEtfCCSL1 -KJG+yfCMhGb7O0d8/6HMe5aHlptkjFS2GOp/DLTIQEoN9yqK6gt7i7PTphY/1C2D -ptpCZzE32a2+2NEEW67dIlFzZ/ihNSVeUfPasHezKtricECPQw4h3BZ4RETMmoq+ -1LvxgPl3B8EqaeYRhwECgcEAjjp/0hu/ukQhiNeR5a9p1ECBFP8qFh6Cpo0Az/DT -1kX0qU8tnT3cYYhwbVGwLxn2HVRdLrbjMj/t88W/LM2IaQ162m7TvvBMxNmr058y -sW/LADp5YWWsY70EJ8AfaTmdQriqKsNiLLpNdgcm1bkwHJ1CNlvEpDs1OOI3cCGi -BEuUmeKxpRhwCaZeaR5tREmbD70My+BMDTDLfrXoKqzl4JrRua4jFTpHeZaFdkkh -gDq3K6+KpVREQFEhyOtIB2kk +MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDuNnCqYWoguzKI +B3PwOsoRzI8wgNdxx3RiIJSItFISlAgB4XkYzPBpi5nFR8GCqq7IUQQ+iYwdZa3y +H6X11IdlrCx4gDdQFSFOegnG41oqv7GwBEFvq6xlowpoaGw+5/8/sJX/VU44rL9/ +fiMVTbehMhMS/z5nTSYSACV7sRXnwW4T6l2Od77FzPBjnaFFDNr5GIoiD4mNSJ35 +t05tliGcz0IyE5TGR6kIEFNIH5theHoJJ4JC4uLyWJweJpxDx10njWRwKN/tXm8F +nHQPMRAUl2wM07QZEI1yfzUr00/oG2dpPnPyNh+6p2ld8JS0g2/Pd2pQL8OtmM2c +DcN5E+qCEW1UVIJ5//ad8pUcoQwyRIBROJbakqv6FcVTdgTogoq5Vu+T6TVFLSIS +vVvpsV0MtT/H9/9TtCnqOwliE8s8kb3NjQT8e72VHNd43bVPE4DeQ+XlbMoKzV+G +OmSHSfzSOZB9kScSmGd5YD8783TbL8/7Nn1ERQdWqaixGI36+BECAwEAAQKCAYBV +Ubhevg9V89ZwdELpSxUu9NZgZ/VCck7UCplIsVUoBE8t5UULRfPhybdkuoOrulhp +tOLRR1ChAtcffohhmSJ5nwY6jqnBDCBmzD0OOEYGQ6xvv8Z0KcfQi2nh5WzHxy5b +8HJ5BmPC1tSr5FDKg5B+ssG0Lyl5tF8rWVQTjmSrIlO73Fhv+6GflPyQoVeutKEF +UO3Ar1H0AYtbcnUruPcHBBDQgMTrk6UOF1LM5U0wxwbmmnkEXeEtLeGUxv13JUMe +QTrSw0P+hn5uiDMwY5lI212ayorbwyNuzU0hGW7j98qa/S9MVSeRwv4bsbtBqwtT +ZVGL2TogjeJ+8+qDlv5tf3crD1pV0yu7uVUeIGrJZJdiiMM6N7/x3cIJtrLDaF1w +9kUqdQGWDWwRV3w0FaeXDVlUTJ3VFTZIinLo1Vmd3AXLn97eVy+68DWD6ELlMkfF +ro3bQbQu59DGswDF9+mMauhgvljnxY/wUnkyp8LGZt8w/RU/op8LcvPKFjQfX6UC +gcEA/RClguU/JTWQSF4Vjy5+DmrzSCXabrO7986lkOwPXEaXLsF2pGOU+sbxffXZ +PCQ4zU6aNYBMtNWLrVqBrPnI78XZQbmSG7zUDxWwmr1ttuSHGthdaZUVTOsFsnpE +R+1lj20G2T2ankzv0ICFz7BWyaYwyzDrABwuP189b3juuX6xGLlCO25/AnK+iTXQ +WF4ZURZiwDg4WpxvPsE2FFglN09TtDDCeQw/zv7Jh6jWtHZfivfv/wR8ILu72gde +LdinAoHBAPD5slojp2St6iWTaxcYYBc+4x+Rv7oyxeAyM/00iIAnf19oaAw3jki1 +yz6zeNnhaZuwa6ruvhJAESPc+pXkmoPpQ1yIRjKZc3jPVoaxYuSPgUEbHV6BQbjD +clIoGkC6ISsjanMq8Z3pK7e2bxY4mxGRQIFSFnTeK8m8nzq5dYisVtxxJFnV2fDG +NWDMdDYBh52vpkPjnm5OoOuilkEH2ygtZlT6bKAbnhi/FVjYCHk46inaYx8PakMu +LnvZI0OIhwKBwBGzYGBPeKM5o+Xr7sYdEmQfxvR88VJc8ADdS2dfm5NwvJJgpdPJ +w1nnIG0XDSLPxclWfiLP3o2ngiWV9wwKTKu4wwF94WJfStXjRn8MUOhCA9E04RPJ +gbvnlHZvZudBC6GElr4LOQ1phDypQLLOOsPQBAmyWj2fuvxjxQBPDSOcYPbBvog5 +qliZfgpK4U/NBShO0IlxZT+xQXa6PPYfVDsSKWCpKHEfEjeASshaXuowfW5S+U51 +GdmQSAtwCH5ccQKBwQCOLgW5gYfms2aPvSdWfR9VF9nSaqCBMCvoWDasky5mzucs +V+HsM2tUI09EM4h+pa02GyWruSmUgxCZ5GxFvJgedKc2FYG1oSysf0lCN69tw+4z +h9gQRpuMdGUjbF3xCuE/HqpUQWZGEamlv5JTvhpghx9ULibp1Zxob05Ty9E5TtYB +QxB7oN3yXkBoWLnIk6Z8t4KWU9rKosH3xfp5bDU2w3K5ePhWj3T8jOH/hZeaTqZ7 +A0uwq9u6v6jVkgxocEkCgcEAhyMPyiMqqq55qD6JlPY4zf4mWQJS4MnmWexH/5N1 +a6uogerwZnIjuH0/wNc2qzQSOwVJRqjlxRZbEkWST0JK/meXZ+e0nqaROWICutO6 +ciIf2wVjTzn1f85DHwPhUf3P2zIfpVFh+XuvSb32J+pzNwK40gMhirYMDSbsm/RQ +JrJHQwEX9BvI6IP5kaMOMlSwiG3Soo3MxeJWmozkz09+cs7BwMFsUKOdqruJHSaw +/Q06DQ9u9UyjmLyKv3IkN/cK -----END PRIVATE KEY----- Certificate: Data: @@ -47,38 +47,38 @@ Certificate: Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Validity Not Before: Aug 29 14:23:16 2018 GMT - Not After : Oct 28 14:23:16 2037 GMT + Not After : Oct 28 14:23:16 2525 GMT Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: - 00:a0:2a:28:71:0b:ed:a0:ed:de:cc:25:f2:14:05: - f1:56:8a:e3:30:c6:0d:16:85:dc:4f:c8:65:33:30: - 08:de:c5:b1:0e:1e:8d:28:8e:7b:71:3d:d1:fd:29: - 84:70:88:a4:4a:6f:d8:e7:9b:35:e9:d8:22:93:86: - a0:58:24:87:ad:ab:fd:cb:61:9a:78:6e:f0:c9:fe: - 15:42:2f:d7:b8:8e:ab:b5:97:ec:1d:f4:39:2a:84: - a6:7a:f5:be:82:d7:f7:75:d8:90:0a:bc:2e:53:21: - 3f:bf:6f:b1:20:95:85:3c:28:c3:71:d9:63:b9:2b: - 12:09:79:5a:57:eb:c8:e7:e3:d6:2d:53:38:34:85: - 3d:10:89:78:f8:7a:e8:1b:0e:4d:4b:d5:ff:7d:c6: - 0b:e4:1d:a5:56:55:0c:62:e8:c1:4d:58:72:6a:ff: - 15:d4:6f:c1:3f:85:df:d0:de:86:9d:37:50:57:31: - 69:7d:3f:8e:83:e1:1f:98:18:a4:10:75:91:64:c0: - 42:6c:6e:a8:a3:16:f5:96:6c:ea:1a:cf:b4:c5:c5: - ff:27:d2:ae:b5:eb:cd:37:69:72:df:69:68:a4:7c: - 45:cb:9f:39:c4:bc:aa:3b:bf:21:22:be:d4:ff:cb: - 5e:0d:9b:e4:a2:47:79:d2:e8:4d:32:0e:df:20:99: - e1:dd:68:77:2b:99:04:fe:c9:0e:b2:34:e6:03:09: - c7:de:60:cf:ab:06:eb:ce:50:73:ee:76:33:32:d2: - 4f:0a:ff:42:0f:8c:3a:34:28:07:2d:28:f1:f4:51: - 56:f2:0c:13:0a:0d:d1:90:db:e2:e1:44:52:ec:19: - 71:e5:0f:d6:f4:e4:fc:61:a9:35:0b:7b:72:de:2b: - a2:99:fa:2b:86:6d:6b:70:54:b6:8b:e5:2e:36:5a: - 20:80:61:73:52:84:4d:4a:a3:44:3b:c2:e8:00:8a: - 9a:57:09:ff:9a:58:fd:d6:c7:d6:53:ae:c7:e2:0c: - 16:c8:7e:76:39:9a:57:dd:1b:dd + 00:ee:36:70:aa:61:6a:20:bb:32:88:07:73:f0:3a: + ca:11:cc:8f:30:80:d7:71:c7:74:62:20:94:88:b4: + 52:12:94:08:01:e1:79:18:cc:f0:69:8b:99:c5:47: + c1:82:aa:ae:c8:51:04:3e:89:8c:1d:65:ad:f2:1f: + a5:f5:d4:87:65:ac:2c:78:80:37:50:15:21:4e:7a: + 09:c6:e3:5a:2a:bf:b1:b0:04:41:6f:ab:ac:65:a3: + 0a:68:68:6c:3e:e7:ff:3f:b0:95:ff:55:4e:38:ac: + bf:7f:7e:23:15:4d:b7:a1:32:13:12:ff:3e:67:4d: + 26:12:00:25:7b:b1:15:e7:c1:6e:13:ea:5d:8e:77: + be:c5:cc:f0:63:9d:a1:45:0c:da:f9:18:8a:22:0f: + 89:8d:48:9d:f9:b7:4e:6d:96:21:9c:cf:42:32:13: + 94:c6:47:a9:08:10:53:48:1f:9b:61:78:7a:09:27: + 82:42:e2:e2:f2:58:9c:1e:26:9c:43:c7:5d:27:8d: + 64:70:28:df:ed:5e:6f:05:9c:74:0f:31:10:14:97: + 6c:0c:d3:b4:19:10:8d:72:7f:35:2b:d3:4f:e8:1b: + 67:69:3e:73:f2:36:1f:ba:a7:69:5d:f0:94:b4:83: + 6f:cf:77:6a:50:2f:c3:ad:98:cd:9c:0d:c3:79:13: + ea:82:11:6d:54:54:82:79:ff:f6:9d:f2:95:1c:a1: + 0c:32:44:80:51:38:96:da:92:ab:fa:15:c5:53:76: + 04:e8:82:8a:b9:56:ef:93:e9:35:45:2d:22:12:bd: + 5b:e9:b1:5d:0c:b5:3f:c7:f7:ff:53:b4:29:ea:3b: + 09:62:13:cb:3c:91:bd:cd:8d:04:fc:7b:bd:95:1c: + d7:78:dd:b5:4f:13:80:de:43:e5:e5:6c:ca:0a:cd: + 5f:86:3a:64:87:49:fc:d2:39:90:7d:91:27:12:98: + 67:79:60:3f:3b:f3:74:db:2f:cf:fb:36:7d:44:45: + 07:56:a9:a8:b1:18:8d:fa:f8:11 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: @@ -90,9 +90,9 @@ Certificate: X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: - 3F:B1:E9:4F:A0:BE:30:66:3E:0A:18:C8:0F:47:1A:4F:34:6A:0F:42 + 16:22:C9:AA:20:D4:F4:8E:ED:9C:A6:BB:23:F5:F2:29:44:ED:F2:1E X509v3 Authority Key Identifier: - keyid:F3:EC:94:8E:F2:8E:30:C4:8E:68:C2:BF:8E:6A:19:C0:C1:9F:76:65 + keyid:C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server serial:CB:2D:80:99:5A:69:52:5B Authority Information Access: @@ -103,59 +103,59 @@ Certificate: URI:http://testca.pythontest.net/testca/revocation.crl Signature Algorithm: sha256WithRSAEncryption Signature Value: - ca:34:ba:c5:d0:cf:27:31:32:d6:0d:27:30:b8:db:17:df:b7: - 39:a7:bb:b1:3b:86:c4:31:fd:fb:ab:db:63:1a:cc:90:ab:b9: - 4e:ab:34:49:0c:5e:8c:3e:70:a3:a7:6b:2f:a7:9a:25:7b:01: - 5a:18:96:48:76:f8:36:78:74:fa:bc:7d:68:7f:e5:ca:a6:9d: - 7b:dc:72:bd:a3:25:51:17:68:e8:e9:d7:02:86:2c:7d:16:7c: - b5:dc:44:b2:0a:e3:f7:c9:33:a3:51:36:83:bc:d4:70:cd:84: - 91:9f:06:ba:2d:d2:05:0a:65:c3:d9:55:09:a8:b8:09:69:bb: - 93:86:c2:b7:c2:90:74:7c:bf:f0:5d:bc:0e:63:13:8c:eb:fa: - 0f:f1:fa:e5:12:70:4d:0c:eb:8c:2e:a2:42:42:00:04:0f:fc: - f9:1f:41:9c:63:78:f0:66:93:b2:8f:2e:e8:93:1c:50:cb:2d: - 7f:b6:ba:57:6f:52:62:d7:39:0b:09:82:ab:a6:53:4d:cc:05: - 3e:19:f0:d4:c0:ce:a9:ad:10:ce:b9:71:e4:8f:f2:5a:3c:65: - ba:dc:cb:e0:04:90:2b:a5:15:a6:7d:da:dc:a3:b5:b7:bc:a0: - de:30:4e:64:cb:17:0d:3a:a0:52:d2:67:3b:a2:3a:00:d5:39: - aa:61:75:52:9f:fe:9b:c0:e8:a0:69:af:a8:b3:a3:1d:0a:40: - 52:04:e7:3d:c0:00:96:5f:2b:33:06:0c:30:f6:d3:18:72:ee: - 38:d0:64:d3:00:86:37:ec:4f:e9:38:49:e6:01:ff:a2:9a:7c: - dc:6a:d3:cb:a8:ba:58:fb:c3:86:78:47:f1:06:a6:45:e7:53: - de:99:1d:81:e6:bc:63:74:46:7c:70:23:57:29:60:70:9a:cc: - 6f:00:8e:c2:bf:6a:73:7d:6e:b0:62:e6:dc:13:1a:b9:fe:0f: - c2:d1:06:a1:79:62:7f:b6:30:a9:03:d0:47:57:25:db:48:10: - d1:cf:fb:7d:ac:3d + 43:82:1f:18:b4:cb:7a:b7:4e:ac:c3:65:2e:b7:57:3a:f0:78: + b3:b2:20:3e:bd:7b:24:f7:e7:17:cc:62:c0:b8:63:f0:2e:30: + 0c:54:be:c9:94:7c:54:d4:40:06:6e:92:9d:72:2c:44:f5:e3: + c1:4a:3f:26:e4:21:ca:ba:ef:4f:a3:50:56:ee:89:5c:dc:5b: + 98:bc:0c:e9:db:16:98:f0:4c:3f:65:b9:d9:e0:2e:bd:83:9e: + c7:1b:f7:4f:87:5f:75:ff:67:5d:0a:ff:ce:fa:0b:f1:d5:8b: + 58:23:2b:92:27:b8:15:ff:66:c2:f9:68:e2:ed:64:a0:4a:e0: + 42:8b:ac:35:6a:67:64:f5:cb:a9:00:37:20:56:dd:3a:02:6e: + d8:0f:b4:5d:ff:92:a3:0d:65:fc:2e:ab:4e:37:bc:7e:d6:5b: + 1c:55:78:a0:6e:a9:2e:55:31:cf:61:f0:1b:4c:fe:fe:60:75: + 76:e8:d9:a1:f5:14:f0:43:33:4d:52:05:be:33:ff:da:31:94: + bd:0d:e5:4d:a8:ee:d1:f3:92:34:c2:36:91:37:3a:6d:ec:20: + df:b3:9e:a2:5d:d0:f0:a1:e2:ff:b7:85:ce:09:e3:c8:4a:6a: + 93:a4:ae:ec:c1:67:42:f7:8e:2f:64:ca:d7:76:72:bf:3f:ef: + 64:ff:10:dd:a2:3e:2d:f5:aa:02:cf:31:f0:6d:93:6b:56:4c: + b0:88:95:54:dc:d4:ac:dc:c1:88:27:8b:d9:9c:4e:66:93:f8: + dd:5e:74:41:26:9a:ef:e8:c8:46:5c:d5:f4:fc:cd:cc:67:c7: + 33:62:2e:70:9b:d1:39:de:34:fd:ad:9d:b9:48:61:e7:89:53: + 62:62:f0:40:6c:68:2f:e1:da:40:61:2a:50:af:c9:41:6d:98: + 16:af:cb:63:03:ec:04:99:e0:39:98:60:ae:aa:6a:57:9b:25: + 73:03:16:bf:78:c8:d7:2f:eb:fc:64:7f:c7:78:8c:34:15:5b: + 66:40:98:86:e6:0a -----BEGIN CERTIFICATE----- -MIIF8TCCBFmgAwIBAgIJAMstgJlaaVJcMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIF8zCCBFugAwIBAgIJAMstgJlaaVJcMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj -MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxv -Y2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKAqKHEL7aDt -3swl8hQF8VaK4zDGDRaF3E/IZTMwCN7FsQ4ejSiOe3E90f0phHCIpEpv2OebNenY -IpOGoFgkh62r/cthmnhu8Mn+FUIv17iOq7WX7B30OSqEpnr1voLX93XYkAq8LlMh -P79vsSCVhTwow3HZY7krEgl5WlfryOfj1i1TODSFPRCJePh66BsOTUvV/33GC+Qd -pVZVDGLowU1Ycmr/FdRvwT+F39Dehp03UFcxaX0/joPhH5gYpBB1kWTAQmxuqKMW -9ZZs6hrPtMXF/yfSrrXrzTdpct9paKR8RcufOcS8qju/ISK+1P/LXg2b5KJHedLo -TTIO3yCZ4d1odyuZBP7JDrI05gMJx95gz6sG685Qc+52MzLSTwr/Qg+MOjQoBy0o -8fRRVvIMEwoN0ZDb4uFEUuwZceUP1vTk/GGpNQt7ct4ropn6K4Zta3BUtovlLjZa -IIBhc1KETUqjRDvC6ACKmlcJ/5pY/dbH1lOux+IMFsh+djmaV90b3QIDAQABo4IB -wDCCAbwwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA4GA1UdDwEB/wQEAwIFoDAdBgNV -HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E -FgQUP7HpT6C+MGY+ChjID0caTzRqD0IwfQYDVR0jBHYwdIAU8+yUjvKOMMSOaMK/ -jmoZwMGfdmWhUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcoIJAMst -gJlaaVJbMIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly90ZXN0 -Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1BggrBgEFBQcw -AYYpaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2NzcC8wQwYD -VR0fBDwwOjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0 -Y2EvcmV2b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGBAMo0usXQzycxMtYN -JzC42xfftzmnu7E7hsQx/fur22MazJCruU6rNEkMXow+cKOnay+nmiV7AVoYlkh2 -+DZ4dPq8fWh/5cqmnXvccr2jJVEXaOjp1wKGLH0WfLXcRLIK4/fJM6NRNoO81HDN -hJGfBrot0gUKZcPZVQmouAlpu5OGwrfCkHR8v/BdvA5jE4zr+g/x+uUScE0M64wu -okJCAAQP/PkfQZxjePBmk7KPLuiTHFDLLX+2uldvUmLXOQsJgqumU03MBT4Z8NTA -zqmtEM65ceSP8lo8Zbrcy+AEkCulFaZ92tyjtbe8oN4wTmTLFw06oFLSZzuiOgDV -OaphdVKf/pvA6KBpr6izox0KQFIE5z3AAJZfKzMGDDD20xhy7jjQZNMAhjfsT+k4 -SeYB/6KafNxq08uoulj7w4Z4R/EGpkXnU96ZHYHmvGN0RnxwI1cpYHCazG8AjsK/ -anN9brBi5twTGrn+D8LRBqF5Yn+2MKkD0EdXJdtIENHP+32sPQ== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowXzELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4 +MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJ +bG9jYWxob3N0MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA7jZwqmFq +ILsyiAdz8DrKEcyPMIDXccd0YiCUiLRSEpQIAeF5GMzwaYuZxUfBgqquyFEEPomM +HWWt8h+l9dSHZawseIA3UBUhTnoJxuNaKr+xsARBb6usZaMKaGhsPuf/P7CV/1VO +OKy/f34jFU23oTITEv8+Z00mEgAle7EV58FuE+pdjne+xczwY52hRQza+RiKIg+J +jUid+bdObZYhnM9CMhOUxkepCBBTSB+bYXh6CSeCQuLi8licHiacQ8ddJ41kcCjf +7V5vBZx0DzEQFJdsDNO0GRCNcn81K9NP6BtnaT5z8jYfuqdpXfCUtINvz3dqUC/D +rZjNnA3DeRPqghFtVFSCef/2nfKVHKEMMkSAUTiW2pKr+hXFU3YE6IKKuVbvk+k1 +RS0iEr1b6bFdDLU/x/f/U7Qp6jsJYhPLPJG9zY0E/Hu9lRzXeN21TxOA3kPl5WzK +Cs1fhjpkh0n80jmQfZEnEphneWA/O/N02y/P+zZ9REUHVqmosRiN+vgRAgMBAAGj +ggHAMIIBvDAUBgNVHREEDTALgglsb2NhbGhvc3QwDgYDVR0PAQH/BAQDAgWgMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1Ud +DgQWBBQWIsmqINT0ju2cprsj9fIpRO3yHjB9BgNVHSMEdjB0gBTACisoQ95fyX1H +5UebNvJljGc74qFRpE8wTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5dGhvbiBT +b2Z0d2FyZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2VydmVyggkA +yy2AmVppUlswgYMGCCsGAQUFBwEBBHcwdTA8BggrBgEFBQcwAoYwaHR0cDovL3Rl +c3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2EvcHljYWNlcnQuY2VyMDUGCCsGAQUF +BzABhilodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9vY3NwLzBD +BgNVHR8EPDA6MDigNqA0hjJodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rl +c3RjYS9yZXZvY2F0aW9uLmNybDANBgkqhkiG9w0BAQsFAAOCAYEAQ4IfGLTLerdO +rMNlLrdXOvB4s7IgPr17JPfnF8xiwLhj8C4wDFS+yZR8VNRABm6SnXIsRPXjwUo/ +JuQhyrrvT6NQVu6JXNxbmLwM6dsWmPBMP2W52eAuvYOexxv3T4dfdf9nXQr/zvoL +8dWLWCMrkie4Ff9mwvlo4u1koErgQousNWpnZPXLqQA3IFbdOgJu2A+0Xf+Sow1l +/C6rTje8ftZbHFV4oG6pLlUxz2HwG0z+/mB1dujZofUU8EMzTVIFvjP/2jGUvQ3l +Taju0fOSNMI2kTc6bewg37Oeol3Q8KHi/7eFzgnjyEpqk6Su7MFnQveOL2TK13Zy +vz/vZP8Q3aI+LfWqAs8x8G2Ta1ZMsIiVVNzUrNzBiCeL2ZxOZpP43V50QSaa7+jI +RlzV9PzNzGfHM2IucJvROd40/a2duUhh54lTYmLwQGxoL+HaQGEqUK/JQW2YFq/L +YwPsBJngOZhgrqpqV5slcwMWv3jI1y/r/GR/x3iMNBVbZkCYhuYK -----END CERTIFICATE----- diff --git a/Lib/test/certdata/keycert3.pem.reference b/Lib/test/certdata/keycert3.pem.reference index 04a749c920b38c..84d2ca29953e46 100644 --- a/Lib/test/certdata/keycert3.pem.reference +++ b/Lib/test/certdata/keycert3.pem.reference @@ -4,7 +4,7 @@ 'issuer': ((('countryName', 'XY'),), (('organizationName', 'Python Software Foundation CA'),), (('commonName', 'our-ca-server'),)), - 'notAfter': 'Oct 28 14:23:16 2037 GMT', + 'notAfter': 'Oct 28 14:23:16 2525 GMT', 'notBefore': 'Aug 29 14:23:16 2018 GMT', 'serialNumber': 'CB2D80995A69525C', 'subject': ((('countryName', 'XY'),), @@ -12,4 +12,4 @@ (('organizationName', 'Python Software Foundation'),), (('commonName', 'localhost'),)), 'subjectAltName': (('DNS', 'localhost'),), - 'version': 3} \ No newline at end of file + 'version': 3} diff --git a/Lib/test/certdata/keycert4.pem b/Lib/test/certdata/keycert4.pem index ff4dceac7907c5..fcaa3a1656d1a5 100644 --- a/Lib/test/certdata/keycert4.pem +++ b/Lib/test/certdata/keycert4.pem @@ -1,42 +1,42 @@ -----BEGIN PRIVATE KEY----- -MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDGKA1zZDjeNPh2 -J9WHVXXMUf8h5N4/bHCM3CbIaZ1dShkCgfmFWmOtruEihgbfRYaSWZAwCmVAQGjm -gvUfgOIgsFfM8yO+zDByPhza7XvWPZfEe7mNRFe5ZlYntbeM/vuWCM4VzwDq/mqF -TFxNRmwInqE7hx0WnfCoQWe9N41hJyl1K0OjADb+SjlpJ0/UJ63hsB+dowGjaaBv -J8HduQcRqNg8s6FcyJJ8Mjss1uRMFK2j9QrmgbA61XuIPCxzc3J57mW8FN2KsR8D -2HOhe9nsTGlxp+O5Cudf/RBWB443xcoyduwRXOFTdEAU45MS4tKGP2hzezuxMFQn -LKARXVW4/gFxZk7kU8TweZUS6LAYPfYJnlfteb6z37LAbtoDvzKUKBEDf/nmoa7C -uKxSPC5HIKhLbjU/6kuPglSVEfJPJWu2bZJDAkFL85Ot3gPs10EX2lMUy0Jt3tf+ -TaQjEvFZhpKN8KAdYj3eVgOfzIBbQyjotHJjFe9Jkq4q7RoI+ncCAwEAAQKCAYAH -tRsdRh1Z7JmHOasy+tPDsvhVuWLHMaYlScvAYhJh/W65YSKd56+zFKINlX3fYcp5 -Fz67Yy+uWahXVE2QgFou3KX0u+9ucRiLFXfYheWL3xSMXJgRee0LI/T7tRe7uAHu -CnoURqKCulIqzLOO1efx1eKasXmVuhEtmjhVpcmDGv8SChSKTIjzgOjqT7QGE9Xq -eSRhq7mulpq9zWq+/369yG+0SvPs60vTxNovDIaBn/RHSW5FjeDss5QnmYMh/ukN -dggoKllQlkTzHSxHmKrIJuryZC+bsqvEPUFXN0NMUYcZRvt1lwdjzq/A+w4gDDZG -7QqAzYMYQZMw9PJeHqu4mxfUX5hJWuAwG5I2eV3kBRheoFw7MxP0tw40fPlFU+Zh -pRXbKwhMAlIHi0D8NyMn3hkVPyToWVVY3vHRknBB/52RqRq3MjqEFaAZfp0nFkiF -ytv3Dd5aeBb1vraOIREyhxIxE/qY8CtZC+6JI8CpufLmFXB412WPwl0OrVpWYfEC -gcEA486zOI46xRDgDw0jqTpOFHzh+3VZ8UoPoiqCjKzJGnrh2EeLvTsXX/GZOj0m -5zl6RHEGFjm5vKCh2C72Vj/m+AFVy7V9iJRzTYzP8So/3paaqo7ZaROTa6uStxdD -VPnY1uIgVQz9w5coN4dmr+RLBpFvvWaHp1wuC08YIWxcC9HSTQpbi1EP5eo08fOk -8reNkDEHxihDGHr1xW0z0qJqK1IVyLP7wDkmapudMZjkjqJSGJwwefV4qyGMTV2b -suW1AoHBAN6t9n6LBH553MF5iUrNJYxXh/SCom4Zft9aD6W4bZV/xL4XPpKBB4HX -aWdeI0iYZU9U+CZ88tBoQCt+JMrJ9cz03ENOvA/MBMREwbZ2hKmQgnoDZsV0vNry -6UsxeQmeNpGQFUz9foVJQVRdQCceN2YEABdehV1HZoSBbuGZkzqGJXrWwaf/ZhpB -dPYGUGOsczoD2/QLuWy2M7f7v0Ews6Heww3zipWzvdxKE0IpyVs30ZwVi8CRQiWU -bEcleXP6+wKBwAi3xEwJxV39Q1XQHuk+/fXywYMp/oMpXmfKUKypgBivUy0/r61S -MZbOXBrKdE6s+GzeFmmLU/xP+WGYinzKfUBIbMwa6e7sH218UgjcoQ0Xnlugk9ld -kmqwajDvhvgdh5rRlIMsuBlgE33shJV+mxBpSGlrHw3cjTaJlFbTGsKpCO9B0jcG -pyEZUWVg+ZMASz6VYcLHj6nEKtufTjhlVsLJpWPE34F/rmSuB9n6C+UZeSLP91rz -dea2pfPf/TFfcQKBwF4DSj9Qx/vxzS7t9fXbuM+QoPitMpCTOQppRpPr0nA8uj6b -J7LIwPejj3+xsenTVWpx8DanqAgvC3CRWE05iQoYEupj0mhE9Xo7oSE81nOUbFHB -H+GbkKRLzA0P/Q7/egBouWWA3Kq/K9LHb+9UBYWPiM5U/K9OFs04rCyZHxylSCud -gbNA08Wf/xZjwgri4t8KhBF75bQtFJbHtY57Vkuv9d/tA4SCl1Tq/UiAxd86KMfi -HNeXPDsLd89t1eIOgwKBwQDJkqwZXkhwkhoNuHRdzPO/1f5FyKpQxFs+x+OBulzG -zuwVKIawsLlUR4TBtF7PChOSZSH50VZaBI5kVti79kEtfNjfAzg4kleHrY8jQ/eq -HludZ3nmiPqqlbH4MH8NWczPEjee6z4ODROsAe31pz3S8YQK7KVoEuSf0+usJ894 -FtzS5wl6POAXTo2QeSNg9zTbb6JjVYcq6KCTnflDm4YEvFKI+ARqAXQHxm05wEOe -DbKC6hxxQbDaNOvXEAda8wU= +MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQC/uCI/4eVSCIrx +//GcCCxeQP16Mtf0wAuINBR9uTySF8sEVoS6rNBwLeudZXaHmcp3jM7N2e9GjI8d +dQccPApKBwjAxhdT4XeuUTep4VraKWjLTWDvABHfCVFB1tX3HusEWaS8n/pH+N4L +UfnxS3HnFqGC5ib2DSgFTCnLQSj82iUgACdf87iZTons+kRvqYsdwpsgBUnO+w+o +c5o7Nj1bJJlTREsY6kQGY94as4pCkmqhoBTC7/le9wFGmXipRYi3pfSTOqAQJfqW +1VlQ4Bbc3lN5L+ONTmFXOgTJ5qhaS8cglnYElJI1QQTagyWQMHuBDIMpr3Iv/5qU +UzdIMzoMrpX6ien3Gan/jyjjzvP95jJvGujQudw/myXK8VOUThVtstRDFA3cIoV4 +UqMODz8w6qYU0GPYFBq//1UdpDrk/fBPBe3MLJT2+sB/kTzwxxYsKqcdjPG2Bt3Y +2nk7hCzE0KuueqCQPk/3fomY1TDyTlWOriAS40EYue5Rhx9qr8kCAwEAAQKCAYAL +X7EoeQ5Rv4/+q2B6EUIQlWp0RW/qZTpJ6k0M6GBfimnQ6BEXwgjbnt3LiKlvggAw +93mNXNCFLvGOndK+KhGyMpiiVx4rK8Ud4lObEHODXdGJvh1yEF7/DF51uXkYIA1x +RKAxUIxYmLsTkNlzJzaqrv0F9wF4t28YYVxZYpQ76/Un4Np1JtBcx/wGwxIsTbKj +IVhynd2zGdHj/He5643YSmOOPQ73e25tsp8KlnwtVuJclFKm/fWdXKoGtjQiVq2b +bViG7WTqb+a+R3IrO8CE2vAQ1ZqklP4Pg33AU1XFogRweqSkXvBGy1GHSSXCO4uX +gORj/bo/gAZ/eeufwqxBxJMS4Kbmxes/oYEgJidoaeA6DZjcKr+J3rFUt9j6rpxt +abeKBiK6wTHkKAdQwoccDdKFROvL4ZEu4zpjkmiqDrtIZEqtB8YCvoMpteIqrBhr +stLCDrftsysBTNGNn0THb4H5wx8nkZPCVyvaBD4N4Skp5rapP2bbrPhigcOoR8EC +gcEA4ToVg2b09tLWpmCg6XXssT1SvvFcSaJ3jjRKMfpmP5epWFiZ21qAOCbYhMNu +2G21AyNd1W7oVi6epXsB2YBOlSI0Fr6RuN0fDwg5jZLxEkEqDsL2QKsgoKHtGfBn +gX9jLQ5Lsy5/0CRXYCfPjdccbr2J5Gm2fU/jhhCi9ji/6b2RbgrRkIkr2I/J6KbS +sO+p1d93CFNagLMbdDspugDlIgj52OBMYO60nDlNU8O2pkAcLQTpWVqEjmoo4Q4K +oyOXAoHBANnqB93sLCndEiZNth7cOOEhNKCWRDkpGwDBbn2Dj3kBaXg8eCTG7tiF +FPyNVydYg+u0vcPIjj9URsOfpHc9MLSYtKAgCL3rSk+OQnROeg9hCjmB5Ucg7NTR +gSh/flfWp/q1EDeOVAu8B9DuBX1209br4xi78LnBP5/UzRjhuFEmvCvOqVCMCI7Y +I1k3l4NhOk87fKq5dbtxvNTU2eFTtt1+YjYwZFY+AUmx3WBz+aFwygks3S4SvN1J +LtLVYhOznwKBwQDC047WixIuDLX3WDD5orOroeNZHsn5PFv1HBBuaS9XpSatMH9u ++ztc12WGetQAze2+GDLMNNMv8cX0WZKBBfd0FBFA93pwkn6Sb0fxyoFUjCAIguen +iyB/M3M5c/blUz+EMxCSoA+aCkW2/NkS1lhXBwgoGLXuclPbnbqKCQ8h74TEzwD2 +6WGPRNqgsOYifj7IrjR2dDwehlCiW6c9qhaLOX5+94+6beK4HO1iHzN5Xo3A97Wv +QJjX5McV3yKeemMCgcA4N3reEo52IlULUqL4JSH7WkCkaP+iq2sO79fcQ3Ng6S9X +WGo6OqPlcbevS5s/SEOILDGEb5na1pgG4YlhRYTqIjb+1CTNMgUSrwWP0asFiqhD +m7IVfnX6lS23z+Q9LuBY+hr76hjeihyOFsmNy3jtCh+lAt8gXK1YQ2LB14FgVhjX +SFI/uFCA4VuFKaVJvGx5gkQwGvY3bCkl0t9+lMUpMPCPQD6yTP6yD1OoDWNJ9bn5 +UfyhZS4Z/EY7F9dcc8sCgcEAi8yW4gNCZSsGQRLh+fyDCSdak4ahATAeiI24231u +jK5+ncK9ZoZvzO/h+V5bw7ha59rD8aGmrLqzBVKEMi0PAT38psNH9ZtRt9y29YQ8 +WpyHtODMbphfbH4SFH3nj3PldRtBcOt0EDdp/4s64A9qdOWRx/vlJhdg0vtWTy5s +koyyOHhTcplpyPPq0BetYKl9UlXPVjus/RT1XV/lz2YrE8E9UAq+/r7ECoMExaZt +8j8J8O3lTWPxNTaQuiPiHA7E -----END PRIVATE KEY----- Certificate: Data: @@ -47,38 +47,38 @@ Certificate: Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Validity Not Before: Aug 29 14:23:16 2018 GMT - Not After : Oct 28 14:23:16 2037 GMT + Not After : Oct 28 14:23:16 2525 GMT Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=fakehostname Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: - 00:c6:28:0d:73:64:38:de:34:f8:76:27:d5:87:55: - 75:cc:51:ff:21:e4:de:3f:6c:70:8c:dc:26:c8:69: - 9d:5d:4a:19:02:81:f9:85:5a:63:ad:ae:e1:22:86: - 06:df:45:86:92:59:90:30:0a:65:40:40:68:e6:82: - f5:1f:80:e2:20:b0:57:cc:f3:23:be:cc:30:72:3e: - 1c:da:ed:7b:d6:3d:97:c4:7b:b9:8d:44:57:b9:66: - 56:27:b5:b7:8c:fe:fb:96:08:ce:15:cf:00:ea:fe: - 6a:85:4c:5c:4d:46:6c:08:9e:a1:3b:87:1d:16:9d: - f0:a8:41:67:bd:37:8d:61:27:29:75:2b:43:a3:00: - 36:fe:4a:39:69:27:4f:d4:27:ad:e1:b0:1f:9d:a3: - 01:a3:69:a0:6f:27:c1:dd:b9:07:11:a8:d8:3c:b3: - a1:5c:c8:92:7c:32:3b:2c:d6:e4:4c:14:ad:a3:f5: - 0a:e6:81:b0:3a:d5:7b:88:3c:2c:73:73:72:79:ee: - 65:bc:14:dd:8a:b1:1f:03:d8:73:a1:7b:d9:ec:4c: - 69:71:a7:e3:b9:0a:e7:5f:fd:10:56:07:8e:37:c5: - ca:32:76:ec:11:5c:e1:53:74:40:14:e3:93:12:e2: - d2:86:3f:68:73:7b:3b:b1:30:54:27:2c:a0:11:5d: - 55:b8:fe:01:71:66:4e:e4:53:c4:f0:79:95:12:e8: - b0:18:3d:f6:09:9e:57:ed:79:be:b3:df:b2:c0:6e: - da:03:bf:32:94:28:11:03:7f:f9:e6:a1:ae:c2:b8: - ac:52:3c:2e:47:20:a8:4b:6e:35:3f:ea:4b:8f:82: - 54:95:11:f2:4f:25:6b:b6:6d:92:43:02:41:4b:f3: - 93:ad:de:03:ec:d7:41:17:da:53:14:cb:42:6d:de: - d7:fe:4d:a4:23:12:f1:59:86:92:8d:f0:a0:1d:62: - 3d:de:56:03:9f:cc:80:5b:43:28:e8:b4:72:63:15: - ef:49:92:ae:2a:ed:1a:08:fa:77 + 00:bf:b8:22:3f:e1:e5:52:08:8a:f1:ff:f1:9c:08: + 2c:5e:40:fd:7a:32:d7:f4:c0:0b:88:34:14:7d:b9: + 3c:92:17:cb:04:56:84:ba:ac:d0:70:2d:eb:9d:65: + 76:87:99:ca:77:8c:ce:cd:d9:ef:46:8c:8f:1d:75: + 07:1c:3c:0a:4a:07:08:c0:c6:17:53:e1:77:ae:51: + 37:a9:e1:5a:da:29:68:cb:4d:60:ef:00:11:df:09: + 51:41:d6:d5:f7:1e:eb:04:59:a4:bc:9f:fa:47:f8: + de:0b:51:f9:f1:4b:71:e7:16:a1:82:e6:26:f6:0d: + 28:05:4c:29:cb:41:28:fc:da:25:20:00:27:5f:f3: + b8:99:4e:89:ec:fa:44:6f:a9:8b:1d:c2:9b:20:05: + 49:ce:fb:0f:a8:73:9a:3b:36:3d:5b:24:99:53:44: + 4b:18:ea:44:06:63:de:1a:b3:8a:42:92:6a:a1:a0: + 14:c2:ef:f9:5e:f7:01:46:99:78:a9:45:88:b7:a5: + f4:93:3a:a0:10:25:fa:96:d5:59:50:e0:16:dc:de: + 53:79:2f:e3:8d:4e:61:57:3a:04:c9:e6:a8:5a:4b: + c7:20:96:76:04:94:92:35:41:04:da:83:25:90:30: + 7b:81:0c:83:29:af:72:2f:ff:9a:94:53:37:48:33: + 3a:0c:ae:95:fa:89:e9:f7:19:a9:ff:8f:28:e3:ce: + f3:fd:e6:32:6f:1a:e8:d0:b9:dc:3f:9b:25:ca:f1: + 53:94:4e:15:6d:b2:d4:43:14:0d:dc:22:85:78:52: + a3:0e:0f:3f:30:ea:a6:14:d0:63:d8:14:1a:bf:ff: + 55:1d:a4:3a:e4:fd:f0:4f:05:ed:cc:2c:94:f6:fa: + c0:7f:91:3c:f0:c7:16:2c:2a:a7:1d:8c:f1:b6:06: + dd:d8:da:79:3b:84:2c:c4:d0:ab:ae:7a:a0:90:3e: + 4f:f7:7e:89:98:d5:30:f2:4e:55:8e:ae:20:12:e3: + 41:18:b9:ee:51:87:1f:6a:af:c9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: @@ -90,9 +90,9 @@ Certificate: X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: - 1C:70:14:B0:20:DD:08:76:A4:3B:56:59:FA:5F:34:F8:36:66:E8:56 + E4:3D:4C:DB:96:85:CC:90:ED:0F:58:1E:8D:4D:7D:34:6C:4E:11:10 X509v3 Authority Key Identifier: - keyid:F3:EC:94:8E:F2:8E:30:C4:8E:68:C2:BF:8E:6A:19:C0:C1:9F:76:65 + keyid:C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server serial:CB:2D:80:99:5A:69:52:5B Authority Information Access: @@ -103,59 +103,59 @@ Certificate: URI:http://testca.pythontest.net/testca/revocation.crl Signature Algorithm: sha256WithRSAEncryption Signature Value: - 75:14:e5:68:45:8d:ed:6c:f1:27:1e:0e:f3:35:ae:0e:60:c1: - 65:36:62:b8:07:78:e1:b9:8d:7a:50:70:af:06:c9:d4:ee:50: - ef:d2:76:b2:a2:b6:cb:dc:a6:18:b5:3d:d2:f7:eb:0e:ec:b7: - 95:cd:2e:b1:36:6f:a8:9f:b8:4d:ff:ce:8a:c4:8e:62:37:32: - 80:3e:05:4a:4d:39:87:69:09:00:e8:40:64:d2:9d:f9:1f:9f: - ab:67:1f:f9:c6:84:ba:7e:17:6c:8b:8d:08:ee:fb:8a:d7:cd: - 06:25:72:9f:4e:1a:c2:71:e1:1b:cf:a2:d7:1c:05:12:95:d6: - 49:4b:e9:95:95:89:cf:68:18:46:a3:ea:0d:9d:8e:ca:1c:28: - 55:49:6b:c0:4b:58:f5:42:b9:0a:ec:0e:6e:21:a4:ff:60:c0: - 1b:6e:40:72:d0:a5:c5:b5:db:4e:87:67:3a:31:70:cb:32:84: - 70:a9:e2:ff:e0:f2:db:cd:03:b4:85:45:d3:07:cc:0f:c7:49: - d8:c2:17:eb:73:f7:4a:c0:d9:8c:59:ef:c0:0a:ce:13:0b:84: - c9:aa:0d:11:14:b4:e5:74:aa:ec:18:de:5f:26:18:98:4a:76: - f0:7f:cd:e6:c4:b5:58:03:03:f5:10:01:5d:8f:63:88:ba:65: - d7:b4:7f:5a:1a:51:0e:ed:e5:68:fa:18:03:72:15:a1:ec:27: - 1f:ea:ac:24:46:18:6e:f1:97:db:4a:f4:d6:a1:91:a0:8c:b0: - 2f:be:87:3b:44:b0:8d:2a:89:85:5f:f2:d9:e3:2e:66:b2:88: - 98:04:2c:96:32:38:99:19:a9:83:fd:94:0c:dd:63:d4:1b:60: - 9d:43:98:35:ac:b4:23:38:de:7f:85:52:57:a0:37:df:a5:cf: - be:54:2c:3c:50:27:2b:d4:54:a9:9d:a3:d4:a5:b3:c0:ea:3d: - 0e:e2:70:6b:fb:cb:a5:56:05:ec:64:72:f0:1a:db:64:01:cb: - 5d:27:c4:a1:c4:63 + 63:e9:cd:0f:ec:dd:27:a0:fc:76:16:a1:f2:5f:d3:07:9a:3f: + 97:f4:11:e8:20:e9:3c:dd:16:4f:20:62:71:73:a9:46:3e:85: + 6e:44:be:9d:08:4b:eb:80:08:d5:1b:93:5f:4a:0f:df:b7:1b: + 38:e2:2b:5c:68:48:ea:0a:58:5c:36:6c:79:a4:1e:b5:7e:ef: + cb:8d:5d:bd:7d:4a:e6:4e:dd:0b:87:10:ff:01:0e:9b:8b:bd: + de:1c:9a:25:fb:a2:e1:52:7b:8a:aa:08:37:b2:87:f7:45:9d: + 0b:ab:11:6b:0c:7f:db:ed:de:cc:1e:86:f0:be:30:25:6b:4b: + ff:f5:f2:99:ed:b0:b1:68:c1:44:0b:79:7b:81:95:b5:36:37: + 12:c4:99:9e:85:e8:2f:2d:cc:cd:d8:c6:f2:20:ec:6a:06:fd: + b8:fc:ff:02:11:95:4d:38:0d:42:8b:b2:43:eb:c2:b9:a4:e0: + 33:f1:da:25:2f:11:cf:57:b9:25:e5:ab:92:f2:b2:b5:11:2f: + bd:31:f7:55:eb:96:94:78:5a:ad:9c:8f:56:ec:34:a0:73:9c: + 01:c2:76:24:e0:f8:b3:c9:23:b9:ea:ab:c3:0a:d3:f8:53:44: + c7:12:37:76:44:d7:ee:25:93:f4:1c:1d:7c:fe:06:2c:fa:c5: + bb:c6:90:a4:57:fd:09:2e:da:af:f3:ac:e6:6d:7f:03:a1:26: + 36:9a:51:7d:8d:28:a7:5d:5d:37:57:cc:6a:11:2a:98:1d:57: + 71:32:6e:98:7c:12:28:ef:5c:2f:26:29:d4:56:0a:b1:23:d9: + 9d:35:20:1a:ec:cc:51:53:6e:ef:1c:e7:bc:3c:21:e7:64:31: + b1:4c:f3:55:b5:c4:93:17:d8:72:5a:05:2e:4a:e5:33:07:0e: + 7d:cf:22:73:0b:67:9f:b4:82:60:cd:71:f8:76:0c:c4:dc:98: + ee:49:f9:03:7f:0d:d8:c6:76:79:3c:28:ed:77:77:d3:7e:d5: + aa:1e:6e:2e:df:a5 -----BEGIN CERTIFICATE----- -MIIF9zCCBF+gAwIBAgIJAMstgJlaaVJdMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIF+TCCBGGgAwIBAgIJAMstgJlaaVJdMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaMGIxCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj -MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZh -a2Vob3N0bmFtZTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMYoDXNk -ON40+HYn1YdVdcxR/yHk3j9scIzcJshpnV1KGQKB+YVaY62u4SKGBt9FhpJZkDAK -ZUBAaOaC9R+A4iCwV8zzI77MMHI+HNrte9Y9l8R7uY1EV7lmVie1t4z++5YIzhXP -AOr+aoVMXE1GbAieoTuHHRad8KhBZ703jWEnKXUrQ6MANv5KOWknT9QnreGwH52j -AaNpoG8nwd25BxGo2DyzoVzIknwyOyzW5EwUraP1CuaBsDrVe4g8LHNzcnnuZbwU -3YqxHwPYc6F72exMaXGn47kK51/9EFYHjjfFyjJ27BFc4VN0QBTjkxLi0oY/aHN7 -O7EwVCcsoBFdVbj+AXFmTuRTxPB5lRLosBg99gmeV+15vrPfssBu2gO/MpQoEQN/ -+eahrsK4rFI8LkcgqEtuNT/qS4+CVJUR8k8la7ZtkkMCQUvzk63eA+zXQRfaUxTL -Qm3e1/5NpCMS8VmGko3woB1iPd5WA5/MgFtDKOi0cmMV70mSrirtGgj6dwIDAQAB -o4IBwzCCAb8wFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA4GA1UdDwEB/wQEAwIF -oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd -BgNVHQ4EFgQUHHAUsCDdCHakO1ZZ+l80+DZm6FYwfQYDVR0jBHYwdIAU8+yUjvKO -MMSOaMK/jmoZwMGfdmWhUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRo -b24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZl -coIJAMstgJlaaVJbMIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6 -Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1Bggr -BgEFBQcwAYYpaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2Nz -cC8wQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5l -dC90ZXN0Y2EvcmV2b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGBAHUU5WhF -je1s8SceDvM1rg5gwWU2YrgHeOG5jXpQcK8GydTuUO/SdrKitsvcphi1PdL36w7s -t5XNLrE2b6ifuE3/zorEjmI3MoA+BUpNOYdpCQDoQGTSnfkfn6tnH/nGhLp+F2yL -jQju+4rXzQYlcp9OGsJx4RvPotccBRKV1klL6ZWVic9oGEaj6g2djsocKFVJa8BL -WPVCuQrsDm4hpP9gwBtuQHLQpcW1206HZzoxcMsyhHCp4v/g8tvNA7SFRdMHzA/H -SdjCF+tz90rA2YxZ78AKzhMLhMmqDREUtOV0quwY3l8mGJhKdvB/zebEtVgDA/UQ -AV2PY4i6Zde0f1oaUQ7t5Wj6GANyFaHsJx/qrCRGGG7xl9tK9NahkaCMsC++hztE -sI0qiYVf8tnjLmayiJgELJYyOJkZqYP9lAzdY9QbYJ1DmDWstCM43n+FUlegN9+l -z75ULDxQJyvUVKmdo9Sls8DqPQ7icGv7y6VWBexkcvAa22QBy10nxKHEYw== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowYjELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4 +MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEVMBMGA1UEAwwM +ZmFrZWhvc3RuYW1lMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAv7gi +P+HlUgiK8f/xnAgsXkD9ejLX9MALiDQUfbk8khfLBFaEuqzQcC3rnWV2h5nKd4zO +zdnvRoyPHXUHHDwKSgcIwMYXU+F3rlE3qeFa2iloy01g7wAR3wlRQdbV9x7rBFmk +vJ/6R/jeC1H58Utx5xahguYm9g0oBUwpy0Eo/NolIAAnX/O4mU6J7PpEb6mLHcKb +IAVJzvsPqHOaOzY9WySZU0RLGOpEBmPeGrOKQpJqoaAUwu/5XvcBRpl4qUWIt6X0 +kzqgECX6ltVZUOAW3N5TeS/jjU5hVzoEyeaoWkvHIJZ2BJSSNUEE2oMlkDB7gQyD +Ka9yL/+alFM3SDM6DK6V+onp9xmp/48o487z/eYybxro0LncP5slyvFTlE4VbbLU +QxQN3CKFeFKjDg8/MOqmFNBj2BQav/9VHaQ65P3wTwXtzCyU9vrAf5E88McWLCqn +HYzxtgbd2Np5O4QsxNCrrnqgkD5P936JmNUw8k5Vjq4gEuNBGLnuUYcfaq/JAgMB +AAGjggHDMIIBvzAXBgNVHREEEDAOggxmYWtlaG9zdG5hbWUwDgYDVR0PAQH/BAQD +AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA +MB0GA1UdDgQWBBTkPUzbloXMkO0PWB6NTX00bE4REDB9BgNVHSMEdjB0gBTACiso +Q95fyX1H5UebNvJljGc74qFRpE8wTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5 +dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2Vy +dmVyggkAyy2AmVppUlswgYMGCCsGAQUFBwEBBHcwdTA8BggrBgEFBQcwAoYwaHR0 +cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2EvcHljYWNlcnQuY2VyMDUG +CCsGAQUFBzABhilodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9v +Y3NwLzBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3Qu +bmV0L3Rlc3RjYS9yZXZvY2F0aW9uLmNybDANBgkqhkiG9w0BAQsFAAOCAYEAY+nN +D+zdJ6D8dhah8l/TB5o/l/QR6CDpPN0WTyBicXOpRj6FbkS+nQhL64AI1RuTX0oP +37cbOOIrXGhI6gpYXDZseaQetX7vy41dvX1K5k7dC4cQ/wEOm4u93hyaJfui4VJ7 +iqoIN7KH90WdC6sRawx/2+3ezB6G8L4wJWtL//Xyme2wsWjBRAt5e4GVtTY3EsSZ +noXoLy3MzdjG8iDsagb9uPz/AhGVTTgNQouyQ+vCuaTgM/HaJS8Rz1e5JeWrkvKy +tREvvTH3VeuWlHharZyPVuw0oHOcAcJ2JOD4s8kjueqrwwrT+FNExxI3dkTX7iWT +9BwdfP4GLPrFu8aQpFf9CS7ar/Os5m1/A6EmNppRfY0op11dN1fMahEqmB1XcTJu +mHwSKO9cLyYp1FYKsSPZnTUgGuzMUVNu7xznvDwh52QxsUzzVbXEkxfYcloFLkrl +MwcOfc8icwtnn7SCYM1x+HYMxNyY7kn5A38N2MZ2eTwo7Xd3037Vqh5uLt+l -----END CERTIFICATE----- diff --git a/Lib/test/certdata/keycertecc.pem b/Lib/test/certdata/keycertecc.pem index bd109921898044..d503d49dc85f15 100644 --- a/Lib/test/certdata/keycertecc.pem +++ b/Lib/test/certdata/keycertecc.pem @@ -1,8 +1,8 @@ -----BEGIN PRIVATE KEY----- -MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDRUbCeT3hMph4Y/ahL -1sy9Qfy4DYotuAP06UetzG6syv+EoQ02kX3xvazqwiJDrEyhZANiAAQef97STEPn -4Nk6C153VEx24MNkJUcmLe771u6lr3Q8Em3J/YPaA1i9Ys7KZA3WvoKBPoWaaikn -4yLQbd/6YE6AAjMuaThlR1/cqH5QnmS3DXHUjmxnLjWy/dZl0CJG1qo= +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBuhPMBtySJ8hFhn5hU +1yvdDujmB8ajjXNlkQ9GhGdghQIAfKmP9vWtSY+1+BRjpAahZANiAAQKLvQoetPb +S5tbgExB5vSDUtgc7hK1j6AN++En6AkW8KkK+O/31jkItqBoSQz8ts+VCU5cloTf +H6i5AS9zUkHr4DEyn+XxfiutzcNQPdQIBmygWAsUpa1XlZf8ExMFf/A= -----END PRIVATE KEY----- Certificate: Data: @@ -13,19 +13,19 @@ Certificate: Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Validity Not Before: Aug 29 14:23:16 2018 GMT - Not After : Oct 28 14:23:16 2037 GMT + Not After : Oct 28 14:23:16 2525 GMT Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost-ecc Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (384 bit) pub: - 04:1e:7f:de:d2:4c:43:e7:e0:d9:3a:0b:5e:77:54: - 4c:76:e0:c3:64:25:47:26:2d:ee:fb:d6:ee:a5:af: - 74:3c:12:6d:c9:fd:83:da:03:58:bd:62:ce:ca:64: - 0d:d6:be:82:81:3e:85:9a:6a:29:27:e3:22:d0:6d: - df:fa:60:4e:80:02:33:2e:69:38:65:47:5f:dc:a8: - 7e:50:9e:64:b7:0d:71:d4:8e:6c:67:2e:35:b2:fd: - d6:65:d0:22:46:d6:aa + 04:0a:2e:f4:28:7a:d3:db:4b:9b:5b:80:4c:41:e6: + f4:83:52:d8:1c:ee:12:b5:8f:a0:0d:fb:e1:27:e8: + 09:16:f0:a9:0a:f8:ef:f7:d6:39:08:b6:a0:68:49: + 0c:fc:b6:cf:95:09:4e:5c:96:84:df:1f:a8:b9:01: + 2f:73:52:41:eb:e0:31:32:9f:e5:f1:7e:2b:ad:cd: + c3:50:3d:d4:08:06:6c:a0:58:0b:14:a5:ad:57:95: + 97:fc:13:13:05:7f:f0 ASN1 OID: secp384r1 NIST CURVE: P-384 X509v3 extensions: @@ -38,9 +38,9 @@ Certificate: X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: - 45:ED:32:14:6D:51:A2:3B:B0:80:55:E0:A6:9B:74:4C:A5:56:88:B1 + F3:39:E5:90:3F:58:6F:55:9D:91:D4:86:B8:1B:14:35:09:AC:06:97 X509v3 Authority Key Identifier: - keyid:F3:EC:94:8E:F2:8E:30:C4:8E:68:C2:BF:8E:6A:19:C0:C1:9F:76:65 + keyid:C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server serial:CB:2D:80:99:5A:69:52:5B Authority Information Access: @@ -51,53 +51,53 @@ Certificate: URI:http://testca.pythontest.net/testca/revocation.crl Signature Algorithm: sha256WithRSAEncryption Signature Value: - 07:e4:91:0b:d3:ed:4b:52:7f:50:68:c7:8d:80:48:9f:b7:4a: - 13:66:bf:9d:4c:2d:18:19:68:a0:da:3b:12:85:05:16:fa:8d: - 9c:58:c6:81:b3:96:ba:11:62:65:d3:76:f1:1c:ab:95:e4:d8: - 2a:e0:1f:7b:c5:20:2e:7c:8f:de:87:7a:2b:52:54:ca:d1:41: - b0:5e:20:72:df:44:00:4a:69:1a:ef:10:63:52:13:ed:49:02: - ee:dc:9d:f3:c8:ba:c4:01:81:5a:a9:1c:15:12:b6:21:de:44: - a5:fd:7e:f9:22:d1:3e:ee:22:dd:31:55:32:4e:41:68:27:c5: - 95:1b:7e:6b:18:74:f9:22:d6:b7:b9:31:72:51:a0:5a:2c:ff: - 62:76:e9:a0:55:8d:78:33:52:4a:58:b2:f4:4b:0c:43:82:2f: - a9:84:68:05:dd:11:47:70:24:fe:5c:92:fd:17:21:63:bb:fa: - 93:fa:54:54:05:72:48:ed:81:48:ab:95:fc:6d:a8:62:96:f9: - 3b:e2:71:18:05:3e:76:bb:df:95:17:7b:81:4b:1f:7f:e1:67: - 76:c4:07:cb:65:a7:f2:cf:e6:b4:fb:75:7c:ee:df:a1:f5:34: - 20:2b:48:fd:2e:49:ff:f3:a6:3b:00:49:6c:88:79:ed:9c:16: - 2a:04:72:e2:93:e4:7e:3f:2a:dd:30:47:9a:99:84:2a:b9:c4: - 40:31:a6:68:f3:20:d1:75:f1:1e:c8:18:64:5b:f8:4c:ce:9a: - 3c:57:2c:e3:63:64:29:0a:c2:b6:8e:20:01:55:9f:fe:10:ba: - 12:42:38:0a:9b:53:01:a5:b4:08:76:ec:e8:a6:fc:69:2c:f7: - 7f:5e:0f:44:07:55:e1:7c:2e:58:e5:d6:fc:6f:c2:4d:83:65: - bd:f3:32:e3:14:48:22:8d:80:18:ea:44:f8:24:79:ff:ff:c6: - 04:c2:e9:90:34:40:d6:59:3f:59:1e:4a:9a:58:60:ce:ab:f9: - 76:0e:ef:f7:05:17 + b8:d9:bf:b8:88:0a:01:2b:aa:64:32:e8:97:e1:0f:ee:34:40: + ef:71:fc:e5:f4:a2:3b:26:00:e2:19:3b:3e:cb:8e:2b:51:4c: + 30:ff:ab:44:9d:28:8d:d2:9c:32:e3:6b:96:73:1c:9d:55:76: + b2:bf:af:b8:51:ed:fd:04:e7:0d:fa:8c:2a:68:01:cb:92:90: + 7d:d1:31:d8:6c:f4:b8:4b:ea:62:59:1e:31:4e:f7:17:ae:3f: + f0:b6:ff:f8:6e:64:e3:6e:e9:19:4f:d0:1e:84:1e:df:56:49: + ae:90:a9:e0:7b:70:e6:97:7f:08:f2:03:49:82:7d:58:8e:a5: + a0:88:59:f3:a1:ab:b7:dd:6b:9a:2b:79:64:9c:d3:07:7c:ec: + a3:8d:56:77:28:10:c9:42:a5:fa:81:8e:35:ad:f7:28:da:58: + cc:a0:61:fa:0d:75:fd:26:ab:07:88:c5:64:21:f1:98:1c:e3: + 13:51:38:a7:59:a5:59:88:b9:10:4d:c1:79:70:3f:36:9e:08: + 75:53:7f:77:a3:3d:5d:16:b7:3b:a2:f6:eb:41:9b:56:16:80: + 34:96:57:f0:3a:3d:91:43:17:51:2b:64:2c:d7:e2:25:45:85: + f3:5f:73:f8:7d:aa:a3:6d:61:e8:ba:c5:90:5e:16:50:bc:79: + b9:4e:df:66:db:ae:95:80:15:da:4e:bf:8f:4e:9d:e3:7d:b0: + ab:8b:72:93:3c:56:1b:92:d3:67:07:d5:5a:ad:98:16:69:ea: + 46:fe:e0:d0:f4:ae:95:d3:b5:80:7d:f2:64:4d:14:c0:97:d2: + f3:91:bb:e6:43:d0:7e:39:14:0b:95:ab:c1:56:fd:26:79:f8: + 8c:69:eb:bc:74:0e:ea:cd:94:62:7e:30:58:01:7f:84:ee:9d: + 58:9c:fc:8f:75:1e:d9:86:cb:f4:fd:4c:af:b2:f7:69:ea:58: + cb:7c:93:ce:3d:86:f0:46:01:df:86:02:a1:6c:0f:fb:13:84: + d6:75:23:f9:17:21 -----BEGIN CERTIFICATE----- -MIIEyzCCAzOgAwIBAgIJAMstgJlaaVJeMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIEzTCCAzWgAwIBAgIJAMstgJlaaVJeMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaMGMxCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj -MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNVBAMMDWxv -Y2FsaG9zdC1lY2MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQef97STEPn4Nk6C153 -VEx24MNkJUcmLe771u6lr3Q8Em3J/YPaA1i9Ys7KZA3WvoKBPoWaaikn4yLQbd/6 -YE6AAjMuaThlR1/cqH5QnmS3DXHUjmxnLjWy/dZl0CJG1qqjggHEMIIBwDAYBgNV -HREEETAPgg1sb2NhbGhvc3QtZWNjMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU -BggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQURe0y -FG1RojuwgFXgppt0TKVWiLEwfQYDVR0jBHYwdIAU8+yUjvKOMMSOaMK/jmoZwMGf -dmWhUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg -Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcoIJAMstgJlaaVJb -MIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly90ZXN0Y2EucHl0 -aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1BggrBgEFBQcwAYYpaHR0 -cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2NzcC8wQwYDVR0fBDww -OjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2EvcmV2 -b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGBAAfkkQvT7UtSf1Box42ASJ+3 -ShNmv51MLRgZaKDaOxKFBRb6jZxYxoGzlroRYmXTdvEcq5Xk2CrgH3vFIC58j96H -eitSVMrRQbBeIHLfRABKaRrvEGNSE+1JAu7cnfPIusQBgVqpHBUStiHeRKX9fvki -0T7uIt0xVTJOQWgnxZUbfmsYdPki1re5MXJRoFos/2J26aBVjXgzUkpYsvRLDEOC -L6mEaAXdEUdwJP5ckv0XIWO7+pP6VFQFckjtgUirlfxtqGKW+TvicRgFPna735UX -e4FLH3/hZ3bEB8tlp/LP5rT7dXzu36H1NCArSP0uSf/zpjsASWyIee2cFioEcuKT -5H4/Kt0wR5qZhCq5xEAxpmjzINF18R7IGGRb+EzOmjxXLONjZCkKwraOIAFVn/4Q -uhJCOAqbUwGltAh27Oim/Gks939eD0QHVeF8Lljl1vxvwk2DZb3zMuMUSCKNgBjq -RPgkef//xgTC6ZA0QNZZP1keSppYYM6r+XYO7/cFFw== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowYzELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4 +MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UEAwwN +bG9jYWxob3N0LWVjYzB2MBAGByqGSM49AgEGBSuBBAAiA2IABAou9Ch609tLm1uA +TEHm9INS2BzuErWPoA374SfoCRbwqQr47/fWOQi2oGhJDPy2z5UJTlyWhN8fqLkB +L3NSQevgMTKf5fF+K63Nw1A91AgGbKBYCxSlrVeVl/wTEwV/8KOCAcQwggHAMBgG +A1UdEQQRMA+CDWxvY2FsaG9zdC1lY2MwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW +MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTz +OeWQP1hvVZ2R1Ia4GxQ1CawGlzB9BgNVHSMEdjB0gBTACisoQ95fyX1H5UebNvJl +jGc74qFRpE8wTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5dGhvbiBTb2Z0d2Fy +ZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2VydmVyggkAyy2AmVpp +UlswgYMGCCsGAQUFBwEBBHcwdTA8BggrBgEFBQcwAoYwaHR0cDovL3Rlc3RjYS5w +eXRob250ZXN0Lm5ldC90ZXN0Y2EvcHljYWNlcnQuY2VyMDUGCCsGAQUFBzABhilo +dHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9vY3NwLzBDBgNVHR8E +PDA6MDigNqA0hjJodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9y +ZXZvY2F0aW9uLmNybDANBgkqhkiG9w0BAQsFAAOCAYEAuNm/uIgKASuqZDLol+EP +7jRA73H85fSiOyYA4hk7PsuOK1FMMP+rRJ0ojdKcMuNrlnMcnVV2sr+vuFHt/QTn +DfqMKmgBy5KQfdEx2Gz0uEvqYlkeMU73F64/8Lb/+G5k427pGU/QHoQe31ZJrpCp +4Htw5pd/CPIDSYJ9WI6loIhZ86Grt91rmit5ZJzTB3zso41WdygQyUKl+oGONa33 +KNpYzKBh+g11/SarB4jFZCHxmBzjE1E4p1mlWYi5EE3BeXA/Np4IdVN/d6M9XRa3 +O6L260GbVhaANJZX8Do9kUMXUStkLNfiJUWF819z+H2qo21h6LrFkF4WULx5uU7f +ZtuulYAV2k6/j06d432wq4tykzxWG5LTZwfVWq2YFmnqRv7g0PSuldO1gH3yZE0U +wJfS85G75kPQfjkUC5WrwVb9Jnn4jGnrvHQO6s2UYn4wWAF/hO6dWJz8j3Ue2YbL +9P1Mr7L3aepYy3yTzj2G8EYB34YCoWwP+xOE1nUj+Rch -----END CERTIFICATE----- diff --git a/Lib/test/certdata/nosan.pem b/Lib/test/certdata/nosan.pem index c6ff8ea31bfa2e..c397342fa86f6e 100644 --- a/Lib/test/certdata/nosan.pem +++ b/Lib/test/certdata/nosan.pem @@ -1,131 +1,137 @@ -----BEGIN PRIVATE KEY----- -MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQC99xEYPTwFN/ji -i0lm11ckEGhcxciSsIgTgior54CLgQy7JXllTYmAWFTTg2zNBvDMexGI0h+xtZ4q -1Renghgt33N3Y6CT3v/L7JkE1abQbFveKW/ydlxH0+jLlsENSWjySwC80+f9L3bX -TcD8T4Fu9Uty2Rg1a/Eyekng5RmfkmLNgxfnX5R5nWhh0Aia7h3Ax2zCALfxqZIm -fxwavEgHsW/yZi+T+eoJwe0i7a6LaUoLqsPV9ZhagziNDaappPHH42NW39WlRhx1 -UjtiRm2Jihnzxcfs+90zLXSp5pxo/cE9Ia4d8ieq3Rxd/XgjlF6FXXFJjwfL36Dw -ehy8m3PKKAuO+fyMgPPPMQb7oaRy/MBG0NayRreTwyKILS2zafIW/iKpgICbxrWJ -r/H1b3S6PBKYUE2uQs0/ZPnRjjh0VeNnue7JcRoNbe27I2d56KUBsVEPdokjU59v -NYi6Se+ViZXtUbM1u/I0kvDMprAiobwtJFYgcE86N1lFJjHSwDMCAwEAAQKCAYBb -lvnJBA0iPwBiyeFUElNTcg2/XST9hNu2/DU1AeM6X7gxqznCnAXFudD8Qgt9NvF2 -xYeIvjbFydk+sYs8Gj9qLqhPUdukMAqI2cRVTmWla/lHPhdZgbOwdf1x23es3k4Z -NAxg/pKFwhK8cCKyA+tWAjKkZwODDk42ljt0kUEvbLbye1hVGAJQOJKRRmo/uLrj -rcNELnCBtc5ffT2hrlHUU7qz1ozt/brXhYa+JnbXhKZMxcKyMD2KtmXXrFNEy99o -jXbrpDCos82bzQfPDo8IpCbVbEd2J00aFmrNjQWhZuXX5dXflrujW4J0nzeHrZ78 -rNAz2/YuZ543BTB3XbogeFuLC5RqBgAMmw2WJ96Oa/UG8nZNvEw54N5r6dhfXj6A -VlJFLVwlfBQdAdaM3P4uZ6WECrH3EerQa27qyUdRrcDaGPLt7wG9FmMivnW1KQsy -5ow/gM0CsxFj2xNoGw1S5jtclbgSy8HNJaBsNk4XMQ+ORABZdG1MTTE+GMSjD/EC -gcEA+6JYiZEo+QrvItIZYB6Go4suu/F8df1pEjJlxwp2GmObitRhtV6r9g9IySFv -5SL7ZxARr4aQxvM7fNp57p9ssmkBtY0ofMjJAxhvs4T37bAcGK/2xCegNSmbqh24 -FAWpRDMgE5PjtuWC5jTvSOYFeUxwI/cu0HxWdxJl2dPUSL1nI2jP+ok3pZobEQk9 -E2+MlHpKmU+s/lAkuQiP+AW9a4M+ZJNWxocJjmtwj4OjJXPm7GddA/5x622DxFe6 -4K2vAoHBAMFC0An25bwGoFrCV/96s45K4qZcZcJ660+aK3xXaq6/8KfiusJnWds2 -nc0B6jYjKs8A7yTAGXke6fmyVsoLosZiXsbpW2m16g8jL79Tc85O9oDNmDIGk1uT -tRLZc2BvmHmy/dNrdbT/EHC3FKNWQVqWc2sHhPeB6F3hIEXDSUO/GB0njMZNXrPJ -547RlhN0xCLb3vTzzGHwNmwfI81YjV/XI4vpJjq1YceN8Xyd1r5ZOFfU8woIACO3 -I4dvBQ1avQKBwQCLDs9wzohfAFzg2Exvos7y6AKemDgYmD8NcE5wbWaQ9MTLNsz8 -RuIu64lkpRbKAMf/z5CGeI3fdCFGwRGq/e06tu7b3rMmKmtzS3jHM08zyiPsvKlZ -AzD00BaXLy8/2VUOPFaYmxy3QSRShaRKm9sgik5agcocKuo5iTBB7V8eB5VMqyps -IJJg8MXOZ1WaPQXqM56wFKjcLXvtyT6OaNWh6Xh8ajQFKDDuxI8CsFNjaiaONBzi -DSX1XaL4ySab7T8CgcEAsI+7xP6+EDP1mDVpc8zD8kHUI6zSgwUNqiHtjKHIo3JU -CO2JNkZ5v158eGlBcshaOdheozKlkxR9KlSWGezbf2crs4pKq585AS9iVeeGK3vU -lQRAAaQkSEv/6AKl9/q8UKMIZnkMhploibGZt0f8WSiOtb+e6QjUI8CjXVj2vF// -RdN2N01EMflKBh7Qf2H0NuytGxkJJojxD4K7kMVQE7lXjmEpPgWsGUZC01jYcfrN -EOFKUWXRys9sNDVnZjX5AoHAFRyOC1BlmVEtcOsgzum4+JEDWvRnO1hP1tm68eTZ -ijB/XppDtVESpq3+1+gx2YOmzlUNEhKlcn6eHPWEJwdVxJ87Gdh03rIV/ZQUKe46 -3+j6l/5coN4WfCBloy4b+Tcj+ZTL4sKaLm33RoD2UEWS5mmItfZuoEFQB958h3JD -1Ka1tgsLnuYGjcrg+ALvbM5nQlefzPqPJh0C8UV3Ny/4Gd02YgHw7Yoe4m6OUqQv -hctFUL/gjIGg9PVqTWzVVKaI +MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDD5QDHBBTqG5g/ +OW6kVb6oTHLM4q6wX42YofPGBjWFlIeMX78A1PzRvgKLo9RXbBOb/Q89rbtsL9dd ++FcUaNP7GNLnX+MpeOnMOL6M7LzihFi0OyRmvCytWIUMYkH8lqHuydwdUROsbqGk +2r7Sbe8XzDbf9dNnCYZnoOJMiGvp08D5FFGJL+K7N9xCEHCpHJ5mFyywzunoR3us +EgV+0b8nt287RcLoBNaORCLt6L1FSsSb6g3NS/AUNNDb1VLoa96HFLL3rBCqSt3y +SCGtz3lncEG5HXBRNEWoka4SKqHDOP8zDZZxtmNwWp6QtHaFj4rY/XnMGiekJgIG +crzeB8jAgwGC9u23Yo5/IX5OhgSIbqj0mtYVRwZwJbszXVQn7BNbQzNFNgnpJPpJ +xA4xDRr415IsAQHm7ugt3G0aX2PbbXYxOpF/Ud+3JQu5vYGbcMUxqOPaHi3C8QUT +rcvIRBm4W2L2fd3xANpC6RafRVXjfeGFfk0pyArlvIyYCGvxAeUCAwEAAQKCAYAE +A1FQwmMxHOhUbuAIRoUInwhMeLs7ZKJx8OsGPDSCTGRGGnAFD/rSP63cNy71T+AF +gggpiGQegz9KkeGfhQwM1GssLGk8WnCp2fnqbAwyhkZzpOs+WEJSCsKMFDc3S0GU +hChIYAJFtgRLJnAFM+b2V0uIfHCz26hGqKOdDb/Wumzd8zPhH+/SNI5hdM7xStez +2d/dlqVZ21c0ghiMLZ/M2qrz8EEvWccc4BEuYtqJYNpdgAauLIGF0SxByPt/oZMf +4fa0zOVfAL6F5cPFkycRzuz97Lx+ZdtLuUBx/3y8Sk24TR1QutwaFhbwpRSQSUrg +xT7ZmS24rQhaP8i7+ROLGy0CPlLMc/D3WvvtdLDWOUF30azURvAFcqKA87Bp05bR +HI/ewXaSB26J34MUmBHy5dBjld+HX6hQInPhCTZu7gNDOrPaEc8Ug50c1r7HkYRl +VBv/4BQo3YtNdoKhL08MVuNbcxrzge3kI0mbQu7qDSyrve02WnQ1zijJ916NbgEC +gcEA6oFNNtWzVw/7/MBxUZ1tE5VW5U2SjRvQZlcPTJ9Ub16byhOCdNvE17uyYLt5 +diqoVAvSGWiJ+OKsmw3XTLdhxzWeZ1a9ZiCozsmIfHMQmL9t3MxzTnMEZCfcvxz0 +DPvAN0REUtwRkMbt7vC+g01Eom9UpAH7hKXkc3pTgtkoyFeebC/YneGtdOTVATKU +WMfsY6Biye7P1D8V7btjLI8LTnv90ygoP0uSrX53hp7k4EFAeXyT9VN5wMXLw81a +5K69AoHBANXZsvSSIwe7fjspNUU9yELnEokDIdBn4ARX6x5PonL2KB0iVUzWgjHb +vs23GAzAgKKY+S8VLYptBLUBlsZ/pSLfZLWd1ywxeHmk/nkzuqlAw1jwuUlMq6Vr +BJmfhpOoXeSrQwvkL/uOejdrDSmLAFiIV3l9LtkmIJzfQSSy2QB8mfWwni0vxOJT +mIqZE01rfRTNLIqxO3+0d7pDqArVvWxYqF4C8kihUhNjkB5NaURUTzDQ3Y33aAvT +zAm697nGSQKBwQDEQ8ed9ykL2sLpfR7aUclytHBvpYbcNsUqgf66ADeopiP48m8i +4rRSYjMepok3jugmv2XuAgJHnV8cvm7NNEXPdl7G2l/V08u0lhN3JM5lKQIH4801 +gSnRsVMdWFwhaaosFySfvLOu2e9VJYQtXEPvNwI96bLaCAW1aFHwl1N8qWhb34eK +S9DinopvYCesTlbX4uoLW6XxW4M83rJYHrg1zaxYR6m3n8Z5EflzYBTqY3JUuyES +F/U0k9bAX2SNNHkCgcALk8mYbADxfjkLQuPbZ8jbtl7OhBjki3sZQRk9ftowlxr8 +2Mr9ae+Ke3cM9AidSB6urtFutxrMD7LdicR74pUyGh39pxnrDpKTI1eTgDVuzE7H +FeEyErCIOA77siM7AzZyFsN+dVATslbzgRwpT5kpMdhqf1h18RZ656tDLVuKJzS+ +lF073QYvqo7rkfX1jwgqhCERMR8jfsWsk9UZIREsOHCFBmvPesxSuGUo/s/gHyBa +aDRWZzp+yWyWakTXDeECgcBaPIxLK0ky89Mv8jTSyIJIMhQj8+z8wFLJFQG5vF/Z +1taLIDY0stU8HzKflTJ5v72r2jpIvu5YgDEgl+kKjyqLMWSu4nBZ2OoJet49S6d3 +X0YL2VzsIiSG+8cmVvBBf7iZCHDKiCM20dzzhZq8BCLiaPq+Zu2No2xEJyE0m8rc +I66z6fV1BWQXLe6vPC8EVvBWz3Ybje0czUdZnZ44qV6qyZzREXuqbC0qS5RanE4Z ++Ps9b3TezE7gDII6SbUwhZo= -----END PRIVATE KEY----- Certificate: Data: - Version: 1 (0x0) + Version: 3 (0x2) Serial Number: cb:2d:80:99:5a:69:52:61 Signature Algorithm: sha256WithRSAEncryption Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Validity Not Before: Aug 29 14:23:16 2018 GMT - Not After : Oct 28 14:23:16 2037 GMT + Not After : Oct 28 14:23:16 2525 GMT Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=nosan Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: - 00:bd:f7:11:18:3d:3c:05:37:f8:e2:8b:49:66:d7: - 57:24:10:68:5c:c5:c8:92:b0:88:13:82:2a:2b:e7: - 80:8b:81:0c:bb:25:79:65:4d:89:80:58:54:d3:83: - 6c:cd:06:f0:cc:7b:11:88:d2:1f:b1:b5:9e:2a:d5: - 17:a7:82:18:2d:df:73:77:63:a0:93:de:ff:cb:ec: - 99:04:d5:a6:d0:6c:5b:de:29:6f:f2:76:5c:47:d3: - e8:cb:96:c1:0d:49:68:f2:4b:00:bc:d3:e7:fd:2f: - 76:d7:4d:c0:fc:4f:81:6e:f5:4b:72:d9:18:35:6b: - f1:32:7a:49:e0:e5:19:9f:92:62:cd:83:17:e7:5f: - 94:79:9d:68:61:d0:08:9a:ee:1d:c0:c7:6c:c2:00: - b7:f1:a9:92:26:7f:1c:1a:bc:48:07:b1:6f:f2:66: - 2f:93:f9:ea:09:c1:ed:22:ed:ae:8b:69:4a:0b:aa: - c3:d5:f5:98:5a:83:38:8d:0d:a6:a9:a4:f1:c7:e3: - 63:56:df:d5:a5:46:1c:75:52:3b:62:46:6d:89:8a: - 19:f3:c5:c7:ec:fb:dd:33:2d:74:a9:e6:9c:68:fd: - c1:3d:21:ae:1d:f2:27:aa:dd:1c:5d:fd:78:23:94: - 5e:85:5d:71:49:8f:07:cb:df:a0:f0:7a:1c:bc:9b: - 73:ca:28:0b:8e:f9:fc:8c:80:f3:cf:31:06:fb:a1: - a4:72:fc:c0:46:d0:d6:b2:46:b7:93:c3:22:88:2d: - 2d:b3:69:f2:16:fe:22:a9:80:80:9b:c6:b5:89:af: - f1:f5:6f:74:ba:3c:12:98:50:4d:ae:42:cd:3f:64: - f9:d1:8e:38:74:55:e3:67:b9:ee:c9:71:1a:0d:6d: - ed:bb:23:67:79:e8:a5:01:b1:51:0f:76:89:23:53: - 9f:6f:35:88:ba:49:ef:95:89:95:ed:51:b3:35:bb: - f2:34:92:f0:cc:a6:b0:22:a1:bc:2d:24:56:20:70: - 4f:3a:37:59:45:26:31:d2:c0:33 + 00:c3:e5:00:c7:04:14:ea:1b:98:3f:39:6e:a4:55: + be:a8:4c:72:cc:e2:ae:b0:5f:8d:98:a1:f3:c6:06: + 35:85:94:87:8c:5f:bf:00:d4:fc:d1:be:02:8b:a3: + d4:57:6c:13:9b:fd:0f:3d:ad:bb:6c:2f:d7:5d:f8: + 57:14:68:d3:fb:18:d2:e7:5f:e3:29:78:e9:cc:38: + be:8c:ec:bc:e2:84:58:b4:3b:24:66:bc:2c:ad:58: + 85:0c:62:41:fc:96:a1:ee:c9:dc:1d:51:13:ac:6e: + a1:a4:da:be:d2:6d:ef:17:cc:36:df:f5:d3:67:09: + 86:67:a0:e2:4c:88:6b:e9:d3:c0:f9:14:51:89:2f: + e2:bb:37:dc:42:10:70:a9:1c:9e:66:17:2c:b0:ce: + e9:e8:47:7b:ac:12:05:7e:d1:bf:27:b7:6f:3b:45: + c2:e8:04:d6:8e:44:22:ed:e8:bd:45:4a:c4:9b:ea: + 0d:cd:4b:f0:14:34:d0:db:d5:52:e8:6b:de:87:14: + b2:f7:ac:10:aa:4a:dd:f2:48:21:ad:cf:79:67:70: + 41:b9:1d:70:51:34:45:a8:91:ae:12:2a:a1:c3:38: + ff:33:0d:96:71:b6:63:70:5a:9e:90:b4:76:85:8f: + 8a:d8:fd:79:cc:1a:27:a4:26:02:06:72:bc:de:07: + c8:c0:83:01:82:f6:ed:b7:62:8e:7f:21:7e:4e:86: + 04:88:6e:a8:f4:9a:d6:15:47:06:70:25:bb:33:5d: + 54:27:ec:13:5b:43:33:45:36:09:e9:24:fa:49:c4: + 0e:31:0d:1a:f8:d7:92:2c:01:01:e6:ee:e8:2d:dc: + 6d:1a:5f:63:db:6d:76:31:3a:91:7f:51:df:b7:25: + 0b:b9:bd:81:9b:70:c5:31:a8:e3:da:1e:2d:c2:f1: + 05:13:ad:cb:c8:44:19:b8:5b:62:f6:7d:dd:f1:00: + da:42:e9:16:9f:45:55:e3:7d:e1:85:7e:4d:29:c8: + 0a:e5:bc:8c:98:08:6b:f1:01:e5 Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 27:04:5B:37:51:0D:92:FD:2C:60:61:FE:4F:9C:66:20:41:2C:08:45 + X509v3 Authority Key Identifier: + C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 Signature Algorithm: sha256WithRSAEncryption Signature Value: - 7e:dd:64:64:92:6c:b9:41:ce:f3:e3:f8:e6:9f:c8:5b:32:39: - 8c:03:5b:5e:7e:b3:23:ca:6c:d1:99:2f:53:af:9d:3c:84:cd: - c6:ce:0a:ee:94:de:ff:a7:06:81:7e:e2:38:a5:05:39:58:22: - dc:13:83:53:e7:f8:16:cb:93:dc:cf:4b:e6:1b:9f:9e:71:ef: - ee:ba:ea:b6:68:5c:32:22:7e:54:4f:46:a6:0b:11:8f:ef:05: - 6e:d3:0b:d0:a8:be:95:23:a2:e4:e7:a8:a2:a4:7d:98:52:86: - a4:15:fb:74:7a:9a:89:23:43:20:26:3a:56:9e:a3:6e:54:02: - 76:4e:25:9c:a1:8c:03:99:e5:eb:a6:61:b4:9c:2a:b1:ed:eb: - 94:f9:14:aa:a4:c3:f0:f7:7a:03:a3:b1:f8:c0:83:79:ab:8a: - 93:7f:0a:95:08:50:ff:55:19:ac:28:a2:c8:9f:a6:77:72:a3: - da:37:a9:ff:f3:57:70:c8:65:d9:55:14:84:b4:b3:78:86:82: - da:84:2c:48:19:51:ec:9d:20:b1:4d:18:fb:82:9f:7b:a7:80: - 22:69:25:83:4d:bf:ac:31:64:f5:39:11:f1:ed:53:fb:67:ab: - 91:86:c5:4d:87:e8:6b:fe:9a:84:fe:6a:92:6b:62:c1:ae:d2: - f0:cb:06:6e:f3:50:f4:8d:6d:fa:7d:6a:1c:64:c3:98:91:da: - c9:8c:a9:79:e5:48:4c:a2:de:42:28:e8:0e:9f:52:6a:a4:e0: - c7:ac:11:9c:ba:5d:d6:84:93:56:28:f1:6d:83:aa:62:b2:b7: - 56:c6:64:d9:96:4e:97:ab:4e:8f:ba:f6:ab:b9:17:52:98:32: - 7f:b5:12:fa:39:d7:34:2a:f3:ed:40:90:6f:66:7b:b6:c1:9d: - b9:53:d0:e3:e9:69:8c:cf:7a:fd:08:0a:62:47:d4:ce:72:f7: - 6f:80:b4:1d:18:7a:ba:a2:a9:45:49:ef:9c:0b:99:89:03:ab: - 5f:7a:9d:c5:77:b7 + a0:b7:48:56:c6:b3:92:26:3f:d8:92:3c:ed:72:b5:89:ea:fd: + c9:66:da:ba:6a:8e:0d:04:ea:b2:fd:1f:e4:29:da:1e:c7:8f: + 5a:f0:88:74:dd:b3:f0:5e:a7:c4:77:13:cf:a8:19:fb:f2:2d: + ee:47:b4:0c:7c:5b:d3:dc:2f:2a:5c:bf:43:22:1c:91:d8:03: + 7d:44:90:c0:2d:fe:9e:7c:8b:ef:39:4e:b3:87:99:c8:eb:c2: + b7:cf:86:65:05:52:8c:15:b9:6a:8d:cd:e3:2a:29:d1:f5:87: + 42:11:c3:2e:42:ec:ed:26:55:8d:f3:ad:66:f4:79:72:f7:9e: + ed:bc:0c:5a:a7:74:ab:dc:57:e8:5c:99:b6:32:8f:7e:58:6e: + 70:48:ea:5d:a7:fa:b1:fc:c0:e9:50:3a:a4:53:21:e7:8b:77: + 54:2d:bb:64:1e:fc:88:86:90:c1:03:90:17:bb:3c:cf:ce:e8: + 48:32:c2:07:e5:8e:4f:93:a9:1a:e2:f5:93:a8:01:9f:30:26: + 1e:ed:b5:62:e9:25:c5:b0:32:e1:fc:bd:d6:48:b4:70:a9:e2: + cd:f6:a9:42:cb:bb:24:39:b9:34:fc:b9:cb:09:01:f0:5e:7e: + ef:b5:59:d6:88:31:a9:4c:be:7d:5b:de:4d:ec:84:1b:a1:1b: + d8:7d:83:cb:f1:04:c9:f1:f3:a4:08:05:3c:b5:96:13:1d:37: + 8a:23:83:22:86:72:17:13:5e:e8:89:06:58:cd:89:42:71:12: + e5:47:fc:f7:6e:96:28:8f:19:b9:d7:86:5b:c5:62:14:e1:5b: + 06:e7:e0:66:7e:fc:b7:9e:a9:99:14:e5:0a:d6:df:8f:b5:a2: + 1a:74:54:30:f6:f4:bf:1b:43:1d:be:4f:38:92:55:10:7b:d8: + 4f:e0:33:0f:40:2e:58:ec:9c:78:1b:43:17:b3:cb:0b:f5:34: + e2:7e:11:a1:90:b6:3c:79:6a:0b:91:ce:0b:8d:d5:60:e4:6d: + c8:2a:3d:40:6d:17 -----BEGIN CERTIFICATE----- -MIIEJDCCAowCCQDLLYCZWmlSYTANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJY -WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV -BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTgwODI5MTQyMzE2WhcNMzcxMDI4MTQyMzE2 -WjBbMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwOQ2FzdGxlIEFudGhyYXgxIzAhBgNV -BAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQ4wDAYDVQQDDAVub3NhbjCC -AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAL33ERg9PAU3+OKLSWbXVyQQ -aFzFyJKwiBOCKivngIuBDLsleWVNiYBYVNODbM0G8Mx7EYjSH7G1nirVF6eCGC3f -c3djoJPe/8vsmQTVptBsW94pb/J2XEfT6MuWwQ1JaPJLALzT5/0vdtdNwPxPgW71 -S3LZGDVr8TJ6SeDlGZ+SYs2DF+dflHmdaGHQCJruHcDHbMIAt/GpkiZ/HBq8SAex -b/JmL5P56gnB7SLtrotpSguqw9X1mFqDOI0Npqmk8cfjY1bf1aVGHHVSO2JGbYmK -GfPFx+z73TMtdKnmnGj9wT0hrh3yJ6rdHF39eCOUXoVdcUmPB8vfoPB6HLybc8oo -C475/IyA888xBvuhpHL8wEbQ1rJGt5PDIogtLbNp8hb+IqmAgJvGtYmv8fVvdLo8 -EphQTa5CzT9k+dGOOHRV42e57slxGg1t7bsjZ3nopQGxUQ92iSNTn281iLpJ75WJ -le1RszW78jSS8MymsCKhvC0kViBwTzo3WUUmMdLAMwIDAQABMA0GCSqGSIb3DQEB -CwUAA4IBgQB+3WRkkmy5Qc7z4/jmn8hbMjmMA1tefrMjymzRmS9Tr508hM3Gzgru -lN7/pwaBfuI4pQU5WCLcE4NT5/gWy5Pcz0vmG5+ece/uuuq2aFwyIn5UT0amCxGP -7wVu0wvQqL6VI6Lk56iipH2YUoakFft0epqJI0MgJjpWnqNuVAJ2TiWcoYwDmeXr -pmG0nCqx7euU+RSqpMPw93oDo7H4wIN5q4qTfwqVCFD/VRmsKKLIn6Z3cqPaN6n/ -81dwyGXZVRSEtLN4hoLahCxIGVHsnSCxTRj7gp97p4AiaSWDTb+sMWT1ORHx7VP7 -Z6uRhsVNh+hr/pqE/mqSa2LBrtLwywZu81D0jW36fWocZMOYkdrJjKl55UhMot5C -KOgOn1JqpODHrBGcul3WhJNWKPFtg6pisrdWxmTZlk6Xq06PuvaruRdSmDJ/tRL6 -Odc0KvPtQJBvZnu2wZ25U9Dj6WmMz3r9CApiR9TOcvdvgLQdGHq6oqlFSe+cC5mJ -A6tfep3Fd7c= +MIIEbzCCAtegAwIBAgIJAMstgJlaaVJhMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowWzELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4 +MSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEOMAwGA1UEAwwF +bm9zYW4wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDD5QDHBBTqG5g/ +OW6kVb6oTHLM4q6wX42YofPGBjWFlIeMX78A1PzRvgKLo9RXbBOb/Q89rbtsL9dd ++FcUaNP7GNLnX+MpeOnMOL6M7LzihFi0OyRmvCytWIUMYkH8lqHuydwdUROsbqGk +2r7Sbe8XzDbf9dNnCYZnoOJMiGvp08D5FFGJL+K7N9xCEHCpHJ5mFyywzunoR3us +EgV+0b8nt287RcLoBNaORCLt6L1FSsSb6g3NS/AUNNDb1VLoa96HFLL3rBCqSt3y +SCGtz3lncEG5HXBRNEWoka4SKqHDOP8zDZZxtmNwWp6QtHaFj4rY/XnMGiekJgIG +crzeB8jAgwGC9u23Yo5/IX5OhgSIbqj0mtYVRwZwJbszXVQn7BNbQzNFNgnpJPpJ +xA4xDRr415IsAQHm7ugt3G0aX2PbbXYxOpF/Ud+3JQu5vYGbcMUxqOPaHi3C8QUT +rcvIRBm4W2L2fd3xANpC6RafRVXjfeGFfk0pyArlvIyYCGvxAeUCAwEAAaNCMEAw +HQYDVR0OBBYEFCcEWzdRDZL9LGBh/k+cZiBBLAhFMB8GA1UdIwQYMBaAFMAKKyhD +3l/JfUflR5s28mWMZzviMA0GCSqGSIb3DQEBCwUAA4IBgQCgt0hWxrOSJj/Ykjzt +crWJ6v3JZtq6ao4NBOqy/R/kKdoex49a8Ih03bPwXqfEdxPPqBn78i3uR7QMfFvT +3C8qXL9DIhyR2AN9RJDALf6efIvvOU6zh5nI68K3z4ZlBVKMFblqjc3jKinR9YdC +EcMuQuztJlWN861m9Hly957tvAxap3Sr3FfoXJm2Mo9+WG5wSOpdp/qx/MDpUDqk +UyHni3dULbtkHvyIhpDBA5AXuzzPzuhIMsIH5Y5Pk6ka4vWTqAGfMCYe7bVi6SXF +sDLh/L3WSLRwqeLN9qlCy7skObk0/LnLCQHwXn7vtVnWiDGpTL59W95N7IQboRvY +fYPL8QTJ8fOkCAU8tZYTHTeKI4MihnIXE17oiQZYzYlCcRLlR/z3bpYojxm514Zb +xWIU4VsG5+Bmfvy3nqmZFOUK1t+PtaIadFQw9vS/G0Mdvk84klUQe9hP4DMPQC5Y +7Jx4G0MXs8sL9TTifhGhkLY8eWoLkc4LjdVg5G3IKj1AbRc= -----END CERTIFICATE----- diff --git a/Lib/test/certdata/pycacert.pem b/Lib/test/certdata/pycacert.pem index 0a48bf7d23539c..c2c8b1ecdcfc97 100644 --- a/Lib/test/certdata/pycacert.pem +++ b/Lib/test/certdata/pycacert.pem @@ -7,96 +7,96 @@ Certificate: Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Validity Not Before: Aug 29 14:23:16 2018 GMT - Not After : Oct 28 14:23:16 2037 GMT + Not After : Oct 28 14:23:16 2525 GMT Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: - 00:d0:a0:9b:b1:b9:3b:79:ee:31:2f:b8:51:1c:01: - 75:ed:09:59:4c:ac:c8:bf:6a:0a:f8:7a:08:f0:25: - e3:25:7b:6a:f8:c4:d8:aa:a0:60:07:25:b0:cf:73: - 71:05:52:68:bf:06:93:ae:10:61:96:bc:b3:69:81: - 1a:7d:19:fc:20:86:8f:9a:68:1b:ed:cd:e2:6c:61: - 67:c7:4e:55:ea:43:06:21:1b:e9:b9:be:84:5f:c2: - da:eb:89:88:e0:42:a6:45:49:2a:d0:b9:6b:8c:93: - c9:44:3b:ca:fc:3c:94:7f:dd:70:c5:ad:d8:4b:3b: - dc:1e:f8:55:4b:b5:27:86:f8:df:b0:83:cf:f7:16: - 37:bf:13:17:34:d4:c9:55:ed:6b:16:c9:7f:ad:20: - 4e:f0:1e:d9:1b:bf:8d:ba:cd:ca:96:ef:1e:69:cb: - 51:66:61:48:0d:e8:79:a3:59:61:d4:10:8d:e0:0d: - 3b:0b:85:b6:d5:85:12:dd:a5:07:c5:4b:fa:23:fa: - 54:39:f7:97:0b:c9:44:47:1e:56:77:3c:3c:13:01: - 0b:6d:77:d6:14:ba:44:f4:53:35:56:d9:3d:b9:3e: - 35:5f:db:33:9a:4f:5a:b9:38:44:c9:32:49:fe:66: - f6:1f:1a:97:aa:ca:4c:4a:f6:b8:5e:40:7f:fb:0b: - 1d:f8:5b:a1:dc:f8:c0:2e:d0:6d:49:f5:d2:46:d4: - 90:57:fe:92:81:34:ae:2d:38:bb:a8:17:0c:e1:e5: - 3f:e2:f7:26:05:54:50:f5:64:b3:1c:6e:44:ff:6f: - a9:b4:03:96:e9:0e:c2:88:d8:72:52:90:99:c6:41: - 0f:46:90:59:b8:3e:6f:d2:e2:9e:1d:36:82:95:d3: - 58:8a:12:f3:e2:d8:0d:20:51:23:f0:90:2d:9a:3e: - 7d:26:86:b2:a7:d7:f9:28:60:03:e3:77:c7:88:04: - c9:fe:89:77:70:10:4f:c3:a0:8a:3b:f4:ab:42:7b: - e3:14:92:d8:ae:16:d6:a1:de:7d + 00:e6:ba:e2:e4:c1:c2:0c:1c:3e:62:d8:b9:5c:57: + 2e:52:b8:83:c5:88:3a:e6:9a:7a:f5:64:16:33:eb: + 37:6e:2f:7b:f3:68:03:45:65:47:5d:71:10:59:ca: + 2b:1b:00:6c:81:14:61:f4:86:59:3f:ea:fd:78:37: + 16:9d:43:f1:c4:f6:69:8c:c5:29:06:88:9e:26:22: + 04:ac:04:d8:87:34:48:39:eb:6b:f2:0b:92:aa:c3: + 6e:63:51:51:6b:c2:ad:ff:5c:c8:2f:b2:1b:9c:20: + 8a:40:3e:a2:2f:6a:ea:c8:d9:37:43:5c:dc:ed:92: + e2:d9:40:d2:61:9f:71:8a:f5:ed:39:ba:a8:5e:3e: + b5:21:63:10:d8:6f:b4:e2:11:01:0b:10:e8:bb:fb: + 62:ef:48:55:bc:f5:d2:9c:ab:68:ae:95:25:19:f2: + 97:7d:1a:dc:66:ea:88:5e:86:e4:cb:cb:69:4d:5e: + b0:a3:fb:6c:31:e4:28:60:5e:90:f1:d4:2e:10:50: + e1:85:f0:0d:5c:bd:dd:45:24:08:19:3e:1c:93:66: + 8f:2b:da:53:7d:04:1c:0e:42:c4:68:5e:a6:cd:a9: + 18:ed:a7:cd:6a:d0:d1:86:ba:90:ff:b7:4c:de:c7: + 43:24:6d:c7:1c:6b:9c:81:e7:e1:1b:57:25:90:a9: + 0e:c9:56:f3:f6:6b:5e:2d:b4:2e:40:50:9b:42:63: + d2:d6:99:1c:38:dc:cf:2b:2c:a7:72:f1:c7:5e:63: + 34:76:48:f4:3e:88:13:9e:86:16:53:2f:74:fb:87: + 01:8d:22:a4:68:33:ee:13:6c:7a:06:14:54:56:17: + 57:57:98:34:d0:0b:66:09:e3:88:09:f8:a5:15:1c: + 10:73:d0:88:50:99:5e:18:65:3b:ff:31:27:1b:5e: + c6:aa:41:fd:2d:2f:18:a7:c0:f2:ab:c7:22:b5:0b: + 69:d2:73:d1:bb:d0:1c:3d:fa:a4:35:62:cd:33:86: + c7:a0:23:0f:b9:6a:d5:d2:6d:8d Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: - F3:EC:94:8E:F2:8E:30:C4:8E:68:C2:BF:8E:6A:19:C0:C1:9F:76:65 + C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 X509v3 Authority Key Identifier: - F3:EC:94:8E:F2:8E:30:C4:8E:68:C2:BF:8E:6A:19:C0:C1:9F:76:65 + C0:0A:2B:28:43:DE:5F:C9:7D:47:E5:47:9B:36:F2:65:8C:67:3B:E2 X509v3 Basic Constraints: critical CA:TRUE X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign Signature Algorithm: sha256WithRSAEncryption Signature Value: - 8b:00:54:72:b3:8d:eb:f3:af:34:9f:d6:60:ea:de:84:3f:8c: - 04:8f:19:a6:be:02:67:c4:63:c5:74:e3:47:37:59:83:94:06: - f1:45:19:e8:07:2f:d6:4e:4b:4f:a8:3d:c7:07:07:27:92:f4: - 7e:73:4f:8b:32:19:94:46:7a:25:c4:d9:c4:27:b0:11:63:3a: - 60:8b:85:e1:73:4f:34:3b:6b:a4:34:8c:49:8e:cd:cf:4f:b2: - 65:27:41:19:b0:fc:80:31:78:f2:73:6a:9b:7d:71:34:50:fc: - 78:a8:da:05:b4:9c:5b:3a:99:7a:6b:5d:ef:3b:d3:e9:3b:33: - 01:12:65:cf:5e:07:d8:19:af:d5:53:ea:f0:10:ac:c4:b6:26: - 3c:34:2e:74:ee:64:dd:1d:36:75:89:44:00:b0:0d:fd:2f:b3: - 01:cc:1a:8b:02:cd:6c:e8:80:82:ca:bf:82:d7:00:9d:d8:36: - 15:d2:07:37:fc:6c:73:1d:da:a8:1c:e8:20:8e:32:7a:fe:6d: - 27:16:e4:58:6c:eb:3e:f0:fe:24:52:29:71:b8:96:7b:53:4b: - 45:20:55:40:5e:86:1b:ec:c9:46:91:92:ee:ac:93:65:91:2e: - 94:b6:b6:ac:e8:a3:34:89:a4:1a:12:0d:4d:44:a5:52:ed:8b: - 91:ee:2f:a6:af:a4:95:25:f9:ce:c7:5b:a7:00:d3:93:ca:b4: - 3c:5d:4d:f7:b1:3c:cc:6d:b4:45:be:82:ed:18:90:c8:86:d1: - 75:51:50:04:4c:e8:4f:d2:d6:50:aa:75:e7:5e:ff:a1:7b:27: - 19:1c:6b:49:2c:6c:4d:6b:63:cc:3b:73:00:f3:99:26:d0:82: - 87:d3:a9:36:9c:b4:3d:b9:48:68:a8:92:f0:27:8e:0c:cd:15: - 76:42:84:80:c9:3f:a3:7e:b4:dd:d7:f8:ac:76:ba:60:97:3c: - 5a:1f:4e:de:71:ee:09:39:10:dd:31:d5:68:57:5d:1a:e5:42: - ba:0e:68:e6:45:d3 + bc:e3:56:22:03:e4:5c:b9:67:ff:94:bc:75:9c:00:85:b0:d5: + 9c:c4:c3:29:66:5e:8b:b2:a9:a6:30:86:71:1a:6b:f2:00:c5: + 82:ab:5f:50:04:2a:fb:ed:b8:4c:b9:00:1b:49:57:92:11:cd: + a2:bc:cb:0f:a8:b4:61:f8:14:ca:a0:ec:40:17:ba:55:a1:c4: + bc:a6:b2:5a:ef:f4:20:10:77:47:d0:a0:c5:58:b9:6c:b5:10: + 7b:85:4a:43:a3:fb:2c:01:b9:77:17:b0:be:a0:ee:ae:ae:4d: + 67:86:48:89:57:86:78:ea:3c:ed:f0:41:35:8d:71:68:55:f9: + f2:e9:ac:32:d4:c6:a2:ef:ec:54:e6:c4:8e:2c:fd:bd:aa:60: + 56:65:33:95:ea:10:c6:74:04:eb:2a:6e:9b:11:f6:61:00:aa: + fd:ec:f2:0b:b1:4b:11:cd:93:eb:df:98:ae:4c:b4:07:04:4a: + e5:ef:ff:52:58:75:f5:3e:a4:71:e1:4a:72:5c:a9:8f:d4:aa: + 88:f0:6a:71:b4:c3:00:5f:99:6e:d7:91:af:6c:98:0d:64:c2: + 24:c7:9e:05:11:68:5e:24:62:e3:2e:45:ec:a3:34:f2:a3:9d: + 4d:e5:32:18:2f:74:fc:11:f1:36:50:4f:a0:40:29:68:5c:43: + 4c:23:6c:5d:72:c4:ec:52:76:eb:dc:b2:bc:1f:a6:c4:06:66: + 9b:5c:c7:cc:ca:f2:d1:25:4f:de:a5:1f:8d:e4:0c:49:b6:cf: + 85:40:a1:b9:1f:c6:c7:19:15:07:63:34:93:d0:57:a0:5a:70: + ec:af:4a:1c:72:17:1d:74:a3:6c:31:45:0b:33:7a:a1:b8:46: + db:c7:0e:64:4c:6f:b7:99:04:82:43:1f:e0:59:d6:99:21:27: + 28:09:40:ae:fc:c4:23:aa:a0:0c:08:05:2a:92:1c:db:23:9e: + d1:d5:63:ae:39:13:a3:12:88:5a:43:3c:4a:6e:32:f0:84:9f: + f9:09:0c:91:e7:b8 -----BEGIN CERTIFICATE----- -MIIEgDCCAuigAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +MIIEgjCCAuqgAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW -MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx -NDIzMTZaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg -Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCAaIwDQYJKoZI -hvcNAQEBBQADggGPADCCAYoCggGBANCgm7G5O3nuMS+4URwBde0JWUysyL9qCvh6 -CPAl4yV7avjE2KqgYAclsM9zcQVSaL8Gk64QYZa8s2mBGn0Z/CCGj5poG+3N4mxh -Z8dOVepDBiEb6bm+hF/C2uuJiOBCpkVJKtC5a4yTyUQ7yvw8lH/dcMWt2Es73B74 -VUu1J4b437CDz/cWN78TFzTUyVXtaxbJf60gTvAe2Ru/jbrNypbvHmnLUWZhSA3o -eaNZYdQQjeANOwuFttWFEt2lB8VL+iP6VDn3lwvJREceVnc8PBMBC2131hS6RPRT -NVbZPbk+NV/bM5pPWrk4RMkySf5m9h8al6rKTEr2uF5Af/sLHfhbodz4wC7QbUn1 -0kbUkFf+koE0ri04u6gXDOHlP+L3JgVUUPVksxxuRP9vqbQDlukOwojYclKQmcZB -D0aQWbg+b9Linh02gpXTWIoS8+LYDSBRI/CQLZo+fSaGsqfX+ShgA+N3x4gEyf6J -d3AQT8Ogijv0q0J74xSS2K4W1qHefQIDAQABo2MwYTAdBgNVHQ4EFgQU8+yUjvKO -MMSOaMK/jmoZwMGfdmUwHwYDVR0jBBgwFoAU8+yUjvKOMMSOaMK/jmoZwMGfdmUw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD -ggGBAIsAVHKzjevzrzSf1mDq3oQ/jASPGaa+AmfEY8V040c3WYOUBvFFGegHL9ZO -S0+oPccHByeS9H5zT4syGZRGeiXE2cQnsBFjOmCLheFzTzQ7a6Q0jEmOzc9PsmUn -QRmw/IAxePJzapt9cTRQ/Hio2gW0nFs6mXprXe870+k7MwESZc9eB9gZr9VT6vAQ -rMS2Jjw0LnTuZN0dNnWJRACwDf0vswHMGosCzWzogILKv4LXAJ3YNhXSBzf8bHMd -2qgc6CCOMnr+bScW5Fhs6z7w/iRSKXG4lntTS0UgVUBehhvsyUaRku6sk2WRLpS2 -tqzoozSJpBoSDU1EpVLti5HuL6avpJUl+c7HW6cA05PKtDxdTfexPMxttEW+gu0Y -kMiG0XVRUARM6E/S1lCqdede/6F7Jxkca0ksbE1rY8w7cwDzmSbQgofTqTactD25 -SGiokvAnjgzNFXZChIDJP6N+tN3X+Kx2umCXPFofTt5x7gk5EN0x1WhXXRrlQroO -aOZF0w== +MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAgFw0xODA4MjkxNDIzMTZaGA8yNTI1MTAy +ODE0MjMxNlowTTELMAkGA1UEBhMCWFkxJjAkBgNVBAoMHVB5dGhvbiBTb2Z0d2Fy +ZSBGb3VuZGF0aW9uIENBMRYwFAYDVQQDDA1vdXItY2Etc2VydmVyMIIBojANBgkq +hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA5rri5MHCDBw+Yti5XFcuUriDxYg65pp6 +9WQWM+s3bi9782gDRWVHXXEQWcorGwBsgRRh9IZZP+r9eDcWnUPxxPZpjMUpBoie +JiIErATYhzRIOetr8guSqsNuY1FRa8Kt/1zIL7IbnCCKQD6iL2rqyNk3Q1zc7ZLi +2UDSYZ9xivXtObqoXj61IWMQ2G+04hEBCxDou/ti70hVvPXSnKtorpUlGfKXfRrc +ZuqIXobky8tpTV6wo/tsMeQoYF6Q8dQuEFDhhfANXL3dRSQIGT4ck2aPK9pTfQQc +DkLEaF6mzakY7afNatDRhrqQ/7dM3sdDJG3HHGucgefhG1clkKkOyVbz9mteLbQu +QFCbQmPS1pkcONzPKyyncvHHXmM0dkj0PogTnoYWUy90+4cBjSKkaDPuE2x6BhRU +VhdXV5g00AtmCeOICfilFRwQc9CIUJleGGU7/zEnG17GqkH9LS8Yp8Dyq8citQtp +0nPRu9AcPfqkNWLNM4bHoCMPuWrV0m2NAgMBAAGjYzBhMB0GA1UdDgQWBBTACiso +Q95fyX1H5UebNvJljGc74jAfBgNVHSMEGDAWgBTACisoQ95fyX1H5UebNvJljGc7 +4jAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF +AAOCAYEAvONWIgPkXLln/5S8dZwAhbDVnMTDKWZei7KppjCGcRpr8gDFgqtfUAQq +++24TLkAG0lXkhHNorzLD6i0YfgUyqDsQBe6VaHEvKayWu/0IBB3R9CgxVi5bLUQ +e4VKQ6P7LAG5dxewvqDurq5NZ4ZIiVeGeOo87fBBNY1xaFX58umsMtTGou/sVObE +jiz9vapgVmUzleoQxnQE6ypumxH2YQCq/ezyC7FLEc2T69+Yrky0BwRK5e//Ulh1 +9T6kceFKclypj9SqiPBqcbTDAF+ZbteRr2yYDWTCJMeeBRFoXiRi4y5F7KM08qOd +TeUyGC90/BHxNlBPoEApaFxDTCNsXXLE7FJ269yyvB+mxAZmm1zHzMry0SVP3qUf +jeQMSbbPhUChuR/GxxkVB2M0k9BXoFpw7K9KHHIXHXSjbDFFCzN6obhG28cOZExv +t5kEgkMf4FnWmSEnKAlArvzEI6qgDAgFKpIc2yOe0dVjrjkToxKIWkM8Sm4y8ISf ++QkMkee4 -----END CERTIFICATE----- diff --git a/Lib/test/certdata/pycakey.pem b/Lib/test/certdata/pycakey.pem index a6bf7356f4f684..0248f985545e20 100644 --- a/Lib/test/certdata/pycakey.pem +++ b/Lib/test/certdata/pycakey.pem @@ -1,40 +1,40 @@ -----BEGIN PRIVATE KEY----- -MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDQoJuxuTt57jEv -uFEcAXXtCVlMrMi/agr4egjwJeMle2r4xNiqoGAHJbDPc3EFUmi/BpOuEGGWvLNp -gRp9Gfwgho+aaBvtzeJsYWfHTlXqQwYhG+m5voRfwtrriYjgQqZFSSrQuWuMk8lE -O8r8PJR/3XDFrdhLO9we+FVLtSeG+N+wg8/3Fje/Exc01MlV7WsWyX+tIE7wHtkb -v426zcqW7x5py1FmYUgN6HmjWWHUEI3gDTsLhbbVhRLdpQfFS/oj+lQ595cLyURH -HlZ3PDwTAQttd9YUukT0UzVW2T25PjVf2zOaT1q5OETJMkn+ZvYfGpeqykxK9rhe -QH/7Cx34W6Hc+MAu0G1J9dJG1JBX/pKBNK4tOLuoFwzh5T/i9yYFVFD1ZLMcbkT/ -b6m0A5bpDsKI2HJSkJnGQQ9GkFm4Pm/S4p4dNoKV01iKEvPi2A0gUSPwkC2aPn0m -hrKn1/koYAPjd8eIBMn+iXdwEE/DoIo79KtCe+MUktiuFtah3n0CAwEAAQKCAYAD -iUK0/k2ZRqXJHXKBKy8rWjYMHCj3lvMM/M3g+tYWS7i88w00cIJ1geM006FDSf8i -LxjatvFd2OCg9ay+w8LSbvrJJGGbeXAQjo1v7ePRPttAPWphQ8RCS+8NAKhJcNJu -UzapZ13WJKfL2HLw1+VbziORXjMlLKRnAVDkzHMZO70C5MEQ0EIX+C6zrmBOl2HH -du6LPy8crSaDQg8YxFCI7WWnvRKp+Gp8aIfYnR+7ifT1qr5o9sEUw8GAReyooJ3a -yJ9uBUbcelO8fNjEABf9xjx+jOmOVsQfig2KuBEi0qXlQSpilZfUdYJhtNke9ADu -Hui6MBn04D4RIzeKXV+OLjiLwqkJyNlPuxJ2EGpIHNMcx3gpjXIApAwc47BQwLKJ -VhMWMXS0EWhCLtEzf5UrbMNX+Io3J7noEUu6jxmJV1BKhrnlYeoo4JryN0DUpkSb -rOAOJLOkpfj7+gvqmWI4MT6SQXSr6BK+3m4J5bVSq4pej9uG5NR3Utghi5hF7DEC -gcEA3cYNPYPFSTj9YAR3GUZvwUPVL3ZEFcwjrIeg87JhuZOH/hSQ33SgeEoAtaqL -cLbimj7YzUYx3FOUCp/7yK/bAF1dhAbFab1yZE46Qv2Vi4e+/KEBBftqxyJl5KyV -vc/HE1dXZGZIO1X5Z5MX8nO3rz/YayiozYVmMibrbHxgTEDC4BrbWtPJQNkflWEb -FXNjkm0s2+J3kFANpL94NUKMGtArxQV3hWydGN8wS3Fn7LDnHDoM5mOt/naeKRES -fwwpAoHBAPDTKsKs2LEe4YFzO1EClycDelppjxh5pHSnzTWSq40aKx533SG4aLyI -DmghzoA3OmY0xpAy1WpT9FeiDNbYpiFCH3qBkArQR2QCu+WGUQ9tDoeN0C2Dje4e -Yix49BjcGSWzSNvh+tU9PzRc/9eVBMAQuaCm3yNEL+Z7hFTzkrCWK23+jP/OzIIC -XhnKdOveIYVAjlVgv8CoWIy3xhwXyqPAcstcPmlv9sDAYn37Ot7rGIS7e0WyQxvg -gxnOxFzKNQKBwQDOPOn/NNV5HKh0bHKdbKVs4zoT4zW515etUIvbVR4QSCSFonZ/ -d6PreVZjmvAFp+3fZ2aSrx6bOJZJszGhFfjhw/G9X9aiWO1SXnVL6yrxERIJOWkM -ORy5h0GegOjYFauaTvUUhxHRLEi9i0sPy5EcRpFqReuFBPNe3Fa/EoMzJl6TriYj -tyRHTCNU9XMMZbxJZYH8EgUCjY/Cj9SoIvTL0p+Bn23hBHqrsJLm9dWhhXnHBC0O -68/Y/lJi+l9rCtECgcEAt6PfTJovl0j8HxF23vyBtK9TQtSR2NERlh9LPZn9lViq -Hs66YndT7sg1bDSzWlRDBSMjc1xAH5erkJOzBLYqYNwiUvGvnH9coSfwjkMRVxkL -ZlS+taZGuZiTtmP5h2d3CaegXIQDGU5d/xkXwxYQjEF0u8vkBel+OVxg+cLPTjcF -IRhl/r98dXtGtJYM+LvnhcxHfVWMg2YcOBn/SPbfgGVFZEuQECjf2fYaZQUJzGkr -xjOM+gXIZN6cOjbQyA0tAoHADgR5/bMbcf6Jk0w56c/khFZz/pusne5cjXw5a6qq -fClAqnqjGBpkRxs7HoCR3aje0Pd0pCS93a6Wiqneo4x4HDrpo+pWR2KGAAF4MeO3 -3K94hncmiLAiZo8iqULLKCqJW2EGB2b7QzGpY7jCPiI1g80KuYPesf4ZohSfrr1w -DoqGoNrcIVdVmUgX47lLqIiWarbbDRY0Am9j58dovmNINYr5wCYGbeh2RuUmHr4u -E2bb0CdekSHf05HPiF9QpK1z +MIIG/AIBADANBgkqhkiG9w0BAQEFAASCBuYwggbiAgEAAoIBgQDmuuLkwcIMHD5i +2LlcVy5SuIPFiDrmmnr1ZBYz6zduL3vzaANFZUddcRBZyisbAGyBFGH0hlk/6v14 +NxadQ/HE9mmMxSkGiJ4mIgSsBNiHNEg562vyC5Kqw25jUVFrwq3/XMgvshucIIpA +PqIvaurI2TdDXNztkuLZQNJhn3GK9e05uqhePrUhYxDYb7TiEQELEOi7+2LvSFW8 +9dKcq2iulSUZ8pd9Gtxm6ohehuTLy2lNXrCj+2wx5ChgXpDx1C4QUOGF8A1cvd1F +JAgZPhyTZo8r2lN9BBwOQsRoXqbNqRjtp81q0NGGupD/t0zex0Mkbccca5yB5+Eb +VyWQqQ7JVvP2a14ttC5AUJtCY9LWmRw43M8rLKdy8cdeYzR2SPQ+iBOehhZTL3T7 +hwGNIqRoM+4TbHoGFFRWF1dXmDTQC2YJ44gJ+KUVHBBz0IhQmV4YZTv/MScbXsaq +Qf0tLxinwPKrxyK1C2nSc9G70Bw9+qQ1Ys0zhsegIw+5atXSbY0CAwEAAQKCAYBf +4VWcPjBHHA2Iwgr1Jn1nfqmzklL3tUZXZwoa9SoJrc3Sbmy9j8LCP9PNnEehZuGw +GipClPnNp/dA15OcMrnrYYKnLt9Hico+inBqk3Dvbnh9KSmoYcrHD4N13jr5juMD +dSjzOQ5kKNmKrPx0u/dpE2r1oUdlql5+bYN/ceSbHGtCTCDfWSun/iTn7DO8pdhL +IvGz/Fk2mlaWuYiV9lz//5Z1W+w73sesNNYKgf/d+F9/+VNqMXbanLdypJmTBNp9 +eoS3eLk3ycoiGHCnVNm28IjeElFkUOJKVXY39BoMbS/x1MUHjuZDxdOcEaCV9iOr +adg7d91srwJlHGGX3IkC+08J5OJZtfTEMcB3i9g2omOxLAFfapeRxZdD6zMdxWUG +PUNIiy7UKaHe7JJ+fftnk0QBu5DzyrdP0fryFNz9nySot+gzVlU9idTMnIyE73UJ +foPowKpmxDOYNw0ZGXBIP/lMRNXkQM765P1NJpCN0Ud+kBl7GdFMkI++GFjiH3kC +gcEA+VIsOliXn5xfU2zXZb2q/bPPlCBDw/EzIelRTFVqUC2kL3oh4NlDNWAFgcfX +rQUCCoY9rEKYdTQI0w47K4AkJYajnDG2zHj6fkaPcLweyEDa9Hw2ezDDiwz2uwH2 +4HW+JBZ0I7rRuSRXTSJrzFYYVU6tsr54Kl85l2bmL8V2XVYj4ko9uddsyH0F1Ejt +BYPBghr01uEHsO3nIcNMl10fS9eXdhMTr/haXdDxpFXjR5AO/ouQEyGrXk6LPJpn +rUE7AoHBAOzpN8lQDQlf0JcYFBvFd7JdrhpbaIdATmT0NM/Mh+4B8qy5qnIJBdeQ +9T46sHmHzvhtGHmnP+dckKJi1Y/8Lt6noWNYDRnmrDol046ce2Nj8gxDGBT1kG4n +GBoKkA1Gj5N5yWMB8cGTVzQ+tViRMkn9+jmxRaNsW1Y0j7lMtVz0hJOUscbUALV1 +fYGH7zPiqfHoKoz7UuB2OlCKOH0+V96lAO4EgKMQNcEKMs9+Tg13fHTAyodxy/CY +tjUcKpef1wKBwBE24EDjDw0BMf/Dmxe2QdEkkieLFsK3q60iu+9GUoHYtOZmS2KH +/cD4sUilsLmMh/iMDkQPkRE+l4FjESjOvzAsHK3TLOjvTXRckNja1FFFURjiXqyg +0E+QhJSi7RXQa2F4f2pcItDitnhn8QN5ylJRjWKzDf729jYC78/KlYKaSP393Ecx +nZw2LanboynnT/wYumD/xpUrx/Kn1mj5EAkfiKCpbomO30Zs/9I17+xoAPEIV9lK +UNfBGpIDozbuMwKBwFlZmAWf4FrRvSzPEv5qWjt2I2yjXufrs+VVSPm6LOXx7CGC +oKsDhiWH8UZ4AgjD1KZTFvECyBItEgt8dQkp1k95L1/1XHORURFZJNHbaJnSnv5K +67Ez8DXrHqbrpuqq2wmG3BIwMIqOVExK/kAZ+rp3REEv/5CkFEqN5kq/iIM3YSz7 +3pSbbm0Bk8UfjHKoIOowYqPrQZWQYWvwxV9O/PrmhlQ+dHmLaoqUmxcwjqV7k//A +mmG85GqoXcfoCJRI3wKBwBdnxBzg17TMFufuvX2Bc/M9MqL3+vlwH6SDdr+2yYKA +hiD8Ur2OwtDGHnV4m3NeA/Guyz32H4CzvFAnpzlvMow/dvfp9JUcpdeidhIBZy8V +D7VODIiCyyTAb3g1LK0+HTEHAVRFihbNXhub/P6NckFXw0MJJQOvNNsYQnJTUngY +oxqdt1HeAujEwBrRSfrOGE2K8FVJ/MYf4PmxTIocICBk1/BmNHsUeJ5yFUDBweh5 +UJN6yp5PiGwvW8WFl4waXw== -----END PRIVATE KEY----- diff --git a/Lib/test/certdata/revocation.crl b/Lib/test/certdata/revocation.crl index 431a831c4f196a..a10586d1f79345 100644 --- a/Lib/test/certdata/revocation.crl +++ b/Lib/test/certdata/revocation.crl @@ -1,14 +1,14 @@ -----BEGIN X509 CRL----- -MIICJjCBjwIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE +MIICKDCBkQIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j -YS1zZXJ2ZXIXDTIzMTEyNTA0MjEzNloXDTQzMDEyNDA0MjEzNlqgDjAMMAoGA1Ud -FAQDAgEAMA0GCSqGSIb3DQEBCwUAA4IBgQDMZ4XLQlzUrqBbszEq9I/nXK3jN8/p -VZ2aScU2le0ySJqIthe0yXEYuoFu+I4ZULyNkCA79baStIl8/Lt48DOHfBVv8SVx -ZqF7/fdUZBCLJV1kuhuSSknbtNmja5NI4/lcRRXrodRWDMcOmqlKbAC6RMQz/gMG -vpewGPX1oj5AQnqqd9spKtHbeqeDiyyWYr9ZZFO/433lP7GdsoriTPggYJJMWJvs -819buE0iGwWf+rTLB51VyGluhcz2pqimej6Ra2cdnYh5IztZlDFR99HywzWhVz/A -2fwUA91GR7zATerweXVKNd59mcgF4PZWiXmQMwcE0qQOMqMmAqYPLim1mretZsAs -t1X+nDM0Ak3sKumIjteQF7I6VpSsG4NCtq23G8KpNHnBZVOt0U065lQEvx0ZmB94 -1z7SzjfSZMVXYxBjSXljwuoc1keGpNT5xCmHyrOIxaHsmizzwNESW4dGVLu7/JfK -w40uGbwH09w4Cfbwuo7w6sRWDWPnlW2mkoc= +YS1zZXJ2ZXIXDTI0MTAwODExNTExMloYDzI0MDgwMTI5MTE1MTEyWqAOMAwwCgYD +VR0UBAMCAQAwDQYJKoZIhvcNAQELBQADggGBAKN4S2g4wCeU1fO5TSckAwxgdzdh +pY28f4musnQt7l37MzB2gmJVDSCZfQyrUnfSEST15WEY7CZVyTlbsu6gYKK53Yej +j3ORBfGUgzaz62Hs8di7SrHDzWUlNCFa47YFWDmtj96KTX1AItnpkCCE58Wfpivp +Hu+YINFpi/2vI2nvP/xcfvgT3dXek9kyz+2jHmadxcn2VerSBZZ9fiZk/k4NzgoI +JdiSswtN1c5GelHQfftwRXbWqsp6TvgHC5MagDuHh5Bj7/DftI7nCy0IT5GnP8lS +ZqmXUMpa8zbtSNSTIk0XepmypNW8HHMQbfJp0y7yOQ4pPyXICrjYTg7wKpODRcm3 +BRN89vvNfCszMU41glVfQG+2Po5uAMTl1hX8WYSj0+Xxrdg+wgJead4S5Sq3CgMT +bKsH2Dqh43L8BTxuxzLQyduK0gKSl8vlN7a9Bzm3IXYlyk+kKSyo4jP8XK79pj1k +1JglMFM9jpoMF2VmNjiROtVEl2tbDGwlvpjWYQ== -----END X509 CRL----- diff --git a/Lib/test/certdata/ssl_cert.pem b/Lib/test/certdata/ssl_cert.pem index 427948252b786e..6db52404942210 100644 --- a/Lib/test/certdata/ssl_cert.pem +++ b/Lib/test/certdata/ssl_cert.pem @@ -1,27 +1,27 @@ -----BEGIN CERTIFICATE----- -MIIEgzCCAuugAwIBAgIUU+FIM/dUbCklbdDwNPd2xemDAEwwDQYJKoZIhvcNAQEL +MIIEhTCCAu2gAwIBAgIUTxhwRX6zBQc3+l3imDklEbqcDpIwDQYJKoZIhvcNAQEL BQAwXzELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYD VQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJbG9jYWxo -b3N0MB4XDTIzMTEyNTA0MjEzNloXDTQzMDEyNDA0MjEzNlowXzELMAkGA1UEBhMC -WFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRob24gU29m -dHdhcmUgRm91bmRhdGlvbjESMBAGA1UEAwwJbG9jYWxob3N0MIIBojANBgkqhkiG -9w0BAQEFAAOCAY8AMIIBigKCAYEAzXTIl1su11AGu6sDPsoxqcRGyAX0yjxIcswF -vj+eW/fBs2GcBby95VEOKpJPKRYYB7fAEAjAKK59zFdsDX/ynxPZLqyLQocBkFVq -tclhCRZu//KZND+uQuHSx3PjGkSvK/nrGjg5T0bkM4SFeb0YdLb+0aDTKGozUC82 -oBAilNcrFz1VXpEF0qUe9QeKQhyd0MaW5T1oSn+U3RAj2MXm3TGExyZeaicpIM5O -HFlnwUxsYSDZo0jUj342MbPOZh8szZDWi042jdtSA3i8uMSplEf4O8ZPmX0JCtrz -fVjRVdaKXIjrhMNWB8K44q6AeyhqJcVHtOmPYoHDm0qIjcrurt0LZaGhmCuKimNd -njcPxW0VQmDIS/mO5+s24SK+Mpznm5q/clXEwyD8FbrtrzV5cHCE8eNkxjuQjkmi -wW9uadK1s54tDwRWMl6DRWRyxoF0an885UQWmbsgEB5aRmEx2L0JeD0/q6Iw1Nta -As8DG4AaWuYMrgZXz7XvyiMq3IxVAgMBAAGjNzA1MBQGA1UdEQQNMAuCCWxvY2Fs -aG9zdDAdBgNVHQ4EFgQUl2wd7iWE1JTZUVq2yFBKGm9N36owDQYJKoZIhvcNAQEL -BQADggGBAF0f5x6QXFbgdyLOyeAPD/1DDxNjM68fJSmNM/6vxHJeDFzK0Pja+iJo -xv54YiS9F2tiKPpejk4ujvLQgvrYrTQvliIE+7fUT0dV74wZKPdLphftT9uEo1dH -TeIld+549fqcfZCJfVPE2Ka4vfyMGij9hVfY5FoZL1Xpnq/ZGYyWZNAPbkG292p8 -KrfLZm/0fFYAhq8tG/6DX7+2btxeX4MP/49tzskcYWgOjlkknyhJ76aMG9BJ1D7F -/TIEh5ihNwRTmyt023RBz/xWiN4xBLyIlpQ6d5ECKmFNFr0qnEui6UovfCHUF6lZ -qcAQ5VFQQ2CayNlVmQ+UGmWIqANlacYWBt7Q6VqpGg24zTMec1/Pqd6X07ScSfrm -MAtywrWrU7p1aEkN5lBa4n/XKZHGYMjor/YcMdF5yjdSrZr274YYO1pafmTFwRwH -5o16c8WPc0aPvTFbkGIFT5ddxYstw+QwsBtLKE2lJ4Qfmxt0Ew/0L7xkbK1BaCOo -EGD2IF7VDQ== +b3N0MCAXDTI0MTAwODExNTExMloYDzI0MDgwMTI5MTE1MTEyWjBfMQswCQYDVQQG +EwJYWTEXMBUGA1UEBwwOQ2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBT +b2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDDAlsb2NhbGhvc3QwggGiMA0GCSqG +SIb3DQEBAQUAA4IBjwAwggGKAoIBgQDwcIAYm12nmQTGB3caFn7alDe3LSliEfNC +2ZTR+5sh1eucQPbzgFM5SR4soKGElwI68Eg7g1kwqu3zmrI/FAiQI/RrUHyBZiEt +nFBPM44vY02XjUlJ9nBtgP7QjpRz6ZP0z1DrrojpYLVwg9cR0khTqD5cg2jvTB05 +yL9lQNk295/rMuueC9FaAQ+Y5la0ub7Lbe8gkYPotYliGx5qqCQmsXeTsxCpvQD7 +u0vBF9/nxlwywwzKGXabcN9YQhSECCC4c+eYjqoRgvAaF48xEnokxenzBIqZ82BR +kFo+zfNR+VhJRctNiZ6Ppa1Ise1H3LjZMDfY1S89QOLYsFXUp8L7ZMVE27Bej+Sq +4wEJ3soK/k1kr0YauqJ0lCEKkUPD9OeNHmczeakjj11tgtctsYbwgDSUYGA3w+DC +KD1aSfeuR3Hj89cSsVRrRrPFFih46Tr2PpTNoK6MtPH3RPJKV+Db8E1V2mXmNE0M +Lg6ramSHsD9iZXTLhG2JO+/876k3N3kCAwEAAaM3MDUwFAYDVR0RBA0wC4IJbG9j +YWxob3N0MB0GA1UdDgQWBBR459BlAel5MqCtG0DrvVtMZlQfuTANBgkqhkiG9w0B +AQsFAAOCAYEAaTFWjK/LFzOo+0TWqTTj4WC4N3I8JFrHnlqFJlpchYTW2z92SU1G +iEzFjWzuDNjp5KM9BqlmGtzXZvy6MItGkYsjPRdPVU0rbCmyTho6y77kTyiEG12V +UAJ1in3FOQfDwLPcp7wQRgCQq3iZlv7pwXp2Lm5fzu8kZPnxmTVdiKQun9Ps7uKq +BoM0fM2K14MxVO4Wc0SERnaPszE7xAhkIcs+NRT/gHYdTBlPhao83S3LOOdtCqCP +pNUOEaShlwI5bVsDPUXNX/eS0MYFNlsYTb5rCxK8jf3W3KNjKTOzN94pHiQOhpkg +xMPPi3m03/9oKTVXBtHI2A+u3ukheKE6sBXCLdv/GEs9zYI49zmpQxNWz5EOumWL +k+W/vPv7cD6LeHxxp+nCbEJi1gZtYb3gMY1sLkMNxcOu0QHTqHfme+k7VKWm8anO +3ogGdGtPuPAD/qjMwg3ChSDLl5Ur/E9UPlD4yM/7KtUD7mLv+jbddA62EiA9MxVB +t+yt7pOwOA66 -----END CERTIFICATE----- diff --git a/Lib/test/certdata/ssl_key.passwd.pem b/Lib/test/certdata/ssl_key.passwd.pem index 6ab7d57d003a35..e60a66c2798784 100644 --- a/Lib/test/certdata/ssl_key.passwd.pem +++ b/Lib/test/certdata/ssl_key.passwd.pem @@ -1,42 +1,42 @@ -----BEGIN ENCRYPTED PRIVATE KEY----- -MIIHbTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIsc9l0YPybNICAggA -MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDxb9ekR9MERvIff73hFLc6BIIH -ENhkFePApZj7ZqpjBltINRnaZhu8sEfG1/y3ejDBOa5Sq3C/UPykPfJh0IXsraAB -STZO22UQEDpJzDnf1aLCo2cJpdz4Mr+Uj8OUdPiX83OlhC36gMrkgSYUdhSFQEas -MLiBnXU6Z5Mv1Lxe7TJrnMyA4A8JYXXu5XVTErJrC0YT6iCPQh7eAoEtml9a/tJM -OPg6kn58zmzVDp8LAau4Th1yhdD/cUQM09wg2i5JHLeC9akD+CkNlujVoAirLMTh -xoMXTy2dkv/lIwI9QVx6WE/VKIngBAPIi3Q+YCIm0PaTgWj5U10C8j4t7kW2AEZK -z82+vDOpLRGLo/ItNCO9F/a9e4PK4xxwFCOfR80tQNhs5gjKnbDz5IQv2p+pUfUX -u+AIO0rBb3M9Yya1MC2pc5VLAeQ3UF6YPrNyNjoDsQOytY3YtRVyxiKW72QzeUcX -Vpc3U6u8ZyHhkxK6bMv3dkPHGW1MOBd9/U5z+9lhHOfCGFStIQ9M8N48ZCWEGyty -oZT3UApxgqiBAi1h14ZyagA2mjsMNtTmmkSa3v26WUfrwnjm7LD1/0Vm+ptBOFH2 -CkP/aAvr8Ie+ehWobXGpqwB6rlOAwdpPrePtEZiZtdt58anmCquRgE5GIYtVz30f -flRABM8waJ196RDGkNAmDA3p/sqHy4vbsIOMl8faZ3QxvGVZlPbUEwPhiTIetA5Q -95fT/uIcuBLfpbaN23j/Av3LiJAeABSmGZ+dA+NXC5UMvuX8COyBU0YF2V6ofpIu -gP3UC7Tn4yV3Pbes81LEDCskaN6qVRil47l0G+dNcEHVkrGKcSaRCN+joBSCbuin -Rol34ir9azh8DqHRKdVlLlzTmDQcOwmi0Vx0ASgBXx4UI3IfK45gLJVoz6dkUz+3 -GIPrnh5cw2DvIgIApwmuCQUXPbWZwUW0zuyzhtny9W6S72GUE/P5oUCV+kGYBsup -FNiAyR9+n/xUuzB5HqIosj4rX+M4il4Ovt+KaCO6/COi+YjAO/9EnSttu8OTxsXl -wvgblsT7Y1d+iUfmIVNGtbc5NX46ktrbGiqgPX7oR7YDy5/+FQlnPS1YL0ThUiAC -2RbItu6b0uUyfu2jfWaGqy+SiRZ81rLwKPU3vJSEPfooVcJTG49EE006ZC4TvRzu -fNkId+P+BxvhEpUM4+VKzfzViEPuzR1u/DuwLAavS7nr5qb+zaUq+Fte5vDQmjjC -fflT8hS0BGpYEGndeZT4k+mZunHgs3NVUQ4/HW0nflf1j6qAn4+yIB79dH9d/ubt -RyBG29K+rN0TI/kH9BQZfsAcbnmhpT/ud0mJfeHZ0Lknn6mdJ/k4LXN0T1IlLKz3 -cSleOWY3zjKaOsbuju1o5IiVIr+AF/w+M4nzzDX6DDVpBPAt9iUnDGqjh6mJ3QWQ -CyCJDLNP0X8rZ8va2KOPorIBhmfDwJKEtIoXkb2hqWURTE0chC444QqiMsMXsX6+ -mOmiWGkdBFnEpGITISFTGERCjEfqOgTMweCANpquiLymJXgDURL603N2WexSgwnu -Gy1Ws1cA+1cT65ZLqjSqayZ6WdQvsKBBAnGW5LbwBhoCkX0vahs5nZiw0KnskP60 -wNMnyxaS1SuDJ65n+vuLUl7WeysRyz10RWliYZFiUE7jIXfWeYGonAo4eyCEeV/f -HInxxpswsg/na8BGBPMsx2SfBIiIvSIT4VNxHrL3sIfDrnb2HH/ut/oSLBgSKzY5 -DdkPz309kMM5dqnHANAgRrtVhqzLQE3kNGZ9mO/X1FAyXx8eB7NSeB6ysD8CAHvm -lkyfsGTzVsnuWWpeHqplds0wx5+XouVtFRI5J3RGa39mbpM1hMyIbS0O24CBKW6K -7n2UunbABwepL1hSa4e01OPdz4Zx/oayOevTtlfVqh68cEEc6ePdzf7z69pjot7B -eqlNaqa1POOmkuygL+fiP1BAR3rGEoQKXqb+6JjzLM9CnhCQHHPR2UdqukkEYwsa -bh9CU8AlfAJ19KFDria4JZXtl8LLMLLqWIO8fmQx7VqkEkEkl8jecO8YMaZTzFEb -bW7QtIZ1qHWH0UIHH3Qlav72NJTKvGIbtp1JNrLdsHcYNcojLZkEeA83UPaiTB2R -udltVUd016cktRVzLOKrust8kzPq3iSjpoIXFyFqIYHvWxGHgc7qD5gVBlazqSsV -qudDv+0PCBjLWLjS6HkFI8BfyXd3ME2wvSmTzSSgSh4nVJNNrZ/RVTtQ5MLVcdh0 -sJ3qsq2Pokf61XXjsTiQorX+cgI9zF6zETXHvnLf9FL+G/VSlcLUsQ0wC584qwQt -OSASYTbM79xgmjRmolZOptcYXGktfi2C4iq6V6zpFJuNMVgzZ+SbaQw9bvzUo2jG -VMwrTuQQ+fsAyn66WZvtkSGAdp58+3PNq31ZjafJXBzN +MIIHdTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQMMUN+qWFiwTbIjjb +cLEtYQICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEGGzvsc6e5Zn2M9S +sdoMbaIEggcQ0mQYuMcujHtFfRKLmfclrf/dHOYgnVYc2c9MSR3jfoOwnTdBR1Op +MUuO4ukqrxGkrJBy+MLb1oPEGrnvn39pdBMZx4CBmdwX0jDq36UL9EU5/m071mT+ +Xoe/z/RHtrtmbpA9XKu7n/5gLi9jg57qorss8r5MaPHghm2ZOqaQZIOOMCF+4gNU +Cmp/NHL9TUM/sfQpaw9YM4VuTRyHNO3OiDKaCCz2romFrgM1TYz/I5/n5MMR543J +dsyIFzef3jHYfaXTl97v9ibGVpIUCKfHgYlQf41H+Me890AP4HaS0e2y+73/UwjB +4YSzPVm+lCiBWhFDbMuRmPY3YDQOA+TV06oCO8/aMamPRsryl8g7iOQAIz4hQdoP +ZTXtSZ+F68YmfPjKAj3NNQosvLzfuSfxZ9HqyvZ/0w1eead7pdSs7uvCEvN2Zcvk +a9EWy1bM895zD3DwrxqGnSYbitXouIOf9zHsl2lRUK44XmvgTHoNaJFIVyzVNgQr +e1YJM7LbEvErspa6cZTz7DCR44g9cYBi393XEt5yl4NCtq2PFq762pNqpsQqt5/Y +pLX5w12npf+OZ1WqJla89FabqLaJ1blmDEgfko0XriofW5gWLByvhYINtt+u5x/5 +QdTya2gWBxI2K+sAeGIt913RBAus8hLEDnVGDX/FEthz1OOKLXp0G6HQmqUom5PU +/O36GszhWIz1Q/SpMfZkdHfEfbJFCx0mpaJZTlC01hg+OpnwWxUvO2dxrK46xAzd +/obsVQRLOuyTxjIrQd+vVZRIcOroTHVUbh7qV2NV1sdQbsKnc4mYK8jjHsb/v/O3 +lcOFJX2V55z7FdEOi7qKKn3l5j6SNmdMGlGde16692VCdYo4Wjs2ufkYryJoJQ7L +O3AeoXVrpc2JwKj6GFKN3Bw6A3XEXTShWdHS8DAuHdbLBhHESeb/qA76qNInw/od +PXtsRNBWaS87rh7GGWrO2ULHBk0k5hLa9puXgAZVh5NcrVuujWM2spGPHGJWhvDt +ffOJAe0Kra8b1CHOC9aRUuHnapuu/mAD+XZTAt/UUNq0hdTDO1VTxL4lHpZjmWJ3 +OvmTp1HpA8FpSmzSBw6H0beVT9LXDbkSax86E2YQJPcC9IjQARoaL+7ba1XdXeSQ +k796zrq4YD1SB09qRVVar8nBSHUYAzG2gbAWgAQgOjwtC5nT1Que3kI7weG2nFZ4 +B1MfBmpEqPwMs8O5hurdYmfpBRoudivKrK5si+LB7og1IwVD2IS8mm55/Kmnugf4 +YCEiGu5s9F+njqEZBV7UPAabaFph6Iw3Jfmcg0YUZV60hY6O3EieonfwVBBKWBQp +K0SUs24Ld80B3oYWuqYI+MQlSprskRKFBfx7hp2PsQU9jAVPc8NohmfM5IJAFBwo +rCqAOsRsrRZnVoaRP89X50VuBg6ROiu/cmI5sqou3u30Pndzmlbcg8ekWj+1qrur +prva6uPc0oiCgFTMksFnhKvlHErIm+ceGvNSib+rWNomaL5cjpgnqAG6lZMP7N+p +QvH+ABchP+fJyyl/XuaOLmcXDSkIcadfjJSHACwmGRas3unfOYEyBg29oPu6PNlW +jXFJb7OzWaQfFNcCnHzvYGTvmrbg7VqBVqmVRYX3r6WNDJeaSwDJpxYNNQlTugbm +FOlD9JTeHyZ17rrqiCitbQwBVBpWOhBEIkFD+3JL1ZdGjyc3rcvbERLr/UN649vS +FcMOLiEvFjFdirq6Pe9fx/VD1GrIzXaEhvyCePSeoV6eILm7SSFTVCm+JMtiBlBi +ZjDxlUhQGuMg3IwZRqjfUR90wo3QWe5XOgM9mJa5qY/Yaa9YpFEJcd4mYnXcPLIz +eY8lqGAhROwJhGRhQoTQXucsSEhAkUBpRiE7UCN8OjezvAeFn0+6XyHeST+QZenX +ixAKJ27lFn/njvL4sDocd7ZvXpb3P5ZxCRakMnjunQQyjtUlJmPrNjs+ZlPenLuh +UA3Oj5d96dDqzgZNLxbDHKr6B+CMApBrwUDcum09PYgJ5xZ/Hrct4iSa57Gi528L +l0dcVgPHd80oIn/vyhjVYkkXNMrRhTJIgLuh0KsddZ7/8Xvxma9W8hNQ1sYwE0Yp +RqLgMRdFpTSN8hKUTfRvjzbrW4nQ2XVqAdyM6PEkdrPCBZczdGisp9oMF6woI/pA +ZKNxdUr0DG3tVBJ7z6qfdp2j+yHvhqQt+ohmk3YldPKpXfYz20ZJ52URE8vbCj2K +NZ/MVEACbg6FDgNQ1bIKD61pKL72+SjyKW1wQfIkeqMfOBI8BGclp7BL6dGRrVHN +PLg2j9gsgZ3XsiJOFtJ6Q3UABkeUrbRvAFQXPM8+keWU4VP/99dCJTvnEQTM6O8U +gz2NA4j1ZEOmB5L+hmf2gW+xgW6eeMjylj5JdeAliNaUqIhOju30vo4= -----END ENCRYPTED PRIVATE KEY----- diff --git a/Lib/test/certdata/ssl_key.pem b/Lib/test/certdata/ssl_key.pem index ee927210511dfc..1ad9e5e2b832cf 100644 --- a/Lib/test/certdata/ssl_key.pem +++ b/Lib/test/certdata/ssl_key.pem @@ -1,40 +1,40 @@ -----BEGIN PRIVATE KEY----- -MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDNdMiXWy7XUAa7 -qwM+yjGpxEbIBfTKPEhyzAW+P55b98GzYZwFvL3lUQ4qkk8pFhgHt8AQCMAorn3M -V2wNf/KfE9kurItChwGQVWq1yWEJFm7/8pk0P65C4dLHc+MaRK8r+esaODlPRuQz -hIV5vRh0tv7RoNMoajNQLzagECKU1ysXPVVekQXSpR71B4pCHJ3QxpblPWhKf5Td -ECPYxebdMYTHJl5qJykgzk4cWWfBTGxhINmjSNSPfjYxs85mHyzNkNaLTjaN21ID -eLy4xKmUR/g7xk+ZfQkK2vN9WNFV1opciOuEw1YHwrjiroB7KGolxUe06Y9igcOb -SoiNyu6u3QtloaGYK4qKY12eNw/FbRVCYMhL+Y7n6zbhIr4ynOebmr9yVcTDIPwV -uu2vNXlwcITx42TGO5COSaLBb25p0rWzni0PBFYyXoNFZHLGgXRqfzzlRBaZuyAQ -HlpGYTHYvQl4PT+rojDU21oCzwMbgBpa5gyuBlfPte/KIyrcjFUCAwEAAQKCAYAO -M1r0+TCy4Z1hhceu5JdLql0RELZTbxi71IW2GVwW87gv75hy3hGLAs/1mdC+YIBP -MkBka1JqzWq0/7rgcP5CSAMsInFqqv2s7fZ286ERGXuZFbnInnkrNsQUlJo3E9W+ -tqKtGIM/i0EVHX0DRdJlqMtSjmjh43tB+M1wAUV+n6OjEtJue5wZK+AIpBmGicdP -qZY+6IBnm8tcfzPXFRCoq7ZHdIu0jxnc4l2MQJK3DdL04KoiStOkSl8xDsI+lTtq -D3qa41LE0TY8X2jJ/w6KK3cUeK7F4DQYs+kfCKWMVPpn0/5u6TbC1F7gLvkrseph -7cIgrruNNs9iKacnR1w3U72R+hNxHsNfo4RGHFa192p/Mfc+kiBd5RNR/M9oHdeq -U6T/+KM+QyF5dDOyonY0QjwfAcEx+ZsV72nj8AerjM907I6dgHo/9YZ2S1Dt/xuG -ntD+76GDzmrOvXmmpF0DsTn+Wql7AC4uzaOjv6PVziqz03pR61RpjPDemyJEWMkC -gcEA7BkGGX3enBENs3X6BYFoeXfGO/hV7/aNpA6ykLzw657dqwy2b6bWLiIaqZdZ -u0oiY6+SpOtavkZBFTq4bTVD58FHL0n73Yvvaft507kijpYBrxyDOfTJOETv+dVG -XiY8AUSAE6GjPi0ebuYIVUxoDnMeWDuRJNvTck4byn1hJ1aVlEhwXNxt/nAjq48s -5QDuR6Z9F8lqEACRYCHSMQYFm35c7c1pPsHJnElX8a7eZ9lT7HGPXHaf/ypMkOzo -dvJNAoHBAN7GhDomff/kSgQLyzmqKqQowTZlyihnReapygwr8YpNcqKDqq6VlnfH -Jl1+qtSMSVI0csmccwJWkz1WtSjDsvY+oMdv4gUK3028vQAMQZo+Sh7OElFPFET3 -UmL+Nh73ACPgpiommsdLZQPcIqpWNT5NzO+Jm5xa+U9ToVZgQ7xjrqee5NUiMutr -r7UWAz7vDWu3x7bzYRRdUJxU18NogGbFGWJ1KM0c67GUXu2E7wBQdjVdS78UWs+4 -XBxKQkG2KQKBwQCtO+M82x122BB8iGkulvhogBjlMd8klnzxTpN5HhmMWWH+uvI1 -1G29Jer4WwRNJyU6jb4E4mgPyw7AG/jssLOlniy0Jw32TlIaKpoGXwZbJvgPW9Vx -tgnbDsIiR3o9ZMKMj42GWgike4ikCIc+xzRmvdMbHIHwUJfCfEtp9TtPGPnh9pDz -og3XLsMNg52GXnt3+VI6HOCE41XH+qj2rZt5r2tSVXEOyjQ7R5mOzSeFfXJVwDFX -v/a/zHKnuB0OAdUCgcBLrxPTEaqy2eMPdtZHM/mipbnmejRw/4zu7XYYJoG7483z -SlodT/K7pKvzDYqKBVMPm4P33K/x9mm1aBTJ0ZqmL+a9etRFtEjjByEKuB89gLX7 -uzTb7MrNF10lBopqgK3KgpLRNSZWWNXrtskMJ5eVICdkpdJ5Dyst+RKR3siEYzU9 -+yxxAFpeQsqB8gWORva/RsOR8yNjIMS3J9fZqlIdGA8ktPr0nEOyo96QQR5VdACE -5rpKI2cqtM6OSegynOkCgcAnr2Xzjef6tdcrxrQrq0DjEFTMoCAxQRa6tuF/NYHV -AK70Y4hBNX84Bvym4hmfbMUEuOCJU+QHQf/iDQrHXPhtX3X2/t8M+AlIzmwLKf2o -VwCYnZ8SqiwSaWVg+GANWLh0JuKn/ZYyR8urR79dAXFfp0UK+N39vIxNoBisBf+F -G8mca7zx3UtK2eOW8WgGHz+Y20VZy0m/nkNekd1ZTXoSGhL+iN4XsTRn1YQIn69R -kNdcwhtZZ3dpChUdf+w/LIc= +MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDwcIAYm12nmQTG +B3caFn7alDe3LSliEfNC2ZTR+5sh1eucQPbzgFM5SR4soKGElwI68Eg7g1kwqu3z +mrI/FAiQI/RrUHyBZiEtnFBPM44vY02XjUlJ9nBtgP7QjpRz6ZP0z1DrrojpYLVw +g9cR0khTqD5cg2jvTB05yL9lQNk295/rMuueC9FaAQ+Y5la0ub7Lbe8gkYPotYli +Gx5qqCQmsXeTsxCpvQD7u0vBF9/nxlwywwzKGXabcN9YQhSECCC4c+eYjqoRgvAa +F48xEnokxenzBIqZ82BRkFo+zfNR+VhJRctNiZ6Ppa1Ise1H3LjZMDfY1S89QOLY +sFXUp8L7ZMVE27Bej+Sq4wEJ3soK/k1kr0YauqJ0lCEKkUPD9OeNHmczeakjj11t +gtctsYbwgDSUYGA3w+DCKD1aSfeuR3Hj89cSsVRrRrPFFih46Tr2PpTNoK6MtPH3 +RPJKV+Db8E1V2mXmNE0MLg6ramSHsD9iZXTLhG2JO+/876k3N3kCAwEAAQKCAYAK +Ap0KqTlCd4fv2LK4NtSMNByHt00gRKAMmfNstJ12UKoxBLFjXOXaHjWv5PYkh4bz +vjo7pBHMCWnDuR6Pqr1ahuyvpRex6XcbJ4VebsaOKYO6+gphlm2C2ZqCQ1Vh6Akd +aZ40Wb1gfgK/zvVezBLvzLLf9iahw9j5pWZ2iDci5zdUuvd9Sn+qUB3+nyRf/NW5 +MXgBsp07zIcOOxPOm/Z5V+0jDJL2hiRq1pbmUKClTShcgqtfJKU//niF+6ZQAuiJ +LBPaKIdPXyxLYnkyq2IgjPU0ZwxzdP0a2k72kvImd25Daj7elhGr3++IR+nFzt6h +vqflOfmKDF3zZPyUVI3YXjxo/FrOwGbLMHuuHBgE9txH/mOl1gByrxP+Ax18i3Bf +spSLeUvtaf/w/MopyspPoJBRbAM06PUHQI2v9xq3BZL/gHe2CdJPds2WzpaaVFG4 +oJWNrE3s6CowLqUkqzB7LqJ4ReZ6xe6SpkRotdmVknlIKgDenTFeEUEEVyBiFQEC +gcEA/F1GAaBG0e9vB+AOHZ96SLlZVzObSBYq2kVwUhhGItNnyU9c3fWPIrGREKQa +lw5dsvjl58ij5uEtJoPZf5BsJ0q6xHAs/kKxfpNfZAeoKAV96Z6MVcY+6WOyGjPF +aQo+GgSrCPIciW//WXZrWI1t0M2G0vZ5CFNohnKod+cSgV03PAActlyM2H+r7dtm +MpAD3EPWeeA75saKj/x0SOzuL/wzXKR8BZ6CINZ6r61Tcbk2mDwOHPhUrHeCwjoU +nhy5AoHBAPPnP2FSXFCPXD1Z1hFInCFgm41j7LEyBTVLlnqUrRk7i18fi/WcwwLH ++XvM5DcONY/V3sh7a3tZeHN1P70tRxLE0oO51D4tP5im/oZ6L+hszSYXX7lCbJSR +tni6nU1dssW3nmswfUn01Oh+B0rBGon3RQB6x4beTAW0piVxg9Ic2HYucS1Scrqw +afiFQ5KWklnMYJKInPFzlCwMdgBCuue1dZoJstU9nLQALNNSpGXB2X0+7j9D/qkz +Caw5MfgQwQKBwQDzdCvP78XCSuBq0XvsmefG9n+4fwGDFld6v9gualpmyFjsPJKT +UYwm5PPUAOvh46sCt9hatRVg6sO6zyFoTXP4p7/rN2hAVSiTuiog/r369elVEW3C +ZYBVeKbdXipIPehRA0XYWHCtKY1Fydae07kn4M37AGkcXhKM+VmKajFQ+RMK3/TS +/A+n3+qFiM1bY9FFkW/7nRVMeSY850dq/p59TihibA91AEf6084BYg0IvatsSys2 +SV6uDpDnPE6dhYkCgcBECtAwq1RbmRLnfqdsnPAJk7Txhd3jNQwk6RhqzA1aS7U+ +7UMTWw9AOF+OPQOxpEInBUgob931RGmI9D263eXFA6mi2/Ws/tyODpBVHcM9uRSm +OsEWosQ90kSwe4ckrS4RYH9OcfGR7z5yOa55GVP5B0V1s8r0AhH9SX9MVNWsiSWO +GriyJx0gndSCY1MNkvnzGUQbvQbjiRXeD//fZL5Vo9bSCUCdopmT0bSvo49/X8v3 +19WJSsPBmh5psG8TQEECgcEA64CqZpPux35LeLQsKe0fYeNfAncqiaIoRbAvxKCi +SQf27SD8HK+sfvhvYY7bP7TMEeM7B/O2/AqBQQP0UARIGJg2AknBQT0A7//yJu+o +v4FHy2XKh+RMAx7QrdvnQ4CfrjvjQIaAcN1HrdTKWwgQZZImRf57nUCMm82ktZ2k +vYEJTXMkT8CY0DSeGtPmX5ynk7cauHTdZrkPGhZ3Hr6GAFomOammnnytv2wc+5FA +Ap+d65UgF4KjGY4rtsS+jOHn -----END PRIVATE KEY----- From 7a303fc78a6dbd1b4c01f8a2b14ddcae29f4271b Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Wed, 9 Oct 2024 20:40:50 +1000 Subject: [PATCH 072/247] Fix importlib.resources issue reference in 3.13 What's New (#125175) Previous link was to the PR that removed the mentioned importlib.resources APIs, rather than the issue that added back their improved forms. --- Doc/whatsnew/3.13.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 565f74149725d5..a2897097aaba57 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -922,12 +922,12 @@ importlib * :func:`~importlib.resources.read_text` These functions are no longer deprecated and are not scheduled for removal. - (Contributed by Petr Viktorin in :gh:`106532`.) + (Contributed by Petr Viktorin in :gh:`116608`.) * :func:`~importlib.resources.contents` remains deprecated in favor of the fully-featured :class:`~importlib.resources.abc.Traversable` API. However, there is now no plan to remove it. - (Contributed by Petr Viktorin in :gh:`106532`.) + (Contributed by Petr Viktorin in :gh:`116608`.) io From 3024b16d51bb7f74177c5a5038cc9a56fd2b26bd Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 9 Oct 2024 11:53:57 +0100 Subject: [PATCH 073/247] gh-101100: Consolidate documentation on `ModuleType` attributes (#124709) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Barry Warsaw Co-authored-by: Jelle Zijlstra --- Doc/c-api/import.rst | 26 +- Doc/c-api/module.rst | 22 +- Doc/deprecations/pending-removal-in-3.14.rst | 7 + Doc/deprecations/pending-removal-in-3.15.rst | 15 +- Doc/glossary.rst | 11 +- Doc/library/ast.rst | 2 +- Doc/library/importlib.rst | 87 +++--- Doc/library/pkgutil.rst | 3 +- Doc/library/sys.rst | 3 +- Doc/library/types.rst | 65 +---- Doc/reference/datamodel.rst | 256 +++++++++++++++--- Doc/reference/import.rst | 169 ++---------- Doc/tutorial/modules.rst | 5 +- Doc/whatsnew/2.6.rst | 8 +- Doc/whatsnew/3.0.rst | 4 +- Doc/whatsnew/3.12.rst | 13 +- Doc/whatsnew/3.2.rst | 4 +- Doc/whatsnew/3.4.rst | 3 +- Doc/whatsnew/3.5.rst | 4 +- Misc/NEWS.d/3.10.0a2.rst | 4 +- Misc/NEWS.d/3.11.0a5.rst | 4 +- Misc/NEWS.d/3.12.0a1.rst | 4 +- ...-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst | 4 +- 23 files changed, 379 insertions(+), 344 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 8108a5015be972..6e48644c8fef8b 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -136,14 +136,14 @@ Importing Modules such modules have no way to know that the module object is an unknown (and probably damaged with respect to the module author's intents) state. - The module's :attr:`__spec__` and :attr:`__loader__` will be set, if - not set already, with the appropriate values. The spec's loader will - be set to the module's ``__loader__`` (if set) and to an instance of - :class:`~importlib.machinery.SourceFileLoader` otherwise. + The module's :attr:`~module.__spec__` and :attr:`~module.__loader__` will be + set, if not set already, with the appropriate values. The spec's loader + will be set to the module's :attr:`!__loader__` (if set) and to an instance + of :class:`~importlib.machinery.SourceFileLoader` otherwise. - The module's :attr:`__file__` attribute will be set to the code object's - :attr:`~codeobject.co_filename`. If applicable, :attr:`__cached__` will also - be set. + The module's :attr:`~module.__file__` attribute will be set to the code + object's :attr:`~codeobject.co_filename`. If applicable, + :attr:`~module.__cached__` will also be set. This function will reload the module if it was already imported. See :c:func:`PyImport_ReloadModule` for the intended way to reload a module. @@ -155,29 +155,29 @@ Importing Modules :c:func:`PyImport_ExecCodeModuleWithPathnames`. .. versionchanged:: 3.12 - The setting of :attr:`__cached__` and :attr:`__loader__` is - deprecated. See :class:`~importlib.machinery.ModuleSpec` for + The setting of :attr:`~module.__cached__` and :attr:`~module.__loader__` + is deprecated. See :class:`~importlib.machinery.ModuleSpec` for alternatives. .. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname) - Like :c:func:`PyImport_ExecCodeModule`, but the :attr:`__file__` attribute of - the module object is set to *pathname* if it is non-``NULL``. + Like :c:func:`PyImport_ExecCodeModule`, but the :attr:`~module.__file__` + attribute of the module object is set to *pathname* if it is non-``NULL``. See also :c:func:`PyImport_ExecCodeModuleWithPathnames`. .. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname) - Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`__cached__` + Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`~module.__cached__` attribute of the module object is set to *cpathname* if it is non-``NULL``. Of the three functions, this is the preferred one to use. .. versionadded:: 3.3 .. versionchanged:: 3.12 - Setting :attr:`__cached__` is deprecated. See + Setting :attr:`~module.__cached__` is deprecated. See :class:`~importlib.machinery.ModuleSpec` for alternatives. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index ec61be284caad9..f82a050ab75de0 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -37,18 +37,19 @@ Module Objects single: __package__ (module attribute) single: __loader__ (module attribute) - Return a new module object with the :attr:`__name__` attribute set to *name*. - The module's :attr:`__name__`, :attr:`__doc__`, :attr:`__package__`, and - :attr:`__loader__` attributes are filled in (all but :attr:`__name__` are set - to ``None``); the caller is responsible for providing a :attr:`__file__` - attribute. + Return a new module object with :attr:`module.__name__` set to *name*. + The module's :attr:`!__name__`, :attr:`~module.__doc__`, + :attr:`~module.__package__` and :attr:`~module.__loader__` attributes are + filled in (all but :attr:`!__name__` are set to ``None``). The caller is + responsible for setting a :attr:`~module.__file__` attribute. Return ``NULL`` with an exception set on error. .. versionadded:: 3.3 .. versionchanged:: 3.4 - :attr:`__package__` and :attr:`__loader__` are set to ``None``. + :attr:`~module.__package__` and :attr:`~module.__loader__` are now set to + ``None``. .. c:function:: PyObject* PyModule_New(const char *name) @@ -77,8 +78,9 @@ Module Objects single: __name__ (module attribute) single: SystemError (built-in exception) - Return *module*'s :attr:`__name__` value. If the module does not provide one, - or if it is not a string, :exc:`SystemError` is raised and ``NULL`` is returned. + Return *module*'s :attr:`~module.__name__` value. If the module does not + provide one, or if it is not a string, :exc:`SystemError` is raised and + ``NULL`` is returned. .. versionadded:: 3.3 @@ -108,8 +110,8 @@ Module Objects single: SystemError (built-in exception) Return the name of the file from which *module* was loaded using *module*'s - :attr:`__file__` attribute. If this is not defined, or if it is not a - unicode string, raise :exc:`SystemError` and return ``NULL``; otherwise return + :attr:`~module.__file__` attribute. If this is not defined, or if it is not a + string, raise :exc:`SystemError` and return ``NULL``; otherwise return a reference to a Unicode object. .. versionadded:: 3.2 diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst index 452d6643e1d146..de30f4695059ed 100644 --- a/Doc/deprecations/pending-removal-in-3.14.rst +++ b/Doc/deprecations/pending-removal-in-3.14.rst @@ -1,6 +1,13 @@ Pending Removal in Python 3.14 ------------------------------ +* The import system: + + * Setting :attr:`~module.__loader__` on a module while + failing to set :attr:`__spec__.loader ` + is deprecated. In Python 3.14, :attr:`!__loader__` will cease to be set or + taken into consideration by the import system or the standard library. + * :mod:`argparse`: The *type*, *choices*, and *metavar* parameters of :class:`!argparse.BooleanOptionalAction` are deprecated and will be removed in 3.14. diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst index b921b4f97d524e..a55fb6bea3fdaa 100644 --- a/Doc/deprecations/pending-removal-in-3.15.rst +++ b/Doc/deprecations/pending-removal-in-3.15.rst @@ -1,6 +1,18 @@ Pending Removal in Python 3.15 ------------------------------ +* The import system: + + * Setting :attr:`~module.__cached__` on a module while + failing to set :attr:`__spec__.cached ` + is deprecated. In Python 3.15, :attr:`!__cached__` will cease to be set or + take into consideration by the import system or standard library. (:gh:`97879`) + + * Setting :attr:`~module.__package__` on a module while + failing to set :attr:`__spec__.parent ` + is deprecated. In Python 3.15, :attr:`!__package__` will cease to be set or + take into consideration by the import system or standard library. (:gh:`97879`) + * :mod:`ctypes`: * The undocumented :func:`!ctypes.SetPointerType` function @@ -17,9 +29,6 @@ Pending Removal in Python 3.15 * The :option:`!--cgi` flag to the :program:`python -m http.server` command-line interface has been deprecated since Python 3.13. -* :mod:`importlib`: ``__package__`` and ``__cached__`` will cease to be set or - taken into consideration by the import system (:gh:`97879`). - * :class:`locale`: * The :func:`~locale.getdefaultlocale` function diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 933fb0319452a6..cb7e0a2b89d037 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -461,7 +461,7 @@ Glossary ` for use with :data:`sys.meta_path`, and :term:`path entry finders ` for use with :data:`sys.path_hooks`. - See :ref:`importsystem` and :mod:`importlib` for much more detail. + See :ref:`finders-and-loaders` and :mod:`importlib` for much more detail. floor division Mathematical division that rounds down to nearest integer. The floor @@ -791,8 +791,11 @@ Glossary loader An object that loads a module. It must define a method named :meth:`load_module`. A loader is typically returned by a - :term:`finder`. See :pep:`302` for details and - :class:`importlib.abc.Loader` for an :term:`abstract base class`. + :term:`finder`. See also: + + * :ref:`finders-and-loaders` + * :class:`importlib.abc.Loader` + * :pep:`302` locale encoding On Unix, it is the encoding of the LC_CTYPE locale. It can be set with @@ -862,6 +865,8 @@ Glossary A namespace containing the import-related information used to load a module. An instance of :class:`importlib.machinery.ModuleSpec`. + See also :ref:`module-specs`. + MRO See :term:`method resolution order`. diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index a9518859b83478..3d2df035a85c21 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -902,7 +902,7 @@ Statements (indicating a "simple" target). A "simple" target consists solely of a :class:`Name` node that does not appear between parentheses; all other targets are considered complex. Only simple targets appear in - the :attr:`__annotations__` dictionary of modules and classes. + the :attr:`~object.__annotations__` dictionary of modules and classes. .. doctest:: diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 27d31f66b12495..9e088a598a6c08 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -249,7 +249,7 @@ ABC hierarchy:: An abstract method for finding a :term:`spec ` for the specified module. If this is a top-level import, *path* will be ``None``. Otherwise, this is a search for a subpackage or - module and *path* will be the value of :attr:`__path__` from the + module and *path* will be the value of :attr:`~module.__path__` from the parent package. If a spec cannot be found, ``None`` is returned. When passed in, ``target`` is a module object that the finder may use to make a more educated guess about what spec to return. @@ -355,34 +355,12 @@ ABC hierarchy:: (note that some of these attributes can change when a module is reloaded): - - :attr:`__name__` - The module's fully qualified name. - It is ``'__main__'`` for an executed module. - - - :attr:`__file__` - The location the :term:`loader` used to load the module. - For example, for modules loaded from a .py file this is the filename. - It is not set on all modules (e.g. built-in modules). - - - :attr:`__cached__` - The filename of a compiled version of the module's code. - It is not set on all modules (e.g. built-in modules). - - - :attr:`__path__` - The list of locations where the package's submodules will be found. - Most of the time this is a single directory. - The import system passes this attribute to ``__import__()`` and to finders - in the same way as :data:`sys.path` but just for the package. - It is not set on non-package modules so it can be used - as an indicator that the module is a package. - - - :attr:`__package__` - The fully qualified name of the package the module is in (or the - empty string for a top-level module). - If the module is a package then this is the same as :attr:`__name__`. - - - :attr:`__loader__` - The :term:`loader` used to load the module. + - :attr:`module.__name__` + - :attr:`module.__file__` + - :attr:`module.__cached__` *(deprecated)* + - :attr:`module.__path__` + - :attr:`module.__package__` *(deprecated)* + - :attr:`module.__loader__` *(deprecated)* When :meth:`exec_module` is available then backwards-compatible functionality is provided. @@ -418,7 +396,8 @@ ABC hierarchy:: can implement this abstract method to give direct access to the data stored. :exc:`OSError` is to be raised if the *path* cannot be found. The *path* is expected to be constructed using a module's - :attr:`__file__` attribute or an item from a package's :attr:`__path__`. + :attr:`~module.__file__` attribute or an item from a package's + :attr:`~module.__path__`. .. versionchanged:: 3.4 Raises :exc:`OSError` instead of :exc:`NotImplementedError`. @@ -505,9 +484,9 @@ ABC hierarchy:: .. abstractmethod:: get_filename(fullname) - An abstract method that is to return the value of :attr:`__file__` for - the specified module. If no path is available, :exc:`ImportError` is - raised. + An abstract method that is to return the value of + :attr:`~module.__file__` for the specified module. If no path is + available, :exc:`ImportError` is raised. If source code is available, then the method should return the path to the source file, regardless of whether a bytecode was used to load the @@ -1166,43 +1145,45 @@ find and load modules. .. class:: ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None) A specification for a module's import-system-related state. This is - typically exposed as the module's :attr:`__spec__` attribute. Many + typically exposed as the module's :attr:`~module.__spec__` attribute. Many of these attributes are also available directly on a module: for example, ``module.__spec__.origin == module.__file__``. Note, however, that while the *values* are usually equivalent, they can differ since there is - no synchronization between the two objects. For example, it is possible to update - the module's :attr:`__file__` at runtime and this will not be automatically - reflected in the module's :attr:`__spec__.origin`, and vice versa. + no synchronization between the two objects. For example, it is possible to + update the module's :attr:`~module.__file__` at runtime and this will not be + automatically reflected in the module's + :attr:`__spec__.origin `, and vice versa. .. versionadded:: 3.4 .. attribute:: name - The module's fully qualified name - (see :attr:`__name__` attributes on modules). + The module's fully qualified name (see :attr:`module.__name__`). The :term:`finder` should always set this attribute to a non-empty string. .. attribute:: loader - The :term:`loader` used to load the module - (see :attr:`__loader__` attributes on modules). + The :term:`loader` used to load the module (see :attr:`module.__loader__`). The :term:`finder` should always set this attribute. .. attribute:: origin The location the :term:`loader` should use to load the module - (see :attr:`__file__` attributes on modules). - For example, for modules loaded from a .py file this is the filename. + (see :attr:`module.__file__`). + For example, for modules loaded from a ``.py`` file this is the filename. The :term:`finder` should always set this attribute to a meaningful value for the :term:`loader` to use. In the uncommon case that there is not one (like for namespace packages), it should be set to ``None``. .. attribute:: submodule_search_locations - The list of locations where the package's submodules will be found - (see :attr:`__path__` attributes on modules). - Most of the time this is a single directory. - The :term:`finder` should set this attribute to a list, even an empty one, to indicate + A (possibly empty) :term:`sequence` of strings enumerating the locations + in which a package's submodules will be found + (see :attr:`module.__path__`). Most of the time there will only be a + single directory in this list. + + The :term:`finder` should set this attribute to a sequence, even an empty + one, to indicate to the import system that the module is a package. It should be set to ``None`` for non-package modules. It is set automatically later to a special object for namespace packages. @@ -1216,7 +1197,7 @@ find and load modules. .. attribute:: cached The filename of a compiled version of the module's code - (see :attr:`__cached__` attributes on modules). + (see :attr:`module.__cached__`). The :term:`finder` should always set this attribute but it may be ``None`` for modules that do not need compiled code stored. @@ -1224,14 +1205,14 @@ find and load modules. (Read-only) The fully qualified name of the package the module is in (or the empty string for a top-level module). - See :attr:`__package__` attributes on modules. + See :attr:`module.__package__`. If the module is a package then this is the same as :attr:`name`. .. attribute:: has_location ``True`` if the spec's :attr:`origin` refers to a loadable location, - ``False`` otherwise. This value impacts how :attr:`origin` is interpreted - and how the module's :attr:`__file__` is populated. + ``False`` otherwise. This value impacts how :attr:`!origin` is interpreted + and how the module's :attr:`~module.__file__` is populated. .. class:: AppleFrameworkLoader(name, path) @@ -1416,8 +1397,8 @@ an :term:`importer`. .. versionchanged:: 3.7 Raises :exc:`ModuleNotFoundError` instead of :exc:`AttributeError` if - **package** is in fact not a package (i.e. lacks a :attr:`__path__` - attribute). + **package** is in fact not a package (i.e. lacks a + :attr:`~module.__path__` attribute). .. function:: module_from_spec(spec) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst index f095cc84173737..4a39d53a5f1440 100644 --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -26,7 +26,8 @@ support. __path__ = extend_path(__path__, __name__) For each directory on :data:`sys.path` that has a subdirectory that matches the - package name, add the subdirectory to the package's :attr:`__path__`. This is useful + package name, add the subdirectory to the package's + :attr:`~module.__path__`. This is useful if one wants to distribute different parts of a single logical package as multiple directories. diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index b0e40a4ea06946..20a06a1ecd1a4c 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1274,7 +1274,8 @@ always available. that implement Python's default import semantics. The :meth:`~importlib.abc.MetaPathFinder.find_spec` method is called with at least the absolute name of the module being imported. If the module to be - imported is contained in a package, then the parent package's :attr:`__path__` + imported is contained in a package, then the parent package's + :attr:`~module.__path__` attribute is passed in as a second argument. The method returns a :term:`module spec`, or ``None`` if the module cannot be found. diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 84b80ec6efd59f..439e119461f798 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -260,63 +260,18 @@ Standard names are defined for the following types: The type of :term:`modules `. The constructor takes the name of the module to be created and optionally its :term:`docstring`. - .. note:: - Use :func:`importlib.util.module_from_spec` to create a new module if you - wish to set the various import-controlled attributes. - - .. attribute:: __doc__ - - The :term:`docstring` of the module. Defaults to ``None``. - - .. attribute:: __loader__ - - The :term:`loader` which loaded the module. Defaults to ``None``. - - This attribute is to match :attr:`importlib.machinery.ModuleSpec.loader` - as stored in the :attr:`__spec__` object. - - .. note:: - A future version of Python may stop setting this attribute by default. - To guard against this potential change, preferably read from the - :attr:`__spec__` attribute instead or use - ``getattr(module, "__loader__", None)`` if you explicitly need to use - this attribute. - - .. versionchanged:: 3.4 - Defaults to ``None``. Previously the attribute was optional. - - .. attribute:: __name__ - - The name of the module. Expected to match - :attr:`importlib.machinery.ModuleSpec.name`. - - .. attribute:: __package__ - - Which :term:`package` a module belongs to. If the module is top-level - (i.e. not a part of any specific package) then the attribute should be set - to ``''``, else it should be set to the name of the package (which can be - :attr:`__name__` if the module is a package itself). Defaults to ``None``. - - This attribute is to match :attr:`importlib.machinery.ModuleSpec.parent` - as stored in the :attr:`__spec__` object. - - .. note:: - A future version of Python may stop setting this attribute by default. - To guard against this potential change, preferably read from the - :attr:`__spec__` attribute instead or use - ``getattr(module, "__package__", None)`` if you explicitly need to use - this attribute. - - .. versionchanged:: 3.4 - Defaults to ``None``. Previously the attribute was optional. - - .. attribute:: __spec__ - - A record of the module's import-system-related state. Expected to be an - instance of :class:`importlib.machinery.ModuleSpec`. + .. seealso:: - .. versionadded:: 3.4 + :ref:`Documentation on module objects ` + Provides details on the special attributes that can be found on + instances of :class:`!ModuleType`. + :func:`importlib.util.module_from_spec` + Modules created using the :class:`!ModuleType` constructor are + created with many of their special attributes unset or set to default + values. :func:`!module_from_spec` provides a more robust way of + creating :class:`!ModuleType` instances which ensures the various + attributes are set appropriately. .. data:: EllipsisType diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index d059a660548c7e..f56bd5e8a7803a 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -865,6 +865,8 @@ Instances of arbitrary classes can be made callable by defining a :meth:`~object.__call__` method in their class. +.. _module-objects: + Modules ------- @@ -890,57 +892,243 @@ Attribute assignment updates the module's namespace dictionary, e.g., .. index:: single: __name__ (module attribute) - single: __doc__ (module attribute) + single: __spec__ (module attribute) + single: __package__ (module attribute) + single: __loader__ (module attribute) + single: __path__ (module attribute) single: __file__ (module attribute) + single: __cached__ (module attribute) + single: __doc__ (module attribute) single: __annotations__ (module attribute) single: __annotate__ (module attribute) pair: module; namespace -Predefined (writable) attributes: +.. _import-mod-attrs: + +Import-related attributes on module objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Module objects have the following attributes that relate to the +:ref:`import system `. When a module is created using the machinery associated +with the import system, these attributes are filled in based on the module's +:term:`spec `, before the :term:`loader` executes and loads the +module. + +To create a module dynamically rather than using the import system, +it's recommended to use :func:`importlib.util.module_from_spec`, +which will set the various import-controlled attributes to appropriate values. +It's also possible to use the :class:`types.ModuleType` constructor to create +modules directly, but this technique is more error-prone, as most attributes +must be manually set on the module object after it has been created when using +this approach. + +.. caution:: + + With the exception of :attr:`~module.__name__`, it is **strongly** + recommended that you rely on :attr:`~module.__spec__` and its attributes + instead of any of the other individual attributes listed in this subsection. + Note that updating an attribute on :attr:`!__spec__` will not update the + corresponding attribute on the module itself: + + .. doctest:: + + >>> import typing + >>> typing.__name__, typing.__spec__.name + ('typing', 'typing') + >>> typing.__spec__.name = 'spelling' + >>> typing.__name__, typing.__spec__.name + ('typing', 'spelling') + >>> typing.__name__ = 'keyboard_smashing' + >>> typing.__name__, typing.__spec__.name + ('keyboard_smashing', 'spelling') + +.. attribute:: module.__name__ - :attr:`__name__` - The module's name. + The name used to uniquely identify the module in the import system. + For a directly executed module, this will be set to ``"__main__"``. - :attr:`__doc__` - The module's documentation string, or ``None`` if - unavailable. + This attribute must be set to the fully qualified name of the module. + It is expected to match the value of + :attr:`module.__spec__.name `. - :attr:`__file__` - The pathname of the file from which the - module was loaded, if it was loaded from a file. - The :attr:`__file__` - attribute may be missing for certain types of modules, such as C modules - that are statically linked into the interpreter. For extension modules - loaded dynamically from a shared library, it's the pathname of the shared - library file. +.. attribute:: module.__spec__ - :attr:`~object.__annotations__` - A dictionary containing - :term:`variable annotations ` collected during - module body execution. For best practices on working - with :attr:`!__annotations__`, see :mod:`annotationlib`. + A record of the module's import-system-related state. + + Set to the :class:`module spec ` that was + used when importing the module. See :ref:`module-specs` for more details. + + .. versionadded:: 3.4 + +.. attribute:: module.__package__ + + The :term:`package` a module belongs to. + + If the module is top-level (that is, not a part of any specific package) + then the attribute should be set to ``''`` (the empty string). Otherwise, + it should be set to the name of the module's package (which can be equal to + :attr:`module.__name__` if the module itself is a package). See :pep:`366` + for further details. + + This attribute is used instead of :attr:`~module.__name__` to calculate + explicit relative imports for main modules. It defaults to ``None`` for + modules created dynamically using the :class:`types.ModuleType` constructor; + use :func:`importlib.util.module_from_spec` instead to ensure the attribute + is set to a :class:`str`. + + It is **strongly** recommended that you use + :attr:`module.__spec__.parent ` + instead of :attr:`!module.__package__`. :attr:`__package__` is now only used + as a fallback if :attr:`!__spec__.parent` is not set, and this fallback + path is deprecated. + + .. versionchanged:: 3.4 + This attribute now defaults to ``None`` for modules created dynamically + using the :class:`types.ModuleType` constructor. + Previously the attribute was optional. + + .. versionchanged:: 3.6 + The value of :attr:`!__package__` is expected to be the same as + :attr:`__spec__.parent `. + :attr:`__package__` is now only used as a fallback during import + resolution if :attr:`!__spec__.parent` is not defined. + + .. versionchanged:: 3.10 + :exc:`ImportWarning` is raised if an import resolution falls back to + :attr:`!__package__` instead of + :attr:`__spec__.parent `. + + .. versionchanged:: 3.12 + Raise :exc:`DeprecationWarning` instead of :exc:`ImportWarning` when + falling back to :attr:`!__package__` during import resolution. - .. versionchanged:: 3.14 - Annotations are now :ref:`lazily evaluated `. - See :pep:`649`. + .. deprecated-removed:: 3.13 3.15 + :attr:`!__package__` will cease to be set or taken into consideration + by the import system or standard library. - :attr:`~object.__annotate__` - The :term:`annotate function` for this module, or ``None`` - if the module has no annotations. See :attr:`object.__annotate__`. +.. attribute:: module.__loader__ - .. versionadded:: 3.14 + The :term:`loader` object that the import machinery used to load the module. + + This attribute is mostly useful for introspection, but can be used for + additional loader-specific functionality, for example getting data + associated with a loader. + + :attr:`!__loader__` defaults to ``None`` for modules created dynamically + using the :class:`types.ModuleType` constructor; + use :func:`importlib.util.module_from_spec` instead to ensure the attribute + is set to a :term:`loader` object. + + It is **strongly** recommended that you use + :attr:`module.__spec__.loader ` + instead of :attr:`!module.__loader__`. + + .. versionchanged:: 3.4 + This attribute now defaults to ``None`` for modules created dynamically + using the :class:`types.ModuleType` constructor. + Previously the attribute was optional. + + .. deprecated-removed:: 3.12 3.14 + Setting :attr:`!__loader__` on a module while failing to set + :attr:`!__spec__.loader` is deprecated. In Python 3.14, + :attr:`!__loader__` will cease to be set or taken into consideration by + the import system or the standard library. + +.. attribute:: module.__path__ + + A (possibly empty) :term:`sequence` of strings enumerating the locations + where the package's submodules will be found. Non-package modules should + not have a :attr:`!__path__` attribute. See :ref:`package-path-rules` for + more details. + + It is **strongly** recommended that you use + :attr:`module.__spec__.submodule_search_locations ` + instead of :attr:`!module.__path__`. + +.. attribute:: module.__file__ +.. attribute:: module.__cached__ + + :attr:`!__file__` and :attr:`!__cached__` are both optional attributes that + may or may not be set. Both attributes should be a :class:`str` when they + are available. + + :attr:`!__file__` indicates the pathname of the file from which the module + was loaded (if loaded from a file), or the pathname of the shared library + file for extension modules loaded dynamically from a shared library. + It might be missing for certain types of modules, such as C modules that are + statically linked into the interpreter, and the + :ref:`import system ` may opt to leave it unset if it + has no semantic meaning (for example, a module loaded from a database). + + If :attr:`!__file__` is set then the :attr:`!__cached__` attribute might + also be set, which is the path to any compiled version of + the code (for example, a byte-compiled file). The file does not need to exist + to set this attribute; the path can simply point to where the + compiled file *would* exist (see :pep:`3147`). + + Note that :attr:`!__cached__` may be set even if :attr:`!__file__` is not + set. However, that scenario is quite atypical. Ultimately, the + :term:`loader` is what makes use of the module spec provided by the + :term:`finder` (from which :attr:`!__file__` and :attr:`!__cached__` are + derived). So if a loader can load from a cached module but otherwise does + not load from a file, that atypical scenario may be appropriate. + + It is **strongly** recommended that you use + :attr:`module.__spec__.cached ` + instead of :attr:`!module.__cached__`. + + .. deprecated-removed:: 3.13 3.15 + Setting :attr:`!__cached__` on a module while failing to set + :attr:`!__spec__.cached` is deprecated. In Python 3.15, + :attr:`!__cached__` will cease to be set or taken into consideration by + the import system or standard library. + +Other writable attributes on module objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As well as the import-related attributes listed above, module objects also have +the following writable attributes: + +.. attribute:: module.__doc__ + + The module's documentation string, or ``None`` if unavailable. + See also: :attr:`__doc__ attributes `. + +.. attribute:: module.__annotations__ + + A dictionary containing :term:`variable annotations ` + collected during module body execution. For best practices on working with + :attr:`!__annotations__`, see :mod:`annotationlib`. + + .. versionchanged:: 3.14 + Annotations are now :ref:`lazily evaluated `. + See :pep:`649`. + +.. attribute:: module.__annotate__ + + The :term:`annotate function` for this module, or ``None`` if the module has + no annotations. See also: :attr:`~object.__annotate__` attributes. + + .. versionadded:: 3.14 + +Module dictionaries +^^^^^^^^^^^^^^^^^^^ + +Module objects also have the following special read-only attribute: .. index:: single: __dict__ (module attribute) +.. attribute:: module.__dict__ -Special read-only attribute: :attr:`~object.__dict__` is the module's -namespace as a dictionary object. + The module's namespace as a dictionary object. Uniquely among the attributes + listed here, :attr:`!__dict__` cannot be accessed as a global variable from + within a module; it can only be accessed as an attribute on module objects. -.. impl-detail:: + .. impl-detail:: - Because of the way CPython clears module dictionaries, the module - dictionary will be cleared when the module falls out of scope even if the - dictionary still has live references. To avoid this, copy the dictionary - or keep the module around while using its dictionary directly. + Because of the way CPython clears module dictionaries, the module + dictionary will be cleared when the module falls out of scope even if the + dictionary still has live references. To avoid this, copy the dictionary + or keep the module around while using its dictionary directly. .. _class-attrs-and-methods: diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 0b9d1c233d182a..ac363e8cfa00dc 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -513,8 +513,10 @@ holding is that if you have ``sys.modules['spam']`` and ``sys.modules['spam.foo']`` (as you would after the above import), the latter must appear as the ``foo`` attribute of the former. -Module spec ------------ +.. _module-specs: + +Module specs +------------ The import machinery uses a variety of information about each module during import, especially before loading. Most of the information is @@ -527,163 +529,44 @@ and the loader that executes it. Most importantly, it allows the import machinery to perform the boilerplate operations of loading, whereas without a module spec the loader had that responsibility. -The module's spec is exposed as the ``__spec__`` attribute on a module object. +The module's spec is exposed as :attr:`module.__spec__`. Setting +:attr:`!__spec__` appropriately applies equally to +:ref:`modules initialized during interpreter startup `. +The one exception is ``__main__``, where :attr:`!__spec__` is +:ref:`set to None in some cases `. + See :class:`~importlib.machinery.ModuleSpec` for details on the contents of the module spec. .. versionadded:: 3.4 -.. _import-mod-attrs: - -Import-related module attributes --------------------------------- - -The import machinery fills in these attributes on each module object -during loading, based on the module's spec, before the loader executes -the module. - -It is **strongly** recommended that you rely on :attr:`__spec__` and -its attributes instead of any of the other individual attributes -listed below, except :attr:`__name__`. - -.. attribute:: __name__ - - The ``__name__`` attribute must be set to the fully qualified name of - the module. This name is used to uniquely identify the module in - the import system. - -.. attribute:: __loader__ - - The ``__loader__`` attribute must be set to the loader object that - the import machinery used when loading the module. This is mostly - for introspection, but can be used for additional loader-specific - functionality, for example getting data associated with a loader. - - It is **strongly** recommended that you rely on :attr:`__spec__` - instead of this attribute. - - .. versionchanged:: 3.12 - The value of ``__loader__`` is expected to be the same as - ``__spec__.loader``. The use of ``__loader__`` is deprecated and slated - for removal in Python 3.14. - -.. attribute:: __package__ - - The module's ``__package__`` attribute may be set. Its value must - be a string, but it can be the same value as its ``__name__``. When - the module is a package, its ``__package__`` value should be set to - its ``__name__``. When the module is not a package, ``__package__`` - should be set to the empty string for top-level modules, or for - submodules, to the parent package's name. See :pep:`366` for further - details. - - This attribute is used instead of ``__name__`` to calculate explicit - relative imports for main modules, as defined in :pep:`366`. - - It is **strongly** recommended that you rely on :attr:`__spec__` - instead of this attribute. - - .. versionchanged:: 3.6 - The value of ``__package__`` is expected to be the same as - ``__spec__.parent``. - - .. versionchanged:: 3.10 - :exc:`ImportWarning` is raised if import falls back to - ``__package__`` instead of - :attr:`~importlib.machinery.ModuleSpec.parent`. - - .. versionchanged:: 3.12 - Raise :exc:`DeprecationWarning` instead of :exc:`ImportWarning` - when falling back to ``__package__``. - - .. deprecated-removed:: 3.13 3.15 - ``__package__`` will cease to be set or taken into consideration - by the import system or standard library. - - -.. attribute:: __spec__ - - The ``__spec__`` attribute must be set to the module spec that was - used when importing the module. Setting ``__spec__`` - appropriately applies equally to :ref:`modules initialized during - interpreter startup `. The one exception is ``__main__``, - where ``__spec__`` is :ref:`set to None in some cases `. - - When ``__spec__.parent`` is not set, ``__package__`` is used as - a fallback. - - .. versionadded:: 3.4 - - .. versionchanged:: 3.6 - ``__spec__.parent`` is used as a fallback when ``__package__`` is - not defined. - -.. attribute:: __path__ - - If the module is a package (either regular or namespace), the module - object's ``__path__`` attribute must be set. The value must be - iterable, but may be empty if ``__path__`` has no further significance. - If ``__path__`` is not empty, it must produce strings when iterated - over. More details on the semantics of ``__path__`` are given - :ref:`below `. - - Non-package modules should not have a ``__path__`` attribute. - -.. attribute:: __file__ -.. attribute:: __cached__ - - ``__file__`` is optional (if set, value must be a string). It indicates - the pathname of the file from which the module was loaded (if - loaded from a file), or the pathname of the shared library file - for extension modules loaded dynamically from a shared library. - It might be missing for certain types of modules, such as C - modules that are statically linked into the interpreter, and the - import system may opt to leave it unset if it has no semantic - meaning (e.g. a module loaded from a database). - - If ``__file__`` is set then the ``__cached__`` attribute might also - be set, which is the path to any compiled version of - the code (e.g. byte-compiled file). The file does not need to exist - to set this attribute; the path can simply point to where the - compiled file would exist (see :pep:`3147`). - - Note that ``__cached__`` may be set even if ``__file__`` is not - set. However, that scenario is quite atypical. Ultimately, the - loader is what makes use of the module spec provided by the finder - (from which ``__file__`` and ``__cached__`` are derived). So - if a loader can load from a cached module but otherwise does not load - from a file, that atypical scenario may be appropriate. - - It is **strongly** recommended that you rely on :attr:`__spec__` - instead of ``__cached__``. - - .. deprecated-removed:: 3.13 3.15 - ``__cached__`` will cease to be set or taken into consideration - by the import system or standard library. - .. _package-path-rules: -module.__path__ ---------------- +__path__ attributes on modules +------------------------------ -By definition, if a module has a ``__path__`` attribute, it is a package. +The :attr:`~module.__path__` attribute should be a (possibly empty) +:term:`sequence` of strings enumerating the locations where the package's +submodules will be found. By definition, if a module has a :attr:`!__path__` +attribute, it is a :term:`package`. -A package's ``__path__`` attribute is used during imports of its subpackages. +A package's :attr:`~module.__path__` attribute is used during imports of its +subpackages. Within the import machinery, it functions much the same as :data:`sys.path`, i.e. providing a list of locations to search for modules during import. -However, ``__path__`` is typically much more constrained than -:data:`sys.path`. +However, :attr:`!__path__` is typically much more constrained than +:data:`!sys.path`. -``__path__`` must be an iterable of strings, but it may be empty. The same rules used for :data:`sys.path` also apply to a package's -``__path__``, and :data:`sys.path_hooks` (described below) are -consulted when traversing a package's ``__path__``. +:attr:`!__path__`. :data:`sys.path_hooks` (described below) are +consulted when traversing a package's :attr:`!__path__`. -A package's ``__init__.py`` file may set or alter the package's ``__path__`` +A package's ``__init__.py`` file may set or alter the package's +:attr:`~module.__path__` attribute, and this was typically the way namespace packages were implemented prior to :pep:`420`. With the adoption of :pep:`420`, namespace packages no -longer need to supply ``__init__.py`` files containing only ``__path__`` -manipulation code; the import machinery automatically sets ``__path__`` +longer need to supply ``__init__.py`` files containing only :attr:`!__path__` +manipulation code; the import machinery automatically sets :attr:`!__path__` correctly for the namespace package. Module reprs diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index 0316239e776a95..de7aa0e2342946 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -585,8 +585,9 @@ as the main module of a Python application must always use absolute imports. Packages in Multiple Directories -------------------------------- -Packages support one more special attribute, :attr:`__path__`. This is -initialized to be a list containing the name of the directory holding the +Packages support one more special attribute, :attr:`~module.__path__`. This is +initialized to be a :term:`sequence` of strings containing the name of the +directory holding the package's :file:`__init__.py` before the code in that file is executed. This variable can be modified; doing so affects future searches for modules and subpackages contained in the package. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 3c9c2049b89ea0..fdccfb7deb1ed7 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -502,12 +502,12 @@ Python's :option:`-m` switch allows running a module as a script. When you ran a module that was located inside a package, relative imports didn't work correctly. -The fix for Python 2.6 adds a :attr:`__package__` attribute to -modules. When this attribute is present, relative imports will be +The fix for Python 2.6 adds a :attr:`module.__package__` attribute. +When this attribute is present, relative imports will be relative to the value of this attribute instead of the -:attr:`__name__` attribute. +:attr:`~module.__name__` attribute. -PEP 302-style importers can then set :attr:`__package__` as necessary. +PEP 302-style importers can then set :attr:`~module.__package__` as necessary. The :mod:`runpy` module that implements the :option:`-m` switch now does this, so relative imports will now work correctly in scripts running from inside a package. diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index 888e6279754fc2..d97f5fdd9eaa4a 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -357,8 +357,8 @@ New Syntax provides a standardized way of annotating a function's parameters and return value. There are no semantics attached to such annotations except that they can be introspected at runtime using - the :attr:`__annotations__` attribute. The intent is to encourage - experimentation through metaclasses, decorators or frameworks. + the :attr:`~object.__annotations__` attribute. The intent is to + encourage experimentation through metaclasses, decorators or frameworks. * :pep:`3102`: Keyword-only arguments. Named parameters occurring after ``*args`` in the parameter list *must* be specified using diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index fb8809feda4ec7..463fc269ee8fcc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1309,14 +1309,15 @@ Deprecated may be removed in a future version of Python. Use the single-arg versions of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.) -* :exc:`DeprecationWarning` is now raised when ``__package__`` on a - module differs from ``__spec__.parent`` (previously it was - :exc:`ImportWarning`). +* :exc:`DeprecationWarning` is now raised when :attr:`~module.__package__` on a + module differs from + :attr:`__spec__.parent ` (previously + it was :exc:`ImportWarning`). (Contributed by Brett Cannon in :gh:`65961`.) -* Setting ``__package__`` or ``__cached__`` on a module is deprecated, - and will cease to be set or taken into consideration by the import system in Python 3.14. - (Contributed by Brett Cannon in :gh:`65961`.) +* Setting :attr:`~module.__package__` or :attr:`~module.__cached__` on a + module is deprecated, and will cease to be set or taken into consideration by + the import system in Python 3.14. (Contributed by Brett Cannon in :gh:`65961`.) * The bitwise inversion operator (``~``) on bool is deprecated. It will throw an error in Python 3.16. Use ``not`` for logical negation of bools instead. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index c09fa839886305..7104904c956a7a 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -312,8 +312,8 @@ cluttering source directories, the *pyc* files are now collected in a Aside from the filenames and target directories, the new scheme has a few aspects that are visible to the programmer: -* Imported modules now have a :attr:`__cached__` attribute which stores the name - of the actual file that was imported: +* Imported modules now have a :attr:`~module.__cached__` attribute which stores + the name of the actual file that was imported: >>> import collections >>> collections.__cached__ # doctest: +SKIP diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 71425120c37185..9d746b378995c3 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2271,7 +2271,8 @@ Changes in the Python API :func:`super` and falling through all the way to the ABCs. For compatibility, catch both :exc:`NotImplementedError` or the appropriate exception as needed. -* The module type now initializes the :attr:`__package__` and :attr:`__loader__` +* The module type now initializes the :attr:`~module.__package__` and + :attr:`~module.__loader__` attributes to ``None`` by default. To determine if these attributes were set in a backwards-compatible fashion, use e.g. ``getattr(module, '__loader__', None) is not None``. (:issue:`17115`.) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index d4ae6f1f45d346..3f3f634171dab6 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -423,8 +423,8 @@ are declared in the annotations:: return 'Hello ' + name While these annotations are available at runtime through the usual -:attr:`__annotations__` attribute, *no automatic type checking happens at -runtime*. Instead, it is assumed that a separate off-line type checker +:attr:`~object.__annotations__` attribute, *no automatic type checking happens +at runtime*. Instead, it is assumed that a separate off-line type checker (e.g. `mypy `_) will be used for on-demand source code analysis. diff --git a/Misc/NEWS.d/3.10.0a2.rst b/Misc/NEWS.d/3.10.0a2.rst index bd002b6ad3db9b..3e82de9ef266d6 100644 --- a/Misc/NEWS.d/3.10.0a2.rst +++ b/Misc/NEWS.d/3.10.0a2.rst @@ -226,8 +226,8 @@ thread at the time the function is called. .. section: Core and Builtins Enable ``from __future__ import annotations`` (:pep:`563`) by default. The -values found in :attr:`__annotations__` dicts are now strings, e.g. ``{"x": -"int"}`` instead of ``{"x": int}``. +values found in :attr:`~object.__annotations__` dicts are now strings, for +example ``{"x": "int"}`` instead of ``{"x": int}``. .. diff --git a/Misc/NEWS.d/3.11.0a5.rst b/Misc/NEWS.d/3.11.0a5.rst index 954f5c18b48000..5418d5d59dd583 100644 --- a/Misc/NEWS.d/3.11.0a5.rst +++ b/Misc/NEWS.d/3.11.0a5.rst @@ -486,8 +486,8 @@ Use ``dis.Positions`` in ``dis.Instruction`` instead of a regular ``tuple``. .. nonce: geS-aP .. section: Library -:mod:`pdb` now gracefully handles ``help`` when :attr:`__doc__` is missing, -for example when run with pregenerated optimized ``.pyc`` files. +:mod:`pdb` now gracefully handles ``help`` when :attr:`~module.__doc__` is +missing, for example when run with pregenerated optimized ``.pyc`` files. .. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 7e0f86179bce50..f2668e99a6299b 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -4237,8 +4237,8 @@ by :mod:`asyncio` to AIX platform only. .. nonce: 4dzB80 .. section: Library -Set :attr:`doctest.DocTest.lineno` to ``None`` when object does not have -:attr:`__doc__`. +Set :attr:`doctest.DocTest.lineno` to ``None`` when an object does not have +:attr:`~definition.__doc__`. .. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst index 1e5ad7d08eed7c..567c096472878f 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst @@ -1,3 +1,3 @@ :func:`classmethod` and :func:`staticmethod` now wrap the -:attr:`__annotations__` and :attr:`!__annotate__` attributes of their -underlying callable lazily. See :pep:`649`. Patch by Jelle Zijlstra. +:attr:`~object.__annotations__` and :attr:`~object.__annotate__` attributes of +their underlying callable lazily. See :pep:`649`. Patch by Jelle Zijlstra. From 6b533a659bc8df04daa194d827604dcae14d5801 Mon Sep 17 00:00:00 2001 From: "Tomas R." Date: Wed, 9 Oct 2024 14:54:39 +0200 Subject: [PATCH 074/247] gh-125039: Make `this_instr`/`prev_instr` const in cases generator (GH-125071) --- Lib/test/test_generated_cases.py | 6 +- ...-10-07-23-33-18.gh-issue-125039.MKTyNI.rst | 1 + Python/generated_cases.c.h | 144 +++++++++--------- Tools/cases_generator/tier1_generator.py | 6 +- 4 files changed, 79 insertions(+), 78 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 5b15838f077f3b..cd3718b80612bd 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -450,7 +450,7 @@ def test_cache_effect(self): """ output = """ TARGET(OP) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 4; INSTRUCTION_STATS(OP); @@ -503,7 +503,7 @@ def test_macro_instruction(self): next_instr += 6; INSTRUCTION_STATS(OP); PREDICTED(OP); - _Py_CODEUNIT *this_instr = next_instr - 6; + _Py_CODEUNIT* const this_instr = next_instr - 6; (void)this_instr; _PyStackRef left; _PyStackRef right; @@ -536,7 +536,7 @@ def test_macro_instruction(self): } TARGET(OP1) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(OP1); diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst new file mode 100644 index 00000000000000..93716c0b1c0df1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst @@ -0,0 +1 @@ +Make ``this_instr`` and ``prev_instr`` const in cases generator. diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e1107caa197d7a..c4de7bdeb4ce80 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -14,7 +14,7 @@ next_instr += 2; INSTRUCTION_STATS(BINARY_OP); PREDICTED(BINARY_OP); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef lhs; _PyStackRef rhs; @@ -422,7 +422,7 @@ next_instr += 2; INSTRUCTION_STATS(BINARY_SUBSCR); PREDICTED(BINARY_SUBSCR); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef container; _PyStackRef sub; @@ -858,7 +858,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL); PREDICTED(CALL); - _Py_CODEUNIT *this_instr = next_instr - 4; + _Py_CODEUNIT* const this_instr = next_instr - 4; (void)this_instr; _PyStackRef *callable; _PyStackRef *self_or_null; @@ -1012,7 +1012,7 @@ } TARGET(CALL_ALLOC_AND_ENTER_INIT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_ALLOC_AND_ENTER_INIT); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -1107,7 +1107,7 @@ } TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BOUND_METHOD_EXACT_ARGS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -1210,7 +1210,7 @@ } TARGET(CALL_BOUND_METHOD_GENERAL) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -1625,7 +1625,7 @@ next_instr += 1; INSTRUCTION_STATS(CALL_FUNCTION_EX); PREDICTED(CALL_FUNCTION_EX); - _Py_CODEUNIT *this_instr = next_instr - 1; + _Py_CODEUNIT* const this_instr = next_instr - 1; (void)this_instr; _PyStackRef func; _PyStackRef callargs; @@ -1871,7 +1871,7 @@ next_instr += 4; INSTRUCTION_STATS(CALL_KW); PREDICTED(CALL_KW); - _Py_CODEUNIT *this_instr = next_instr - 4; + _Py_CODEUNIT* const this_instr = next_instr - 4; (void)this_instr; _PyStackRef *callable; _PyStackRef *self_or_null; @@ -2024,7 +2024,7 @@ } TARGET(CALL_KW_BOUND_METHOD) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_KW_BOUND_METHOD); static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); @@ -2223,7 +2223,7 @@ } TARGET(CALL_KW_PY) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_KW_PY); static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); @@ -2795,7 +2795,7 @@ } TARGET(CALL_PY_EXACT_ARGS) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_PY_EXACT_ARGS); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -2876,7 +2876,7 @@ } TARGET(CALL_PY_GENERAL) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_PY_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -3157,7 +3157,7 @@ } TARGET(CLEANUP_THROW) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(CLEANUP_THROW); @@ -3201,7 +3201,7 @@ next_instr += 2; INSTRUCTION_STATS(COMPARE_OP); PREDICTED(COMPARE_OP); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef left; _PyStackRef right; @@ -3381,7 +3381,7 @@ next_instr += 2; INSTRUCTION_STATS(CONTAINS_OP); PREDICTED(CONTAINS_OP); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef left; _PyStackRef right; @@ -3720,7 +3720,7 @@ } TARGET(END_ASYNC_FOR) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(END_ASYNC_FOR); @@ -3781,7 +3781,7 @@ } TARGET(ENTER_EXECUTOR) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(ENTER_EXECUTOR); @@ -3896,7 +3896,7 @@ next_instr += 2; INSTRUCTION_STATS(FOR_ITER); PREDICTED(FOR_ITER); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef iter; _PyStackRef next; @@ -4357,7 +4357,7 @@ } TARGET(INSTRUMENTED_CALL) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 4; INSTRUCTION_STATS(INSTRUMENTED_CALL); @@ -4530,7 +4530,7 @@ } TARGET(INSTRUMENTED_CALL_KW) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 4; INSTRUCTION_STATS(INSTRUMENTED_CALL_KW); @@ -4554,7 +4554,7 @@ } TARGET(INSTRUMENTED_END_FOR) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_END_FOR); @@ -4579,7 +4579,7 @@ } TARGET(INSTRUMENTED_END_SEND) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_END_SEND); @@ -4606,7 +4606,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER); @@ -4647,7 +4647,7 @@ } TARGET(INSTRUMENTED_INSTRUCTION) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_INSTRUCTION); @@ -4666,7 +4666,7 @@ } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_JUMP_BACKWARD); @@ -4690,7 +4690,7 @@ } TARGET(INSTRUMENTED_JUMP_FORWARD) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_JUMP_FORWARD); @@ -4699,8 +4699,8 @@ } TARGET(INSTRUMENTED_LINE) { - _Py_CODEUNIT *prev_instr = frame->instr_ptr; - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const prev_instr = frame->instr_ptr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_LINE); @@ -4734,7 +4734,7 @@ } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); @@ -4748,7 +4748,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE); @@ -4765,7 +4765,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE); @@ -4788,7 +4788,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE); @@ -4811,7 +4811,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE); @@ -4828,7 +4828,7 @@ } TARGET(INSTRUMENTED_RESUME) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RESUME); @@ -4878,7 +4878,7 @@ } TARGET(INSTRUMENTED_RETURN_CONST) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RETURN_CONST); @@ -4931,7 +4931,7 @@ } TARGET(INSTRUMENTED_RETURN_VALUE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RETURN_VALUE); @@ -4976,7 +4976,7 @@ } TARGET(INSTRUMENTED_YIELD_VALUE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_YIELD_VALUE); @@ -5087,7 +5087,7 @@ } TARGET(JUMP_BACKWARD) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(JUMP_BACKWARD); @@ -5220,7 +5220,7 @@ next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR); PREDICTED(LOAD_ATTR); - _Py_CODEUNIT *this_instr = next_instr - 10; + _Py_CODEUNIT* const this_instr = next_instr - 10; (void)this_instr; _PyStackRef owner; _PyStackRef attr; @@ -5294,7 +5294,7 @@ } TARGET(LOAD_ATTR_CLASS) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_CLASS); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5329,7 +5329,7 @@ } TARGET(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5370,7 +5370,7 @@ } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5406,7 +5406,7 @@ } TARGET(LOAD_ATTR_INSTANCE_VALUE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_INSTANCE_VALUE); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5451,7 +5451,7 @@ } TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_METHOD_LAZY_DICT); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5494,7 +5494,7 @@ } TARGET(LOAD_ATTR_METHOD_NO_DICT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_METHOD_NO_DICT); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5530,7 +5530,7 @@ } TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_METHOD_WITH_VALUES); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5578,7 +5578,7 @@ } TARGET(LOAD_ATTR_MODULE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_MODULE); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5621,7 +5621,7 @@ } TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_NO_DICT); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5652,7 +5652,7 @@ } TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5694,7 +5694,7 @@ } TARGET(LOAD_ATTR_PROPERTY) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_PROPERTY); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5759,7 +5759,7 @@ } TARGET(LOAD_ATTR_SLOT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_SLOT); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -5796,7 +5796,7 @@ } TARGET(LOAD_ATTR_WITH_HINT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_WITH_HINT); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); @@ -6101,7 +6101,7 @@ next_instr += 5; INSTRUCTION_STATS(LOAD_GLOBAL); PREDICTED(LOAD_GLOBAL); - _Py_CODEUNIT *this_instr = next_instr - 5; + _Py_CODEUNIT* const this_instr = next_instr - 5; (void)this_instr; _PyStackRef *res; _PyStackRef null = PyStackRef_NULL; @@ -6142,7 +6142,7 @@ } TARGET(LOAD_GLOBAL_BUILTIN) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(LOAD_GLOBAL_BUILTIN); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); @@ -6185,7 +6185,7 @@ } TARGET(LOAD_GLOBAL_MODULE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(LOAD_GLOBAL_MODULE); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); @@ -6299,7 +6299,7 @@ next_instr += 2; INSTRUCTION_STATS(LOAD_SUPER_ATTR); PREDICTED(LOAD_SUPER_ATTR); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef global_super_st; _PyStackRef class_st; @@ -6654,7 +6654,7 @@ } TARGET(POP_JUMP_IF_FALSE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_FALSE); @@ -6673,7 +6673,7 @@ } TARGET(POP_JUMP_IF_NONE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NONE); @@ -6708,7 +6708,7 @@ } TARGET(POP_JUMP_IF_NOT_NONE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NOT_NONE); @@ -6743,7 +6743,7 @@ } TARGET(POP_JUMP_IF_TRUE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_TRUE); @@ -6811,7 +6811,7 @@ } TARGET(RAISE_VARARGS) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(RAISE_VARARGS); @@ -6836,7 +6836,7 @@ } TARGET(RERAISE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; (void)this_instr; next_instr += 1; INSTRUCTION_STATS(RERAISE); @@ -6886,7 +6886,7 @@ next_instr += 1; INSTRUCTION_STATS(RESUME); PREDICTED(RESUME); - _Py_CODEUNIT *this_instr = next_instr - 1; + _Py_CODEUNIT* const this_instr = next_instr - 1; (void)this_instr; // _MAYBE_INSTRUMENT { @@ -7049,7 +7049,7 @@ next_instr += 2; INSTRUCTION_STATS(SEND); PREDICTED(SEND); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef receiver; _PyStackRef v; @@ -7288,7 +7288,7 @@ next_instr += 5; INSTRUCTION_STATS(STORE_ATTR); PREDICTED(STORE_ATTR); - _Py_CODEUNIT *this_instr = next_instr - 5; + _Py_CODEUNIT* const this_instr = next_instr - 5; (void)this_instr; _PyStackRef owner; _PyStackRef v; @@ -7329,7 +7329,7 @@ } TARGET(STORE_ATTR_INSTANCE_VALUE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(STORE_ATTR_INSTANCE_VALUE); static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); @@ -7378,7 +7378,7 @@ } TARGET(STORE_ATTR_SLOT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(STORE_ATTR_SLOT); static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); @@ -7411,7 +7411,7 @@ } TARGET(STORE_ATTR_WITH_HINT) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(STORE_ATTR_WITH_HINT); static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); @@ -7625,7 +7625,7 @@ next_instr += 2; INSTRUCTION_STATS(STORE_SUBSCR); PREDICTED(STORE_SUBSCR); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef container; _PyStackRef sub; @@ -7748,7 +7748,7 @@ next_instr += 4; INSTRUCTION_STATS(TO_BOOL); PREDICTED(TO_BOOL); - _Py_CODEUNIT *this_instr = next_instr - 4; + _Py_CODEUNIT* const this_instr = next_instr - 4; (void)this_instr; _PyStackRef value; _PyStackRef res; @@ -7784,7 +7784,7 @@ } TARGET(TO_BOOL_ALWAYS_TRUE) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(TO_BOOL_ALWAYS_TRUE); static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); @@ -7984,7 +7984,7 @@ next_instr += 2; INSTRUCTION_STATS(UNPACK_SEQUENCE); PREDICTED(UNPACK_SEQUENCE); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; _PyStackRef seq; _PyStackRef *output; diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py index 1b116a578c5a86..8dadc5736c8889 100644 --- a/Tools/cases_generator/tier1_generator.py +++ b/Tools/cases_generator/tier1_generator.py @@ -150,9 +150,9 @@ def generate_tier1( out.emit(f"TARGET({name}) {{\n") unused_guard = "(void)this_instr;\n" if inst.family is None else "" if inst.properties.needs_prev: - out.emit(f"_Py_CODEUNIT *prev_instr = frame->instr_ptr;\n") + out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n") if needs_this and not inst.is_target: - out.emit(f"_Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr;\n") + out.emit(f"_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;\n") out.emit(unused_guard) else: out.emit(f"frame->instr_ptr = next_instr;\n") @@ -161,7 +161,7 @@ def generate_tier1( if inst.is_target: out.emit(f"PREDICTED({name});\n") if needs_this: - out.emit(f"_Py_CODEUNIT *this_instr = next_instr - {inst.size};\n") + out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n") out.emit(unused_guard) if inst.family is not None: out.emit( From e0835aff2e45629ee85af642190e79e4061312b5 Mon Sep 17 00:00:00 2001 From: JamesMcCarthy21 <168590015+JamesMcCarthy21@users.noreply.github.com> Date: Wed, 9 Oct 2024 09:17:18 -0400 Subject: [PATCH 075/247] gh-125168: Fix typo in `__future__.rst` (#125183) * Update `__future__.rst` Fixed typo in the sentence :pep:`649`: *Deferred evaluation of annotations using descriptors* - James McCarthy * Update `__future__.rst` Fixed sphinx formatting --- Doc/library/__future__.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/__future__.rst b/Doc/library/__future__.rst index 6a1179434acd5a..4f3b663006fb28 100644 --- a/Doc/library/__future__.rst +++ b/Doc/library/__future__.rst @@ -66,7 +66,7 @@ language using this mechanism: +------------------+-------------+--------------+---------------------------------------------+ | annotations | 3.7.0b1 | Never [1]_ | :pep:`563`: | | | | | *Postponed evaluation of annotations*, | -| | | | :pep:`649`: *Deferred evalutation of | +| | | | :pep:`649`: *Deferred evaluation of | | | | | annotations using descriptors* | +------------------+-------------+--------------+---------------------------------------------+ From a5716a30914cc11c3a4bec374cdaece3c79b541f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:02:18 +0300 Subject: [PATCH 076/247] gh-101100: Fix Sphinx warnings in `library/unittest.mock.rst` (#124106) --- Doc/library/unittest.mock.rst | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index cc2b1b4299553c..eae3ef2888eae0 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -68,7 +68,7 @@ available, and then make assertions about how they have been used: 3 >>> thing.method.assert_called_with(3, 4, 5, key='value') -:attr:`side_effect` allows you to perform side effects, including raising an +:attr:`~Mock.side_effect` allows you to perform side effects, including raising an exception when a mock is called: >>> from unittest.mock import Mock @@ -760,8 +760,8 @@ the *new_callable* argument to :func:`patch`. .. attribute:: __class__ - Normally the :attr:`__class__` attribute of an object will return its type. - For a mock object with a :attr:`spec`, ``__class__`` returns the spec class + Normally the :attr:`!__class__` attribute of an object will return its type. + For a mock object with a :attr:`!spec`, :attr:`!__class__` returns the spec class instead. This allows mock objects to pass :func:`isinstance` tests for the object they are replacing / masquerading as: @@ -769,7 +769,7 @@ the *new_callable* argument to :func:`patch`. >>> isinstance(mock, int) True - :attr:`__class__` is assignable to, this allows a mock to pass an + :attr:`!__class__` is assignable to, this allows a mock to pass an :func:`isinstance` check without forcing you to use a spec: >>> mock = Mock() @@ -783,8 +783,8 @@ the *new_callable* argument to :func:`patch`. meaning of :class:`Mock`, with the exception of *return_value* and *side_effect* which have no meaning on a non-callable mock. -Mock objects that use a class or an instance as a :attr:`spec` or -:attr:`spec_set` are able to pass :func:`isinstance` tests: +Mock objects that use a class or an instance as a :attr:`!spec` or +:attr:`!spec_set` are able to pass :func:`isinstance` tests: >>> mock = Mock(spec=SomeClass) >>> isinstance(mock, SomeClass) @@ -1198,7 +1198,7 @@ Calls made to the object will be recorded in the attributes like :attr:`~Mock.call_args` and :attr:`~Mock.call_args_list`. If :attr:`~Mock.side_effect` is set then it will be called after the call has -been recorded, so if :attr:`side_effect` raises an exception the call is still +been recorded, so if :attr:`!side_effect` raises an exception the call is still recorded. The simplest way to make a mock raise an exception when called is to make @@ -1219,8 +1219,8 @@ The simplest way to make a mock raise an exception when called is to make >>> m.mock_calls [call(1, 2, 3), call('two', 'three', 'four')] -If :attr:`side_effect` is a function then whatever that function returns is what -calls to the mock return. The :attr:`side_effect` function is called with the +If :attr:`~Mock.side_effect` is a function then whatever that function returns is what +calls to the mock return. The :attr:`!side_effect` function is called with the same arguments as the mock. This allows you to vary the return value of the call dynamically, based on the input: @@ -1237,7 +1237,7 @@ call dynamically, based on the input: If you want the mock to still return the default return value (a new mock), or any set return value, then there are two ways of doing this. Either return -:attr:`mock.return_value` from inside :attr:`side_effect`, or return :data:`DEFAULT`: +:attr:`~Mock.return_value` from inside :attr:`~Mock.side_effect`, or return :data:`DEFAULT`: >>> m = MagicMock() >>> def side_effect(*args, **kwargs): @@ -1254,8 +1254,8 @@ any set return value, then there are two ways of doing this. Either return >>> m() 3 -To remove a :attr:`side_effect`, and return to the default behaviour, set the -:attr:`side_effect` to ``None``: +To remove a :attr:`~Mock.side_effect`, and return to the default behaviour, set the +:attr:`!side_effect` to ``None``: >>> m = MagicMock(return_value=6) >>> def side_effect(*args, **kwargs): @@ -1268,7 +1268,7 @@ To remove a :attr:`side_effect`, and return to the default behaviour, set the >>> m() 6 -The :attr:`side_effect` can also be any iterable object. Repeated calls to the mock +The :attr:`~Mock.side_effect` can also be any iterable object. Repeated calls to the mock will return values from the iterable (until the iterable is exhausted and a :exc:`StopIteration` is raised): @@ -1309,7 +1309,7 @@ objects of any type. You may want a mock object to return ``False`` to a :func:`hasattr` call, or raise an :exc:`AttributeError` when an attribute is fetched. You can do this by providing -an object as a :attr:`spec` for a mock, but that isn't always convenient. +an object as a :attr:`!spec` for a mock, but that isn't always convenient. You "block" attributes by deleting them. Once deleted, accessing an attribute will raise an :exc:`AttributeError`. @@ -1478,7 +1478,7 @@ patch If you are patching builtins in a module then you don't need to pass ``create=True``, it will be added by default. - Patch can be used as a :class:`TestCase` class decorator. It works by + Patch can be used as a :class:`~unittest.TestCase` class decorator. It works by decorating each test method in the class. This reduces the boilerplate code when your test methods share a common patchings set. :func:`patch` finds tests by looking for method names that start with ``patch.TEST_PREFIX``. @@ -1516,7 +1516,7 @@ If the class is instantiated multiple times you could use can set the *return_value* to be anything you want. To configure return values on methods of *instances* on the patched class -you must do this on the :attr:`return_value`. For example:: +you must do this on the :attr:`~Mock.return_value`. For example:: >>> class Class: ... def method(self): @@ -1838,13 +1838,13 @@ context manager is a dictionary where created mocks are keyed by name:: patch methods: start and stop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -All the patchers have :meth:`start` and :meth:`stop` methods. These make it simpler to do +All the patchers have :meth:`!start` and :meth:`!stop` methods. These make it simpler to do patching in ``setUp`` methods or where you want to do multiple patches without nesting decorators or with statements. To use them call :func:`patch`, :func:`patch.object` or :func:`patch.dict` as normal and keep a reference to the returned ``patcher`` object. You can then -call :meth:`start` to put the patch in place and :meth:`stop` to undo it. +call :meth:`!start` to put the patch in place and :meth:`!stop` to undo it. If you are using :func:`patch` to create a mock for you then it will be returned by the call to ``patcher.start``. :: @@ -1861,7 +1861,7 @@ the call to ``patcher.start``. :: A typical use case for this might be for doing multiple patches in the ``setUp`` -method of a :class:`TestCase`:: +method of a :class:`~unittest.TestCase`:: >>> class MyTest(unittest.TestCase): ... def setUp(self): @@ -2534,7 +2534,7 @@ behaviour you can switch it off by setting the module level switch Alternatively you can just use ``vars(my_mock)`` (instance members) and ``dir(type(my_mock))`` (type members) to bypass the filtering irrespective of -:const:`mock.FILTER_DIR`. +:const:`FILTER_DIR`. mock_open @@ -2549,7 +2549,7 @@ mock_open default) then a :class:`MagicMock` will be created for you, with the API limited to methods or attributes available on standard file handles. - *read_data* is a string for the :meth:`~io.IOBase.read`, + *read_data* is a string for the :meth:`~io.RawIOBase.read`, :meth:`~io.IOBase.readline`, and :meth:`~io.IOBase.readlines` methods of the file handle to return. Calls to those methods will take data from *read_data* until it is depleted. The mock of these methods is pretty @@ -2561,7 +2561,7 @@ mock_open .. versionchanged:: 3.4 Added :meth:`~io.IOBase.readline` and :meth:`~io.IOBase.readlines` support. - The mock of :meth:`~io.IOBase.read` changed to consume *read_data* rather + The mock of :meth:`~io.RawIOBase.read` changed to consume *read_data* rather than returning it on each call. .. versionchanged:: 3.5 @@ -2613,7 +2613,7 @@ And for reading files:: Autospeccing ~~~~~~~~~~~~ -Autospeccing is based on the existing :attr:`spec` feature of mock. It limits the +Autospeccing is based on the existing :attr:`!spec` feature of mock. It limits the api of mocks to the api of an original object (the spec), but it is recursive (implemented lazily) so that attributes of mocks only have the same api as the attributes of the spec. In addition mocked functions / methods have the @@ -2638,8 +2638,8 @@ unit tests. Testing everything in isolation is all fine and dandy, but if you don't test how your units are "wired together" there is still lots of room for bugs that tests might have caught. -:mod:`mock` already provides a feature to help with this, called speccing. If you -use a class or instance as the :attr:`spec` for a mock then you can only access +:mod:`unittest.mock` already provides a feature to help with this, called speccing. If you +use a class or instance as the :attr:`!spec` for a mock then you can only access attributes on the mock that exist on the real class: >>> from urllib import request @@ -2677,7 +2677,7 @@ Here's an example of it in use:: >>> mock_request.Request -You can see that :class:`request.Request` has a spec. :class:`request.Request` takes two +You can see that :class:`!request.Request` has a spec. :class:`!request.Request` takes two arguments in the constructor (one of which is *self*). Here's what happens if we try to call it incorrectly:: @@ -2693,8 +2693,8 @@ specced mocks):: >>> req -:class:`Request` objects are not callable, so the return value of instantiating our -mocked out :class:`request.Request` is a non-callable mock. With the spec in place +:class:`!Request` objects are not callable, so the return value of instantiating our +mocked out :class:`!request.Request` is a non-callable mock. With the spec in place any typos in our asserts will raise the correct error:: >>> req.add_header('spam', 'eggs') @@ -2846,8 +2846,8 @@ Sealing mocks .. versionadded:: 3.7 -Order of precedence of :attr:`side_effect`, :attr:`return_value` and *wraps* ----------------------------------------------------------------------------- +Order of precedence of :attr:`!side_effect`, :attr:`!return_value` and *wraps* +------------------------------------------------------------------------------ The order of their precedence is: From 440632adb2934277599bc246b405393ac54b684c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Oct 2024 16:13:55 +0200 Subject: [PATCH 077/247] gh-111178: Fix function signatures in cellobject.c (#125182) --- Objects/cellobject.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/Objects/cellobject.c b/Objects/cellobject.c index b1154e4ca4ace6..590c8a80857699 100644 --- a/Objects/cellobject.c +++ b/Objects/cellobject.c @@ -5,6 +5,8 @@ #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_object.h" +#define _PyCell_CAST(op) _Py_CAST(PyCellObject*, (op)) + PyObject * PyCell_New(PyObject *obj) { @@ -72,8 +74,9 @@ PyCell_Set(PyObject *op, PyObject *value) } static void -cell_dealloc(PyCellObject *op) +cell_dealloc(PyObject *self) { + PyCellObject *op = _PyCell_CAST(self); _PyObject_GC_UNTRACK(op); Py_XDECREF(op->ob_ref); PyObject_GC_Del(op); @@ -100,10 +103,12 @@ cell_richcompare(PyObject *a, PyObject *b, int op) } static PyObject * -cell_repr(PyCellObject *op) +cell_repr(PyObject *self) { - if (op->ob_ref == NULL) + PyCellObject *op = _PyCell_CAST(self); + if (op->ob_ref == NULL) { return PyUnicode_FromFormat("", op); + } return PyUnicode_FromFormat("", op, Py_TYPE(op->ob_ref)->tp_name, @@ -111,24 +116,26 @@ cell_repr(PyCellObject *op) } static int -cell_traverse(PyCellObject *op, visitproc visit, void *arg) +cell_traverse(PyObject *self, visitproc visit, void *arg) { + PyCellObject *op = _PyCell_CAST(self); Py_VISIT(op->ob_ref); return 0; } static int -cell_clear(PyCellObject *op) +cell_clear(PyObject *self) { + PyCellObject *op = _PyCell_CAST(self); Py_CLEAR(op->ob_ref); return 0; } static PyObject * -cell_get_contents(PyCellObject *op, void *closure) +cell_get_contents(PyObject *self, void *closure) { - if (op->ob_ref == NULL) - { + PyCellObject *op = _PyCell_CAST(self); + if (op->ob_ref == NULL) { PyErr_SetString(PyExc_ValueError, "Cell is empty"); return NULL; } @@ -136,15 +143,15 @@ cell_get_contents(PyCellObject *op, void *closure) } static int -cell_set_contents(PyCellObject *op, PyObject *obj, void *Py_UNUSED(ignored)) +cell_set_contents(PyObject *self, PyObject *obj, void *Py_UNUSED(ignored)) { + PyCellObject *op = _PyCell_CAST(self); Py_XSETREF(op->ob_ref, Py_XNewRef(obj)); return 0; } static PyGetSetDef cell_getsetlist[] = { - {"cell_contents", (getter)cell_get_contents, - (setter)cell_set_contents, NULL}, + {"cell_contents", cell_get_contents, cell_set_contents, NULL}, {NULL} /* sentinel */ }; @@ -153,12 +160,12 @@ PyTypeObject PyCell_Type = { "cell", sizeof(PyCellObject), 0, - (destructor)cell_dealloc, /* tp_dealloc */ + cell_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)cell_repr, /* tp_repr */ + cell_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -170,8 +177,8 @@ PyTypeObject PyCell_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ cell_new_doc, /* tp_doc */ - (traverseproc)cell_traverse, /* tp_traverse */ - (inquiry)cell_clear, /* tp_clear */ + cell_traverse, /* tp_traverse */ + cell_clear, /* tp_clear */ cell_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ @@ -186,6 +193,6 @@ PyTypeObject PyCell_Type = { 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ - (newfunc)cell_new, /* tp_new */ + cell_new, /* tp_new */ 0, /* tp_free */ }; From eb18574cc3a0f99fca60b329283d1413abe6eb74 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 9 Oct 2024 15:43:09 +0100 Subject: [PATCH 078/247] GH-120024: Tidy up pycore_stackref.h, splitting into GIL and free-threading sections (GH-125095) --- Include/internal/pycore_stackref.h | 166 +++++++++++------------------ 1 file changed, 65 insertions(+), 101 deletions(-) diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index cf6dd22cfb18d1..7d1eb11aa5ecb8 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -60,54 +60,22 @@ typedef union _PyStackRef { #define Py_TAG_BITS ((uintptr_t)1) #ifdef Py_GIL_DISABLED - static const _PyStackRef PyStackRef_NULL = { .bits = 0 | Py_TAG_DEFERRED}; -#else - static const _PyStackRef PyStackRef_NULL = { .bits = 0 }; -#endif +static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED}; #define PyStackRef_IsNull(stackref) ((stackref).bits == PyStackRef_NULL.bits) +#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_DEFERRED }) +#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_DEFERRED }) +#define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_DEFERRED }) - -#ifdef Py_GIL_DISABLED -# define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_DEFERRED }) -#else -# define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) }) -#endif - -#ifdef Py_GIL_DISABLED -# define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_DEFERRED }) -#else -# define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) }) -#endif - -#ifdef Py_GIL_DISABLED -# define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_DEFERRED }) -#else -# define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) }) -#endif - -// Note: the following are all macros because MSVC (Windows) has trouble inlining them. - -#define PyStackRef_Is(a, b) ((a).bits == (b).bits) - -#define PyStackRef_IsDeferred(ref) (((ref).bits & Py_TAG_BITS) == Py_TAG_DEFERRED) - - -#ifdef Py_GIL_DISABLED -// Gets a PyObject * from a _PyStackRef static inline PyObject * PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) { PyObject *cleared = ((PyObject *)((stackref).bits & (~Py_TAG_BITS))); return cleared; } -#else -# define PyStackRef_AsPyObjectBorrow(stackref) ((PyObject *)(stackref).bits) -#endif -// Converts a PyStackRef back to a PyObject *, stealing the -// PyStackRef. -#ifdef Py_GIL_DISABLED +#define PyStackRef_IsDeferred(ref) (((ref).bits & Py_TAG_BITS) == Py_TAG_DEFERRED) + static inline PyObject * PyStackRef_AsPyObjectSteal(_PyStackRef stackref) { @@ -117,18 +85,7 @@ PyStackRef_AsPyObjectSteal(_PyStackRef stackref) } return PyStackRef_AsPyObjectBorrow(stackref); } -#else -# define PyStackRef_AsPyObjectSteal(stackref) PyStackRef_AsPyObjectBorrow(stackref) -#endif - -// Converts a PyStackRef back to a PyObject *, converting the -// stackref to a new reference. -#define PyStackRef_AsPyObjectNew(stackref) Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)) - -#define PyStackRef_TYPE(stackref) Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref)) -// Converts a PyObject * to a PyStackRef, stealing the reference -#ifdef Py_GIL_DISABLED static inline _PyStackRef _PyStackRef_FromPyObjectSteal(PyObject *obj) { @@ -139,13 +96,7 @@ _PyStackRef_FromPyObjectSteal(PyObject *obj) return ((_PyStackRef){.bits = ((uintptr_t)(obj)) | tag}); } # define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj)) -#else -# define PyStackRef_FromPyObjectSteal(obj) ((_PyStackRef){.bits = ((uintptr_t)(obj))}) -#endif - -// Converts a PyObject * to a PyStackRef, with a new reference -#ifdef Py_GIL_DISABLED static inline _PyStackRef PyStackRef_FromPyObjectNew(PyObject *obj) { @@ -159,13 +110,8 @@ PyStackRef_FromPyObjectNew(PyObject *obj) return (_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) | Py_TAG_PTR }; } } -# define PyStackRef_FromPyObjectNew(obj) PyStackRef_FromPyObjectNew(_PyObject_CAST(obj)) -#else -# define PyStackRef_FromPyObjectNew(obj) ((_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) }) -#endif +#define PyStackRef_FromPyObjectNew(obj) PyStackRef_FromPyObjectNew(_PyObject_CAST(obj)) -#ifdef Py_GIL_DISABLED -// Same as PyStackRef_FromPyObjectNew but only for immortal objects. static inline _PyStackRef PyStackRef_FromPyObjectImmortal(PyObject *obj) { @@ -175,24 +121,9 @@ PyStackRef_FromPyObjectImmortal(PyObject *obj) assert(_Py_IsImmortal(obj)); return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED }; } -# define PyStackRef_FromPyObjectImmortal(obj) PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj)) -#else -# define PyStackRef_FromPyObjectImmortal(obj) ((_PyStackRef){ .bits = (uintptr_t)(obj) }) -#endif - - -#define PyStackRef_CLEAR(op) \ - do { \ - _PyStackRef *_tmp_op_ptr = &(op); \ - _PyStackRef _tmp_old_op = (*_tmp_op_ptr); \ - if (!PyStackRef_IsNull(_tmp_old_op)) { \ - *_tmp_op_ptr = PyStackRef_NULL; \ - PyStackRef_CLOSE(_tmp_old_op); \ - } \ - } while (0) +#define PyStackRef_FromPyObjectImmortal(obj) PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj)) -#ifdef Py_GIL_DISABLED -# define PyStackRef_CLOSE(REF) \ +#define PyStackRef_CLOSE(REF) \ do { \ _PyStackRef _close_tmp = (REF); \ assert(!PyStackRef_IsNull(_close_tmp)); \ @@ -200,20 +131,7 @@ PyStackRef_FromPyObjectImmortal(PyObject *obj) Py_DECREF(PyStackRef_AsPyObjectBorrow(_close_tmp)); \ } \ } while (0) -#else -# define PyStackRef_CLOSE(stackref) Py_DECREF(PyStackRef_AsPyObjectBorrow(stackref)) -#endif -#define PyStackRef_XCLOSE(stackref) \ - do { \ - _PyStackRef _tmp = (stackref); \ - if (!PyStackRef_IsNull(_tmp)) { \ - PyStackRef_CLOSE(_tmp); \ - } \ - } while (0); - - -#ifdef Py_GIL_DISABLED static inline _PyStackRef PyStackRef_DUP(_PyStackRef stackref) { @@ -227,9 +145,6 @@ PyStackRef_DUP(_PyStackRef stackref) Py_INCREF(PyStackRef_AsPyObjectBorrow(stackref)); return stackref; } -#else -# define PyStackRef_DUP(stackref) PyStackRef_FromPyObjectSteal(Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref))) -#endif // Convert a possibly deferred reference to a strong reference. static inline _PyStackRef @@ -238,13 +153,62 @@ PyStackRef_AsStrongReference(_PyStackRef stackref) return PyStackRef_FromPyObjectSteal(PyStackRef_AsPyObjectSteal(stackref)); } -static inline void -_PyObjectStack_FromStackRefStack(PyObject **dst, const _PyStackRef *src, size_t length) -{ - for (size_t i = 0; i < length; i++) { - dst[i] = PyStackRef_AsPyObjectBorrow(src[i]); - } -} + +#else // Py_GIL_DISABLED + +// With GIL +static const _PyStackRef PyStackRef_NULL = { .bits = 0 }; +#define PyStackRef_IsNull(stackref) ((stackref).bits == 0) +#define PyStackRef_True ((_PyStackRef){.bits = (uintptr_t)&_Py_TrueStruct }) +#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) }) +#define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) }) + +#define PyStackRef_AsPyObjectBorrow(stackref) ((PyObject *)(stackref).bits) + +#define PyStackRef_AsPyObjectSteal(stackref) PyStackRef_AsPyObjectBorrow(stackref) + +#define PyStackRef_FromPyObjectSteal(obj) ((_PyStackRef){.bits = ((uintptr_t)(obj))}) + +#define PyStackRef_FromPyObjectNew(obj) ((_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) }) + +#define PyStackRef_FromPyObjectImmortal(obj) ((_PyStackRef){ .bits = (uintptr_t)(obj) }) + +#define PyStackRef_CLOSE(stackref) Py_DECREF(PyStackRef_AsPyObjectBorrow(stackref)) + +#define PyStackRef_DUP(stackref) PyStackRef_FromPyObjectSteal(Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref))) + + +#endif // Py_GIL_DISABLED + +// Note: this is a macro because MSVC (Windows) has trouble inlining it. + +#define PyStackRef_Is(a, b) ((a).bits == (b).bits) + +// Converts a PyStackRef back to a PyObject *, converting the +// stackref to a new reference. +#define PyStackRef_AsPyObjectNew(stackref) Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)) + +#define PyStackRef_TYPE(stackref) Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref)) + +#define PyStackRef_CLEAR(op) \ + do { \ + _PyStackRef *_tmp_op_ptr = &(op); \ + _PyStackRef _tmp_old_op = (*_tmp_op_ptr); \ + if (!PyStackRef_IsNull(_tmp_old_op)) { \ + *_tmp_op_ptr = PyStackRef_NULL; \ + PyStackRef_CLOSE(_tmp_old_op); \ + } \ + } while (0) + +#define PyStackRef_XCLOSE(stackref) \ + do { \ + _PyStackRef _tmp = (stackref); \ + if (!PyStackRef_IsNull(_tmp)) { \ + PyStackRef_CLOSE(_tmp); \ + } \ + } while (0); + + // StackRef type checks From 3ee474f5683110e153fdd0cbd2024f99d6c124e5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Oct 2024 17:02:24 +0200 Subject: [PATCH 079/247] gh-111178: Fix function signatures in codeobject.c (#125180) --- Objects/codeobject.c | 80 ++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 8a2f4d32b911d9..de80f6cca2904f 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1278,8 +1278,9 @@ typedef struct { static void -lineiter_dealloc(lineiterator *li) +lineiter_dealloc(PyObject *self) { + lineiterator *li = (lineiterator*)self; Py_DECREF(li->li_code); Py_TYPE(li)->tp_free(li); } @@ -1293,8 +1294,9 @@ _source_offset_converter(int *value) { } static PyObject * -lineiter_next(lineiterator *li) +lineiter_next(PyObject *self) { + lineiterator *li = (lineiterator*)self; PyCodeAddressRange *bounds = &li->li_line; if (!_PyLineTable_NextAddressRange(bounds)) { return NULL; @@ -1318,7 +1320,7 @@ PyTypeObject _PyLineIterator = { sizeof(lineiterator), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)lineiter_dealloc, /* tp_dealloc */ + lineiter_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -1340,7 +1342,7 @@ PyTypeObject _PyLineIterator = { 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ - (iternextfunc)lineiter_next, /* tp_iternext */ + lineiter_next, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ @@ -1379,15 +1381,17 @@ typedef struct { } positionsiterator; static void -positionsiter_dealloc(positionsiterator* pi) +positionsiter_dealloc(PyObject *self) { + positionsiterator *pi = (positionsiterator*)self; Py_DECREF(pi->pi_code); Py_TYPE(pi)->tp_free(pi); } static PyObject* -positionsiter_next(positionsiterator* pi) +positionsiter_next(PyObject *self) { + positionsiterator *pi = (positionsiterator*)self; if (pi->pi_offset >= pi->pi_range.ar_end) { assert(pi->pi_offset == pi->pi_range.ar_end); if (at_end(&pi->pi_range)) { @@ -1409,7 +1413,7 @@ PyTypeObject _PyPositionsIterator = { sizeof(positionsiterator), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)positionsiter_dealloc, /* tp_dealloc */ + positionsiter_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -1431,7 +1435,7 @@ PyTypeObject _PyPositionsIterator = { 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ - (iternextfunc)positionsiter_next, /* tp_iternext */ + positionsiter_next, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ @@ -1447,8 +1451,9 @@ PyTypeObject _PyPositionsIterator = { }; static PyObject* -code_positionsiterator(PyCodeObject* code, PyObject* Py_UNUSED(args)) +code_positionsiterator(PyObject *self, PyObject* Py_UNUSED(args)) { + PyCodeObject *code = (PyCodeObject*)self; positionsiterator* pi = (positionsiterator*)PyType_GenericAlloc(&_PyPositionsIterator, 0); if (pi == NULL) { return NULL; @@ -1875,16 +1880,18 @@ code_dealloc(PyCodeObject *co) #ifdef Py_GIL_DISABLED static int -code_traverse(PyCodeObject *co, visitproc visit, void *arg) +code_traverse(PyObject *self, visitproc visit, void *arg) { + PyCodeObject *co = (PyCodeObject*)self; Py_VISIT(co->co_consts); return 0; } #endif static PyObject * -code_repr(PyCodeObject *co) +code_repr(PyObject *self) { + PyCodeObject *co = (PyCodeObject*)self; int lineno; if (co->co_firstlineno != 0) lineno = co->co_firstlineno; @@ -1991,8 +1998,9 @@ code_richcompare(PyObject *self, PyObject *other, int op) } static Py_hash_t -code_hash(PyCodeObject *co) +code_hash(PyObject *self) { + PyCodeObject *co = (PyCodeObject*)self; Py_uhash_t uhash = 20221211; #define SCRAMBLE_IN(H) do { \ uhash ^= (Py_uhash_t)(H); \ @@ -2053,8 +2061,9 @@ static PyMemberDef code_memberlist[] = { static PyObject * -code_getlnotab(PyCodeObject *code, void *closure) +code_getlnotab(PyObject *self, void *closure) { + PyCodeObject *code = (PyCodeObject*)self; if (PyErr_WarnEx(PyExc_DeprecationWarning, "co_lnotab is deprecated, use co_lines instead.", 1) < 0) { @@ -2064,51 +2073,57 @@ code_getlnotab(PyCodeObject *code, void *closure) } static PyObject * -code_getvarnames(PyCodeObject *code, void *closure) +code_getvarnames(PyObject *self, void *closure) { + PyCodeObject *code = (PyCodeObject*)self; return _PyCode_GetVarnames(code); } static PyObject * -code_getcellvars(PyCodeObject *code, void *closure) +code_getcellvars(PyObject *self, void *closure) { + PyCodeObject *code = (PyCodeObject*)self; return _PyCode_GetCellvars(code); } static PyObject * -code_getfreevars(PyCodeObject *code, void *closure) +code_getfreevars(PyObject *self, void *closure) { + PyCodeObject *code = (PyCodeObject*)self; return _PyCode_GetFreevars(code); } static PyObject * -code_getcodeadaptive(PyCodeObject *code, void *closure) +code_getcodeadaptive(PyObject *self, void *closure) { + PyCodeObject *code = (PyCodeObject*)self; return PyBytes_FromStringAndSize(code->co_code_adaptive, _PyCode_NBYTES(code)); } static PyObject * -code_getcode(PyCodeObject *code, void *closure) +code_getcode(PyObject *self, void *closure) { + PyCodeObject *code = (PyCodeObject*)self; return _PyCode_GetCode(code); } static PyGetSetDef code_getsetlist[] = { - {"co_lnotab", (getter)code_getlnotab, NULL, NULL}, - {"_co_code_adaptive", (getter)code_getcodeadaptive, NULL, NULL}, + {"co_lnotab", code_getlnotab, NULL, NULL}, + {"_co_code_adaptive", code_getcodeadaptive, NULL, NULL}, // The following old names are kept for backward compatibility. - {"co_varnames", (getter)code_getvarnames, NULL, NULL}, - {"co_cellvars", (getter)code_getcellvars, NULL, NULL}, - {"co_freevars", (getter)code_getfreevars, NULL, NULL}, - {"co_code", (getter)code_getcode, NULL, NULL}, + {"co_varnames", code_getvarnames, NULL, NULL}, + {"co_cellvars", code_getcellvars, NULL, NULL}, + {"co_freevars", code_getfreevars, NULL, NULL}, + {"co_code", code_getcode, NULL, NULL}, {0} }; static PyObject * -code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args)) +code_sizeof(PyObject *self, PyObject *Py_UNUSED(args)) { + PyCodeObject *co = (PyCodeObject*)self; size_t res = _PyObject_VAR_SIZE(Py_TYPE(co), Py_SIZE(co)); _PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra; if (co_extra != NULL) { @@ -2119,8 +2134,9 @@ code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args)) } static PyObject * -code_linesiterator(PyCodeObject *code, PyObject *Py_UNUSED(args)) +code_linesiterator(PyObject *self, PyObject *Py_UNUSED(args)) { + PyCodeObject *code = (PyCodeObject*)self; return (PyObject *)new_linesiterator(code); } @@ -2262,9 +2278,9 @@ code__varname_from_oparg_impl(PyCodeObject *self, int oparg) /* XXX code objects need to participate in GC? */ static struct PyMethodDef code_methods[] = { - {"__sizeof__", (PyCFunction)code_sizeof, METH_NOARGS}, - {"co_lines", (PyCFunction)code_linesiterator, METH_NOARGS}, - {"co_positions", (PyCFunction)code_positionsiterator, METH_NOARGS}, + {"__sizeof__", code_sizeof, METH_NOARGS}, + {"co_lines", code_linesiterator, METH_NOARGS}, + {"co_positions", code_positionsiterator, METH_NOARGS}, CODE_REPLACE_METHODDEF CODE__VARNAME_FROM_OPARG_METHODDEF {"__replace__", _PyCFunction_CAST(code_replace), METH_FASTCALL|METH_KEYWORDS, @@ -2283,11 +2299,11 @@ PyTypeObject PyCode_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)code_repr, /* tp_repr */ + code_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)code_hash, /* tp_hash */ + code_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ @@ -2300,7 +2316,7 @@ PyTypeObject PyCode_Type = { #endif code_new__doc__, /* tp_doc */ #ifdef Py_GIL_DISABLED - (traverseproc)code_traverse, /* tp_traverse */ + code_traverse, /* tp_traverse */ #else 0, /* tp_traverse */ #endif From 6a39e96ab8ebc1144f713988ac6fe439e4476488 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Oct 2024 17:12:11 +0200 Subject: [PATCH 080/247] gh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_BYTES) (#125195) Replace PyBytes_FromString("") and PyBytes_FromStringAndSize("", 0) with Py_GetConstant(Py_CONSTANT_EMPTY_BYTES). --- Modules/_ctypes/_ctypes.c | 4 ++-- Modules/_io/textio.c | 2 +- Modules/mmapmodule.c | 4 ++-- Modules/zlibmodule.c | 4 ++-- Objects/bytesobject.c | 2 +- Parser/action_helpers.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 951e6914ba67a4..9453ed3250bc3b 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4732,7 +4732,7 @@ Array_subscript(PyObject *myself, PyObject *item) char *dest; if (slicelen <= 0) - return PyBytes_FromStringAndSize("", 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); if (step == 1) { return PyBytes_FromStringAndSize(ptr + start, slicelen); @@ -5418,7 +5418,7 @@ Pointer_subscript(PyObject *myself, PyObject *item) char *dest; if (len <= 0) - return PyBytes_FromStringAndSize("", 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); if (step == 1) { return PyBytes_FromStringAndSize(ptr + start, len); diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 439e26c5271939..68d16361962412 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -559,7 +559,7 @@ _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self) Py_DECREF(state); } else { - buffer = PyBytes_FromString(""); + buffer = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); flag = 0; } flag <<= 1; diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 99a85e9e49ad47..e1c26e19932664 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -486,7 +486,7 @@ mmap_read_line_method(mmap_object *self, remaining = (self->pos < self->size) ? self->size - self->pos : 0; if (!remaining) - return PyBytes_FromString(""); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); start = self->data + self->pos; if (safe_memchr(&eol, start, '\n', remaining) < 0) { @@ -1274,7 +1274,7 @@ mmap_subscript(mmap_object *self, PyObject *item) CHECK_VALID(NULL); if (slicelen <= 0) - return PyBytes_FromStringAndSize("", 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); else if (step == 1) return _safe_PyBytes_FromStringAndSize(self->data + start, slicelen); else { diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index c5aaf22eeb2948..78dcce73cdaade 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -267,12 +267,12 @@ newcompobject(PyTypeObject *type) self->eof = 0; self->is_initialised = 0; self->zdict = NULL; - self->unused_data = PyBytes_FromStringAndSize("", 0); + self->unused_data = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); if (self->unused_data == NULL) { Py_DECREF(self); return NULL; } - self->unconsumed_tail = PyBytes_FromStringAndSize("", 0); + self->unconsumed_tail = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); if (self->unconsumed_tail == NULL) { Py_DECREF(self); return NULL; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 58a4feed351707..bf58e55e100b3a 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1638,7 +1638,7 @@ bytes_subscript(PyObject *op, PyObject* item) &stop, step); if (slicelength <= 0) { - return PyBytes_FromStringAndSize("", 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } else if (start == 0 && step == 1 && slicelength == PyBytes_GET_SIZE(self) && diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 1972c606827cdb..24b817c6f8ff27 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1541,7 +1541,7 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, } if (bytes_found) { - PyObject* res = PyBytes_FromString(""); + PyObject* res = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); /* Bytes literals never get a kind, but just for consistency since they are represented as Constant nodes, we'll mirror From b9a8ca0a6aa9251cb798f34f0c9d2cc95107eec6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Oct 2024 17:15:23 +0200 Subject: [PATCH 081/247] gh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_STR) (#125194) Replace PyUnicode_New(0, 0), PyUnicode_FromString("") and PyUnicode_FromStringAndSize("", 0) with Py_GetConstant(Py_CONSTANT_EMPTY_STR). --- Doc/includes/newtypes/custom2.c | 4 ++-- Doc/includes/newtypes/custom3.c | 4 ++-- Doc/includes/newtypes/custom4.c | 4 ++-- Modules/_ctypes/_ctypes.c | 4 ++-- Modules/_datetimemodule.c | 2 +- Modules/_elementtree.c | 4 ++-- Modules/_functoolsmodule.c | 2 +- Modules/_io/stringio.c | 2 +- Modules/_testcapi/datetime.c | 2 +- Modules/cjkcodecs/multibytecodec.c | 4 ++-- Modules/socketmodule.c | 2 +- Modules/unicodedata.c | 2 +- Objects/abstract.c | 2 +- Objects/exceptions.c | 8 ++++---- Objects/stringlib/unicode_format.h | 4 ++-- Parser/pegen_errors.c | 4 ++-- Python/Python-tokenize.c | 6 +++--- Python/ceval.c | 2 +- Python/codecs.c | 2 +- Python/formatter_unicode.c | 2 +- Python/marshal.c | 2 +- Python/symtable.c | 2 +- 22 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Doc/includes/newtypes/custom2.c b/Doc/includes/newtypes/custom2.c index a0222b1795209b..768ce29fab9ff0 100644 --- a/Doc/includes/newtypes/custom2.c +++ b/Doc/includes/newtypes/custom2.c @@ -23,12 +23,12 @@ Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) CustomObject *self; self = (CustomObject *) type->tp_alloc(type, 0); if (self != NULL) { - self->first = PyUnicode_FromString(""); + self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (self->first == NULL) { Py_DECREF(self); return NULL; } - self->last = PyUnicode_FromString(""); + self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (self->last == NULL) { Py_DECREF(self); return NULL; diff --git a/Doc/includes/newtypes/custom3.c b/Doc/includes/newtypes/custom3.c index 4aeebe0a7507d1..7d969adfa7c9cc 100644 --- a/Doc/includes/newtypes/custom3.c +++ b/Doc/includes/newtypes/custom3.c @@ -23,12 +23,12 @@ Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) CustomObject *self; self = (CustomObject *) type->tp_alloc(type, 0); if (self != NULL) { - self->first = PyUnicode_FromString(""); + self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (self->first == NULL) { Py_DECREF(self); return NULL; } - self->last = PyUnicode_FromString(""); + self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (self->last == NULL) { Py_DECREF(self); return NULL; diff --git a/Doc/includes/newtypes/custom4.c b/Doc/includes/newtypes/custom4.c index 3998918f68301e..a7b8de44a57c90 100644 --- a/Doc/includes/newtypes/custom4.c +++ b/Doc/includes/newtypes/custom4.c @@ -39,12 +39,12 @@ Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) CustomObject *self; self = (CustomObject *) type->tp_alloc(type, 0); if (self != NULL) { - self->first = PyUnicode_FromString(""); + self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (self->first == NULL) { Py_DECREF(self); return NULL; } - self->last = PyUnicode_FromString(""); + self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (self->last == NULL) { Py_DECREF(self); return NULL; diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 9453ed3250bc3b..8435ee4090b9e5 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4756,7 +4756,7 @@ Array_subscript(PyObject *myself, PyObject *item) wchar_t *dest; if (slicelen <= 0) - return PyUnicode_New(0, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (step == 1) { return PyUnicode_FromWideChar(ptr + start, slicelen); @@ -5438,7 +5438,7 @@ Pointer_subscript(PyObject *myself, PyObject *item) wchar_t *dest; if (len <= 0) - return PyUnicode_New(0, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (step == 1) { return PyUnicode_FromWideChar(ptr + start, len); diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 90527d2a3e0350..2ba46cddb4f558 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -2921,7 +2921,7 @@ delta_bool(PyDateTime_Delta *self) static PyObject * delta_repr(PyDateTime_Delta *self) { - PyObject *args = PyUnicode_FromString(""); + PyObject *args = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (args == NULL) { return NULL; diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index ec999582d2fb9d..e134e096e044b7 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -196,7 +196,7 @@ list_join(PyObject* list) PyObject* joiner; PyObject* result; - joiner = PyUnicode_FromStringAndSize("", 0); + joiner = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (!joiner) return NULL; result = PyUnicode_Join(joiner, list); @@ -1317,7 +1317,7 @@ _elementtree_Element_findtext_impl(ElementObject *self, PyTypeObject *cls, PyObject* text = element_get_text((ElementObject*)item); if (text == Py_None) { Py_DECREF(item); - return PyUnicode_New(0, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } Py_XINCREF(text); Py_DECREF(item); diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 31cf7bcc09782c..4ab3adc0fe44cc 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -604,7 +604,7 @@ partial_repr(partialobject *pto) return PyUnicode_FromString("..."); } - arglist = PyUnicode_FromString(""); + arglist = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (arglist == NULL) goto done; /* Pack positional arguments */ diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 6d48bcb552b4bf..f558613dc6233c 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -353,7 +353,7 @@ _stringio_readline(stringio *self, Py_ssize_t limit) /* In case of overseek, return the empty string */ if (self->pos >= self->string_size) - return PyUnicode_New(0, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); start = self->buf + self->pos; if (limit < 0 || limit > self->string_size - self->pos) diff --git a/Modules/_testcapi/datetime.c b/Modules/_testcapi/datetime.c index f3d54215e04232..b800f9b8eb3473 100644 --- a/Modules/_testcapi/datetime.c +++ b/Modules/_testcapi/datetime.c @@ -129,7 +129,7 @@ static PyObject * get_timezones_offset_zero(PyObject *self, PyObject *args) { PyObject *offset = PyDelta_FromDSU(0, 0, 0); - PyObject *name = PyUnicode_FromString(""); + PyObject *name = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (offset == NULL || name == NULL) { Py_XDECREF(offset); Py_XDECREF(name); diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 373518673dd352..53135ae4aa7968 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -669,7 +669,7 @@ _multibytecodec_MultibyteCodec_decode_impl(MultibyteCodecObject *self, if (datalen == 0) { ERROR_DECREF(errorcb); - return make_tuple(PyUnicode_New(0, 0), 0); + return make_tuple(Py_GetConstant(Py_CONSTANT_EMPTY_STR), 0); } _PyUnicodeWriter_Init(&buf.writer); @@ -1434,7 +1434,7 @@ mbstreamreader_iread(MultibyteStreamReaderObject *self, Py_ssize_t rsize; if (sizehint == 0) - return PyUnicode_New(0, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); _PyUnicodeWriter_Init(&buf.writer); buf.excobj = NULL; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index ded6f255aaddea..0829d2358129d2 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5636,7 +5636,7 @@ socket_gethostname(PyObject *self, PyObject *unused) return PyErr_SetFromWindowsErr(0); if (size == 0) - return PyUnicode_New(0, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); /* MSDN says ERROR_MORE_DATA may occur because DNS allows longer names */ diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 333ffe68a454e4..60bde755d24574 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -413,7 +413,7 @@ unicodedata_UCD_decomposition_impl(PyObject *self, int chr) if (UCD_Check(self)) { const change_record *old = get_old_record(self, c); if (old->category_changed == 0) - return PyUnicode_FromString(""); /* unassigned */ + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); /* unassigned */ } if (code < 0 || code >= 0x110000) diff --git a/Objects/abstract.c b/Objects/abstract.c index 7cca81464cd112..f6647874d732f6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -862,7 +862,7 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) /* If no format_spec is provided, use an empty string */ if (format_spec == NULL) { - empty = PyUnicode_New(0, 0); + empty = Py_GetConstant(Py_CONSTANT_EMPTY_STR); format_spec = empty; } diff --git a/Objects/exceptions.c b/Objects/exceptions.c index c685481b13a93a..6fbe0f197eaebf 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -154,7 +154,7 @@ BaseException_str(PyBaseExceptionObject *self) { switch (PyTuple_GET_SIZE(self->args)) { case 0: - return PyUnicode_FromString(""); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); case 1: return PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); default: @@ -3001,7 +3001,7 @@ UnicodeEncodeError_str(PyObject *self) if (exc->object == NULL) { /* Not properly initialized. */ - return PyUnicode_FromString(""); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } /* Get reason and encoding as strings, which they might not be if @@ -3123,7 +3123,7 @@ UnicodeDecodeError_str(PyObject *self) if (exc->object == NULL) { /* Not properly initialized. */ - return PyUnicode_FromString(""); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } /* Get reason and encoding as strings, which they might not be if @@ -3224,7 +3224,7 @@ UnicodeTranslateError_str(PyObject *self) if (exc->object == NULL) { /* Not properly initialized. */ - return PyUnicode_FromString(""); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } /* Get reason as a string, which it might not be if it's been diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h index 91c71ab5736c25..44b269ba8ceb55 100644 --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -73,7 +73,7 @@ Py_LOCAL_INLINE(PyObject *) SubString_new_object_or_empty(SubString *str) { if (str->str == NULL) { - return PyUnicode_New(0, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } return SubString_new_object(str); } @@ -531,7 +531,7 @@ render_field(PyObject *fieldobj, SubString *format_spec, _PyUnicodeWriter *write format_spec->start, format_spec->end); else - format_spec_object = PyUnicode_New(0, 0); + format_spec_object = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (format_spec_object == NULL) goto done; diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index e94a4923228d0f..6146f69912bfa3 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -276,7 +276,7 @@ get_error_line_from_tokenizer_buffers(Parser *p, Py_ssize_t lineno) assert(p->tok->fp_interactive); // We can reach this point if the tokenizer buffers for interactive source have not been // initialized because we failed to decode the original source with the given locale. - return PyUnicode_FromStringAndSize("", 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } Py_ssize_t relative_lineno = p->starting_lineno ? lineno - p->starting_lineno + 1 : lineno; @@ -359,7 +359,7 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype, error_line = get_error_line_from_tokenizer_buffers(p, lineno); } else { - error_line = PyUnicode_FromStringAndSize("", 0); + error_line = Py_GetConstant(Py_CONSTANT_EMPTY_STR); } if (!error_line) { goto error; diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 34b4445be27f62..50ce83d18f6e73 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -263,7 +263,7 @@ tokenizeriter_next(tokenizeriterobject *it) } PyObject *str = NULL; if (token.start == NULL || token.end == NULL) { - str = PyUnicode_FromString(""); + str = Py_GetConstant(Py_CONSTANT_EMPTY_STR); } else { str = PyUnicode_FromStringAndSize(token.start, token.end - token.start); @@ -281,7 +281,7 @@ tokenizeriter_next(tokenizeriterobject *it) PyObject* line = NULL; int line_changed = 1; if (it->tok->tok_extra_tokens && is_trailing_token) { - line = PyUnicode_FromString(""); + line = Py_GetConstant(Py_CONSTANT_EMPTY_STR); } else { Py_ssize_t size = it->tok->inp - line_start; if (size >= 1 && it->tok->implicit_newline) { @@ -326,7 +326,7 @@ tokenizeriter_next(tokenizeriterobject *it) else if (type == NL) { if (it->tok->implicit_newline) { Py_DECREF(str); - str = PyUnicode_FromString(""); + str = Py_GetConstant(Py_CONSTANT_EMPTY_STR); } } diff --git a/Python/ceval.c b/Python/ceval.c index ba5c70b25f0a89..f4e0add3034707 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1287,7 +1287,7 @@ too_many_positional(PyThreadState *tstate, PyCodeObject *co, } else { /* This will not fail. */ - kwonly_sig = PyUnicode_FromString(""); + kwonly_sig = Py_GetConstant(Py_CONSTANT_EMPTY_STR); assert(kwonly_sig != NULL); } _PyErr_Format(tstate, PyExc_TypeError, diff --git a/Python/codecs.c b/Python/codecs.c index 68dc232bb86163..2cb3875db35058 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -696,7 +696,7 @@ PyObject *PyCodec_IgnoreErrors(PyObject *exc) wrong_exception_type(exc); return NULL; } - return Py_BuildValue("(Nn)", PyUnicode_New(0, 0), end); + return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end); } diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c index ebd67214f43042..16f711184990ac 100644 --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -740,7 +740,7 @@ get_locale_info(enum LocaleType type, LocaleInfo *locale_info) break; case LT_NO_LOCALE: locale_info->decimal_point = PyUnicode_FromOrdinal('.'); - locale_info->thousands_sep = PyUnicode_New(0, 0); + locale_info->thousands_sep = Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (!locale_info->decimal_point || !locale_info->thousands_sep) return -1; locale_info->grouping = no_grouping; diff --git a/Python/marshal.c b/Python/marshal.c index 3d127b4e331d0d..a280fbfd078f41 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1226,7 +1226,7 @@ r_object(RFILE *p) v = PyUnicode_DecodeUTF8(buffer, n, "surrogatepass"); } else { - v = PyUnicode_New(0, 0); + v = Py_GetConstant(Py_CONSTANT_EMPTY_STR); } if (v == NULL) break; diff --git a/Python/symtable.c b/Python/symtable.c index 8bc9db6d7d6811..52be910c0b6a9b 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -354,7 +354,7 @@ static void _dump_symtable(PySTEntryObject* ste, PyObject* prefix) static void dump_symtable(PySTEntryObject* ste) { - PyObject *empty = PyUnicode_FromString(""); + PyObject *empty = Py_GetConstant(Py_CONSTANT_EMPTY_STR); assert(empty != NULL); _dump_symtable(ste, empty); Py_DECREF(empty); From f978fb4f8d6eac0585057e463bb1701dc04a9900 Mon Sep 17 00:00:00 2001 From: mpage Date: Wed, 9 Oct 2024 08:18:25 -0700 Subject: [PATCH 082/247] gh-115999: Refactor `LOAD_GLOBAL` specializations to avoid reloading {globals, builtins} keys (gh-124953) Each of the `LOAD_GLOBAL` specializations is implemented roughly as: 1. Load keys version. 2. Load cached keys version. 3. Deopt if (1) and (2) don't match. 4. Load keys. 5. Load cached index into keys. 6. Load object from (4) at offset from (5). This is not thread-safe in free-threaded builds; the keys object may be replaced in between steps (3) and (4). This change refactors the specializations to avoid reloading the keys object and instead pass the keys object from guards to be consumed by downstream uops. --- Include/internal/pycore_opcode_metadata.h | 4 +- Include/internal/pycore_uop_ids.h | 213 +++++++++++----------- Include/internal/pycore_uop_metadata.h | 28 ++- Python/bytecodes.c | 57 ++++-- Python/executor_cases.c.h | 91 ++++++++- Python/generated_cases.c.h | 22 ++- Python/optimizer_analysis.c | 42 ++++- Python/optimizer_bytecodes.c | 10 + Python/optimizer_cases.c.h | 60 +++++- 9 files changed, 372 insertions(+), 155 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index a0d3072d2cd5f6..8fec45b1e8d5c3 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1362,8 +1362,8 @@ _PyOpcode_macro_expansion[256] = { [LOAD_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { _LOAD_FAST, 5, 0 }, { _LOAD_FAST, 6, 0 } } }, [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, [LOAD_GLOBAL] = { .nuops = 1, .uops = { { _LOAD_GLOBAL, 0, 0 } } }, - [LOAD_GLOBAL_BUILTIN] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION, 1, 2 }, { _LOAD_GLOBAL_BUILTINS, 1, 3 } } }, - [LOAD_GLOBAL_MODULE] = { .nuops = 2, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _LOAD_GLOBAL_MODULE, 1, 3 } } }, + [LOAD_GLOBAL_BUILTIN] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION_PUSH_KEYS, 1, 2 }, { _LOAD_GLOBAL_BUILTINS_FROM_KEYS, 1, 3 } } }, + [LOAD_GLOBAL_MODULE] = { .nuops = 2, .uops = { { _GUARD_GLOBALS_VERSION_PUSH_KEYS, 1, 1 }, { _LOAD_GLOBAL_MODULE_FROM_KEYS, 1, 3 } } }, [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, [LOAD_NAME] = { .nuops = 1, .uops = { { _LOAD_NAME, 0, 0 } } }, [LOAD_SPECIAL] = { .nuops = 1, .uops = { { _LOAD_SPECIAL, 0, 0 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 48bafacabcfd1d..1951c65a2871cf 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -120,32 +120,33 @@ extern "C" { #define _GUARD_BOTH_FLOAT 367 #define _GUARD_BOTH_INT 368 #define _GUARD_BOTH_UNICODE 369 -#define _GUARD_BUILTINS_VERSION 370 +#define _GUARD_BUILTINS_VERSION_PUSH_KEYS 370 #define _GUARD_DORV_NO_DICT 371 #define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 372 #define _GUARD_GLOBALS_VERSION 373 -#define _GUARD_IS_FALSE_POP 374 -#define _GUARD_IS_NONE_POP 375 -#define _GUARD_IS_NOT_NONE_POP 376 -#define _GUARD_IS_TRUE_POP 377 -#define _GUARD_KEYS_VERSION 378 -#define _GUARD_NOS_FLOAT 379 -#define _GUARD_NOS_INT 380 -#define _GUARD_NOT_EXHAUSTED_LIST 381 -#define _GUARD_NOT_EXHAUSTED_RANGE 382 -#define _GUARD_NOT_EXHAUSTED_TUPLE 383 -#define _GUARD_TOS_FLOAT 384 -#define _GUARD_TOS_INT 385 -#define _GUARD_TYPE_VERSION 386 +#define _GUARD_GLOBALS_VERSION_PUSH_KEYS 374 +#define _GUARD_IS_FALSE_POP 375 +#define _GUARD_IS_NONE_POP 376 +#define _GUARD_IS_NOT_NONE_POP 377 +#define _GUARD_IS_TRUE_POP 378 +#define _GUARD_KEYS_VERSION 379 +#define _GUARD_NOS_FLOAT 380 +#define _GUARD_NOS_INT 381 +#define _GUARD_NOT_EXHAUSTED_LIST 382 +#define _GUARD_NOT_EXHAUSTED_RANGE 383 +#define _GUARD_NOT_EXHAUSTED_TUPLE 384 +#define _GUARD_TOS_FLOAT 385 +#define _GUARD_TOS_INT 386 +#define _GUARD_TYPE_VERSION 387 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 387 -#define _INIT_CALL_PY_EXACT_ARGS 388 -#define _INIT_CALL_PY_EXACT_ARGS_0 389 -#define _INIT_CALL_PY_EXACT_ARGS_1 390 -#define _INIT_CALL_PY_EXACT_ARGS_2 391 -#define _INIT_CALL_PY_EXACT_ARGS_3 392 -#define _INIT_CALL_PY_EXACT_ARGS_4 393 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 388 +#define _INIT_CALL_PY_EXACT_ARGS 389 +#define _INIT_CALL_PY_EXACT_ARGS_0 390 +#define _INIT_CALL_PY_EXACT_ARGS_1 391 +#define _INIT_CALL_PY_EXACT_ARGS_2 392 +#define _INIT_CALL_PY_EXACT_ARGS_3 393 +#define _INIT_CALL_PY_EXACT_ARGS_4 394 #define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX #define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER @@ -157,133 +158,135 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _INTERNAL_INCREMENT_OPT_COUNTER 394 -#define _IS_NONE 395 +#define _INTERNAL_INCREMENT_OPT_COUNTER 395 +#define _IS_NONE 396 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 396 -#define _ITER_CHECK_RANGE 397 -#define _ITER_CHECK_TUPLE 398 -#define _ITER_JUMP_LIST 399 -#define _ITER_JUMP_RANGE 400 -#define _ITER_JUMP_TUPLE 401 -#define _ITER_NEXT_LIST 402 -#define _ITER_NEXT_RANGE 403 -#define _ITER_NEXT_TUPLE 404 -#define _JUMP_TO_TOP 405 +#define _ITER_CHECK_LIST 397 +#define _ITER_CHECK_RANGE 398 +#define _ITER_CHECK_TUPLE 399 +#define _ITER_JUMP_LIST 400 +#define _ITER_JUMP_RANGE 401 +#define _ITER_JUMP_TUPLE 402 +#define _ITER_NEXT_LIST 403 +#define _ITER_NEXT_RANGE 404 +#define _ITER_NEXT_TUPLE 405 +#define _JUMP_TO_TOP 406 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 406 -#define _LOAD_ATTR_CLASS 407 -#define _LOAD_ATTR_CLASS_0 408 -#define _LOAD_ATTR_CLASS_1 409 +#define _LOAD_ATTR 407 +#define _LOAD_ATTR_CLASS 408 +#define _LOAD_ATTR_CLASS_0 409 +#define _LOAD_ATTR_CLASS_1 410 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 410 -#define _LOAD_ATTR_INSTANCE_VALUE_0 411 -#define _LOAD_ATTR_INSTANCE_VALUE_1 412 -#define _LOAD_ATTR_METHOD_LAZY_DICT 413 -#define _LOAD_ATTR_METHOD_NO_DICT 414 -#define _LOAD_ATTR_METHOD_WITH_VALUES 415 -#define _LOAD_ATTR_MODULE 416 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 417 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 418 -#define _LOAD_ATTR_PROPERTY_FRAME 419 -#define _LOAD_ATTR_SLOT 420 -#define _LOAD_ATTR_SLOT_0 421 -#define _LOAD_ATTR_SLOT_1 422 -#define _LOAD_ATTR_WITH_HINT 423 +#define _LOAD_ATTR_INSTANCE_VALUE 411 +#define _LOAD_ATTR_INSTANCE_VALUE_0 412 +#define _LOAD_ATTR_INSTANCE_VALUE_1 413 +#define _LOAD_ATTR_METHOD_LAZY_DICT 414 +#define _LOAD_ATTR_METHOD_NO_DICT 415 +#define _LOAD_ATTR_METHOD_WITH_VALUES 416 +#define _LOAD_ATTR_MODULE 417 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 418 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 419 +#define _LOAD_ATTR_PROPERTY_FRAME 420 +#define _LOAD_ATTR_SLOT 421 +#define _LOAD_ATTR_SLOT_0 422 +#define _LOAD_ATTR_SLOT_1 423 +#define _LOAD_ATTR_WITH_HINT 424 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 424 -#define _LOAD_CONST_INLINE_BORROW 425 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 426 -#define _LOAD_CONST_INLINE_WITH_NULL 427 +#define _LOAD_CONST_INLINE 425 +#define _LOAD_CONST_INLINE_BORROW 426 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 427 +#define _LOAD_CONST_INLINE_WITH_NULL 428 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 428 -#define _LOAD_FAST_0 429 -#define _LOAD_FAST_1 430 -#define _LOAD_FAST_2 431 -#define _LOAD_FAST_3 432 -#define _LOAD_FAST_4 433 -#define _LOAD_FAST_5 434 -#define _LOAD_FAST_6 435 -#define _LOAD_FAST_7 436 +#define _LOAD_FAST 429 +#define _LOAD_FAST_0 430 +#define _LOAD_FAST_1 431 +#define _LOAD_FAST_2 432 +#define _LOAD_FAST_3 433 +#define _LOAD_FAST_4 434 +#define _LOAD_FAST_5 435 +#define _LOAD_FAST_6 436 +#define _LOAD_FAST_7 437 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 437 -#define _LOAD_GLOBAL_BUILTINS 438 -#define _LOAD_GLOBAL_MODULE 439 +#define _LOAD_GLOBAL 438 +#define _LOAD_GLOBAL_BUILTINS 439 +#define _LOAD_GLOBAL_BUILTINS_FROM_KEYS 440 +#define _LOAD_GLOBAL_MODULE 441 +#define _LOAD_GLOBAL_MODULE_FROM_KEYS 442 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME #define _LOAD_SPECIAL LOAD_SPECIAL #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 440 +#define _MAKE_CALLARGS_A_TUPLE 443 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 441 +#define _MAKE_WARM 444 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 442 -#define _MAYBE_EXPAND_METHOD_KW 443 -#define _MONITOR_CALL 444 -#define _MONITOR_JUMP_BACKWARD 445 -#define _MONITOR_RESUME 446 +#define _MAYBE_EXPAND_METHOD 445 +#define _MAYBE_EXPAND_METHOD_KW 446 +#define _MONITOR_CALL 447 +#define _MONITOR_JUMP_BACKWARD 448 +#define _MONITOR_RESUME 449 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_JUMP_IF_FALSE 447 -#define _POP_JUMP_IF_TRUE 448 +#define _POP_JUMP_IF_FALSE 450 +#define _POP_JUMP_IF_TRUE 451 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 449 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 452 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 450 +#define _PUSH_FRAME 453 #define _PUSH_NULL PUSH_NULL -#define _PY_FRAME_GENERAL 451 -#define _PY_FRAME_KW 452 -#define _QUICKEN_RESUME 453 -#define _REPLACE_WITH_TRUE 454 +#define _PY_FRAME_GENERAL 454 +#define _PY_FRAME_KW 455 +#define _QUICKEN_RESUME 456 +#define _REPLACE_WITH_TRUE 457 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 455 -#define _SEND 456 -#define _SEND_GEN_FRAME 457 +#define _SAVE_RETURN_OFFSET 458 +#define _SEND 459 +#define _SEND_GEN_FRAME 460 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 458 -#define _STORE_ATTR 459 -#define _STORE_ATTR_INSTANCE_VALUE 460 -#define _STORE_ATTR_SLOT 461 -#define _STORE_ATTR_WITH_HINT 462 +#define _START_EXECUTOR 461 +#define _STORE_ATTR 462 +#define _STORE_ATTR_INSTANCE_VALUE 463 +#define _STORE_ATTR_SLOT 464 +#define _STORE_ATTR_WITH_HINT 465 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 463 -#define _STORE_FAST_0 464 -#define _STORE_FAST_1 465 -#define _STORE_FAST_2 466 -#define _STORE_FAST_3 467 -#define _STORE_FAST_4 468 -#define _STORE_FAST_5 469 -#define _STORE_FAST_6 470 -#define _STORE_FAST_7 471 +#define _STORE_FAST 466 +#define _STORE_FAST_0 467 +#define _STORE_FAST_1 468 +#define _STORE_FAST_2 469 +#define _STORE_FAST_3 470 +#define _STORE_FAST_4 471 +#define _STORE_FAST_5 472 +#define _STORE_FAST_6 473 +#define _STORE_FAST_7 474 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 472 -#define _STORE_SUBSCR 473 +#define _STORE_SLICE 475 +#define _STORE_SUBSCR 476 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 474 -#define _TO_BOOL 475 +#define _TIER2_RESUME_CHECK 477 +#define _TO_BOOL 478 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT #define _TO_BOOL_LIST TO_BOOL_LIST @@ -293,13 +296,13 @@ extern "C" { #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 476 +#define _UNPACK_SEQUENCE 479 #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 476 +#define MAX_UOP_ID 479 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index c68ee594947283..fd41e9a5fe862b 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -116,9 +116,10 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_GLOBALS_VERSION] = HAS_DEOPT_FLAG, - [_GUARD_BUILTINS_VERSION] = HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_GUARD_GLOBALS_VERSION_PUSH_KEYS] = HAS_DEOPT_FLAG, + [_GUARD_BUILTINS_VERSION_PUSH_KEYS] = HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_MODULE_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_BUILTINS_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_DELETE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, [_DELETE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, @@ -273,6 +274,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG, [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG, [_CHECK_FUNCTION] = HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_INTERNAL_INCREMENT_OPT_COUNTER] = 0, [_DYNAMIC_EXIT] = HAS_ESCAPES_FLAG, [_START_EXECUTOR] = 0, @@ -397,10 +400,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GUARD_BOTH_FLOAT] = "_GUARD_BOTH_FLOAT", [_GUARD_BOTH_INT] = "_GUARD_BOTH_INT", [_GUARD_BOTH_UNICODE] = "_GUARD_BOTH_UNICODE", - [_GUARD_BUILTINS_VERSION] = "_GUARD_BUILTINS_VERSION", + [_GUARD_BUILTINS_VERSION_PUSH_KEYS] = "_GUARD_BUILTINS_VERSION_PUSH_KEYS", [_GUARD_DORV_NO_DICT] = "_GUARD_DORV_NO_DICT", [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT", [_GUARD_GLOBALS_VERSION] = "_GUARD_GLOBALS_VERSION", + [_GUARD_GLOBALS_VERSION_PUSH_KEYS] = "_GUARD_GLOBALS_VERSION_PUSH_KEYS", [_GUARD_IS_FALSE_POP] = "_GUARD_IS_FALSE_POP", [_GUARD_IS_NONE_POP] = "_GUARD_IS_NONE_POP", [_GUARD_IS_NOT_NONE_POP] = "_GUARD_IS_NOT_NONE_POP", @@ -476,7 +480,9 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_LOAD_FROM_DICT_OR_DEREF] = "_LOAD_FROM_DICT_OR_DEREF", [_LOAD_GLOBAL] = "_LOAD_GLOBAL", [_LOAD_GLOBAL_BUILTINS] = "_LOAD_GLOBAL_BUILTINS", + [_LOAD_GLOBAL_BUILTINS_FROM_KEYS] = "_LOAD_GLOBAL_BUILTINS_FROM_KEYS", [_LOAD_GLOBAL_MODULE] = "_LOAD_GLOBAL_MODULE", + [_LOAD_GLOBAL_MODULE_FROM_KEYS] = "_LOAD_GLOBAL_MODULE_FROM_KEYS", [_LOAD_LOCALS] = "_LOAD_LOCALS", [_LOAD_NAME] = "_LOAD_NAME", [_LOAD_SPECIAL] = "_LOAD_SPECIAL", @@ -752,12 +758,14 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _GUARD_GLOBALS_VERSION: return 0; - case _GUARD_BUILTINS_VERSION: + case _GUARD_GLOBALS_VERSION_PUSH_KEYS: return 0; - case _LOAD_GLOBAL_MODULE: - return 0; - case _LOAD_GLOBAL_BUILTINS: + case _GUARD_BUILTINS_VERSION_PUSH_KEYS: return 0; + case _LOAD_GLOBAL_MODULE_FROM_KEYS: + return 1; + case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: + return 1; case _DELETE_FAST: return 0; case _MAKE_CELL: @@ -1066,6 +1074,10 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _CHECK_FUNCTION: return 0; + case _LOAD_GLOBAL_MODULE: + return 0; + case _LOAD_GLOBAL_BUILTINS: + return 0; case _INTERNAL_INCREMENT_OPT_COUNTER: return 1; case _DYNAMIC_EXIT: diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 228d82173e6126..87cca3fc1d373c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1569,17 +1569,29 @@ dummy_func( assert(DK_IS_UNICODE(dict->ma_keys)); } - op(_GUARD_BUILTINS_VERSION, (version/1 --)) { + op(_GUARD_GLOBALS_VERSION_PUSH_KEYS, (version / 1 -- globals_keys: PyDictKeysObject *)) + { + PyDictObject *dict = (PyDictObject *)GLOBALS(); + DEOPT_IF(!PyDict_CheckExact(dict)); + DEOPT_IF(dict->ma_keys->dk_version != version); + globals_keys = dict->ma_keys; + assert(DK_IS_UNICODE(globals_keys)); + } + + op(_GUARD_BUILTINS_VERSION_PUSH_KEYS, (version / 1 -- builtins_keys: PyDictKeysObject *)) + { PyDictObject *dict = (PyDictObject *)BUILTINS(); DEOPT_IF(!PyDict_CheckExact(dict)); DEOPT_IF(dict->ma_keys->dk_version != version); - assert(DK_IS_UNICODE(dict->ma_keys)); + builtins_keys = dict->ma_keys; + assert(DK_IS_UNICODE(builtins_keys)); } - op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) { - PyDictObject *dict = (PyDictObject *)GLOBALS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + op(_LOAD_GLOBAL_MODULE_FROM_KEYS, (index/1, globals_keys: PyDictKeysObject* -- res, null if (oparg & 1))) { + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); PyObject *res_o = entries[index].me_value; + DEAD(globals_keys); + SYNC_SP(); DEOPT_IF(res_o == NULL); Py_INCREF(res_o); STAT_INC(LOAD_GLOBAL, hit); @@ -1587,10 +1599,11 @@ dummy_func( res = PyStackRef_FromPyObjectSteal(res_o); } - op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) { - PyDictObject *bdict = (PyDictObject *)BUILTINS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + op(_LOAD_GLOBAL_BUILTINS_FROM_KEYS, (index/1, builtins_keys: PyDictKeysObject* -- res, null if (oparg & 1))) { + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); PyObject *res_o = entries[index].me_value; + DEAD(builtins_keys); + SYNC_SP(); DEOPT_IF(res_o == NULL); Py_INCREF(res_o); STAT_INC(LOAD_GLOBAL, hit); @@ -1600,15 +1613,15 @@ dummy_func( macro(LOAD_GLOBAL_MODULE) = unused/1 + // Skip over the counter - _GUARD_GLOBALS_VERSION + + _GUARD_GLOBALS_VERSION_PUSH_KEYS + unused/1 + // Skip over the builtins version - _LOAD_GLOBAL_MODULE; + _LOAD_GLOBAL_MODULE_FROM_KEYS; macro(LOAD_GLOBAL_BUILTIN) = unused/1 + // Skip over the counter _GUARD_GLOBALS_VERSION + - _GUARD_BUILTINS_VERSION + - _LOAD_GLOBAL_BUILTINS; + _GUARD_BUILTINS_VERSION_PUSH_KEYS + + _LOAD_GLOBAL_BUILTINS_FROM_KEYS; inst(DELETE_FAST, (--)) { _PyStackRef v = GETLOCAL(oparg); @@ -4871,6 +4884,26 @@ dummy_func( DEOPT_IF(func->func_version != func_version); } + tier2 op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) { + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyObject *res_o = entries[index].me_value; + DEOPT_IF(res_o == NULL); + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); + null = PyStackRef_NULL; + } + + tier2 op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) { + PyDictObject *dict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyObject *res_o = entries[index].me_value; + DEOPT_IF(res_o == NULL); + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); + null = PyStackRef_NULL; + } + /* Internal -- for testing executors */ op(_INTERNAL_INCREMENT_OPT_COUNTER, (opt --)) { _PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 4574e183921006..57e15f33ca7703 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1791,7 +1791,28 @@ break; } - case _GUARD_BUILTINS_VERSION: { + case _GUARD_GLOBALS_VERSION_PUSH_KEYS: { + PyDictKeysObject *globals_keys; + uint16_t version = (uint16_t)CURRENT_OPERAND(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + if (!PyDict_CheckExact(dict)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (dict->ma_keys->dk_version != version) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + globals_keys = dict->ma_keys; + assert(DK_IS_UNICODE(globals_keys)); + stack_pointer[0].bits = (uintptr_t)globals_keys; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _GUARD_BUILTINS_VERSION_PUSH_KEYS: { + PyDictKeysObject *builtins_keys; uint16_t version = (uint16_t)CURRENT_OPERAND(); PyDictObject *dict = (PyDictObject *)BUILTINS(); if (!PyDict_CheckExact(dict)) { @@ -1802,18 +1823,25 @@ UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - assert(DK_IS_UNICODE(dict->ma_keys)); + builtins_keys = dict->ma_keys; + assert(DK_IS_UNICODE(builtins_keys)); + stack_pointer[0].bits = (uintptr_t)builtins_keys; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); break; } - case _LOAD_GLOBAL_MODULE: { + case _LOAD_GLOBAL_MODULE_FROM_KEYS: { + PyDictKeysObject *globals_keys; _PyStackRef res; _PyStackRef null = PyStackRef_NULL; oparg = CURRENT_OPARG(); + globals_keys = (PyDictKeysObject *)stack_pointer[-1].bits; uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *dict = (PyDictObject *)GLOBALS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); PyObject *res_o = entries[index].me_value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -1829,14 +1857,17 @@ break; } - case _LOAD_GLOBAL_BUILTINS: { + case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: { + PyDictKeysObject *builtins_keys; _PyStackRef res; _PyStackRef null = PyStackRef_NULL; oparg = CURRENT_OPARG(); + builtins_keys = (PyDictKeysObject *)stack_pointer[-1].bits; uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *bdict = (PyDictObject *)BUILTINS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); PyObject *res_o = entries[index].me_value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -5698,6 +5729,50 @@ break; } + case _LOAD_GLOBAL_MODULE: { + _PyStackRef res; + _PyStackRef null = PyStackRef_NULL; + oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyObject *res_o = entries[index].me_value; + if (res_o == NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); + null = PyStackRef_NULL; + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_GLOBAL_BUILTINS: { + _PyStackRef res; + _PyStackRef null = PyStackRef_NULL; + oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *dict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyObject *res_o = entries[index].me_value; + if (res_o == NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); + null = PyStackRef_NULL; + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + break; + } + case _INTERNAL_INCREMENT_OPT_COUNTER: { _PyStackRef opt; opt = stack_pointer[-1]; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c4de7bdeb4ce80..7656ce6bb7e313 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -6146,6 +6146,7 @@ next_instr += 5; INSTRUCTION_STATS(LOAD_GLOBAL_BUILTIN); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); + PyDictKeysObject *builtins_keys; _PyStackRef res; _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ @@ -6157,19 +6158,19 @@ DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); } - // _GUARD_BUILTINS_VERSION + // _GUARD_BUILTINS_VERSION_PUSH_KEYS { uint16_t version = read_u16(&this_instr[3].cache); PyDictObject *dict = (PyDictObject *)BUILTINS(); DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); - assert(DK_IS_UNICODE(dict->ma_keys)); + builtins_keys = dict->ma_keys; + assert(DK_IS_UNICODE(builtins_keys)); } - // _LOAD_GLOBAL_BUILTINS + // _LOAD_GLOBAL_BUILTINS_FROM_KEYS { uint16_t index = read_u16(&this_instr[4].cache); - PyDictObject *bdict = (PyDictObject *)BUILTINS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); PyObject *res_o = entries[index].me_value; DEOPT_IF(res_o == NULL, LOAD_GLOBAL); Py_INCREF(res_o); @@ -6189,23 +6190,24 @@ next_instr += 5; INSTRUCTION_STATS(LOAD_GLOBAL_MODULE); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); + PyDictKeysObject *globals_keys; _PyStackRef res; _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ - // _GUARD_GLOBALS_VERSION + // _GUARD_GLOBALS_VERSION_PUSH_KEYS { uint16_t version = read_u16(&this_instr[2].cache); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); - assert(DK_IS_UNICODE(dict->ma_keys)); + globals_keys = dict->ma_keys; + assert(DK_IS_UNICODE(globals_keys)); } /* Skip 1 cache entry */ - // _LOAD_GLOBAL_MODULE + // _LOAD_GLOBAL_MODULE_FROM_KEYS { uint16_t index = read_u16(&this_instr[4].cache); - PyDictObject *dict = (PyDictObject *)GLOBALS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); PyObject *res_o = entries[index].me_value; DEOPT_IF(res_o == NULL, LOAD_GLOBAL); Py_INCREF(res_o); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 06826ff942a761..25166bc2dc5c02 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -131,6 +131,26 @@ incorrect_keys(_PyUOpInstruction *inst, PyObject *obj) return 0; } +static int +check_next_uop(_PyUOpInstruction *buffer, int size, int pc, uint16_t expected) +{ + if (pc + 1 >= size) { + DPRINTF(1, "Cannot rewrite %s at pc %d: buffer too small\n", + _PyOpcode_uop_name[buffer[pc].opcode], pc); + return 0; + } + uint16_t next_opcode = buffer[pc + 1].opcode; + if (next_opcode != expected) { + DPRINTF(1, + "Cannot rewrite %s at pc %d: unexpected next opcode %s, " + "expected %s\n", + _PyOpcode_uop_name[buffer[pc].opcode], pc, + _PyOpcode_uop_name[next_opcode], _PyOpcode_uop_name[expected]); + return 0; + } + return 1; +} + /* Returns 1 if successfully optimized * 0 if the trace is not suitable for optimization (yet) * -1 if there was an error. */ @@ -174,7 +194,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, _PyUOpInstruction *inst = &buffer[pc]; int opcode = inst->opcode; switch(opcode) { - case _GUARD_BUILTINS_VERSION: + case _GUARD_BUILTINS_VERSION_PUSH_KEYS: if (incorrect_keys(inst, builtins)) { OPT_STAT_INC(remove_globals_incorrect_keys); return 0; @@ -182,6 +202,10 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, if (interp->rare_events.builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { continue; } + if (!check_next_uop(buffer, buffer_size, pc, + _LOAD_GLOBAL_BUILTINS_FROM_KEYS)) { + continue; + } if ((builtins_watched & 1) == 0) { PyDict_Watch(BUILTINS_WATCHER_ID, builtins); builtins_watched |= 1; @@ -194,8 +218,13 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, buffer[pc].operand = function_version; function_checked |= 1; } + // We're no longer pushing the builtins keys; rewrite the + // instruction that consumed the keys to load them from the + // frame. + buffer[pc + 1].opcode = _LOAD_GLOBAL_BUILTINS; break; case _GUARD_GLOBALS_VERSION: + case _GUARD_GLOBALS_VERSION_PUSH_KEYS: if (incorrect_keys(inst, globals)) { OPT_STAT_INC(remove_globals_incorrect_keys); return 0; @@ -204,6 +233,11 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, if (watched_mutations >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { continue; } + if (opcode == _GUARD_GLOBALS_VERSION_PUSH_KEYS && + !check_next_uop(buffer, buffer_size, pc, + _LOAD_GLOBAL_MODULE_FROM_KEYS)) { + continue; + } if ((globals_watched & 1) == 0) { PyDict_Watch(GLOBALS_WATCHER_ID, globals); _Py_BloomFilter_Add(dependencies, globals); @@ -217,6 +251,12 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, buffer[pc].operand = function_version; function_checked |= 1; } + if (opcode == _GUARD_GLOBALS_VERSION_PUSH_KEYS) { + // We're no longer pushing the globals keys; rewrite the + // instruction that consumed the keys to load them from the + // frame. + buffer[pc + 1].opcode = _LOAD_GLOBAL_MODULE; + } break; case _LOAD_GLOBAL_BUILTINS: if (function_checked & globals_watched & builtins_watched & 1) { diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index c73b632d1afdd7..d71b55cbe1c68d 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -836,6 +836,16 @@ dummy_func(void) { ctx->done = true; } + op(_GUARD_GLOBALS_VERSION_PUSH_KEYS, (version/1 -- globals_keys)) { + globals_keys = sym_new_unknown(ctx); + (void)version; + } + + op(_GUARD_BUILTINS_VERSION_PUSH_KEYS, (version/1 -- builtins_keys)) { + builtins_keys = sym_new_unknown(ctx); + (void)version; + } + // END BYTECODES // } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index ae532fd27769ab..6ec9e69d1dbc44 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -844,30 +844,48 @@ break; } - case _GUARD_BUILTINS_VERSION: { + case _GUARD_GLOBALS_VERSION_PUSH_KEYS: { + _Py_UopsSymbol *globals_keys; + uint16_t version = (uint16_t)this_instr->operand; + globals_keys = sym_new_unknown(ctx); + (void)version; + stack_pointer[0] = globals_keys; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); break; } - case _LOAD_GLOBAL_MODULE: { + case _GUARD_BUILTINS_VERSION_PUSH_KEYS: { + _Py_UopsSymbol *builtins_keys; + uint16_t version = (uint16_t)this_instr->operand; + builtins_keys = sym_new_unknown(ctx); + (void)version; + stack_pointer[0] = builtins_keys; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_GLOBAL_MODULE_FROM_KEYS: { _Py_UopsSymbol *res; _Py_UopsSymbol *null = NULL; res = sym_new_not_null(ctx); null = sym_new_null(ctx); - stack_pointer[0] = res; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); + stack_pointer[-1] = res; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); assert(WITHIN_STACK_BOUNDS()); break; } - case _LOAD_GLOBAL_BUILTINS: { + case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: { _Py_UopsSymbol *res; _Py_UopsSymbol *null = NULL; res = sym_new_not_null(ctx); null = sym_new_null(ctx); - stack_pointer[0] = res; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); + stack_pointer[-1] = res; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); assert(WITHIN_STACK_BOUNDS()); break; } @@ -2419,6 +2437,30 @@ break; } + case _LOAD_GLOBAL_MODULE: { + _Py_UopsSymbol *res; + _Py_UopsSymbol *null = NULL; + res = sym_new_not_null(ctx); + null = sym_new_null(ctx); + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_GLOBAL_BUILTINS: { + _Py_UopsSymbol *res; + _Py_UopsSymbol *null = NULL; + res = sym_new_not_null(ctx); + null = sym_new_null(ctx); + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + break; + } + case _INTERNAL_INCREMENT_OPT_COUNTER: { stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); From 9bda7750c2af779d3431f5ea120db91c6c83ec49 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Oct 2024 17:54:54 +0200 Subject: [PATCH 083/247] gh-125196: Use PyUnicodeWriter in symtable.c (#125199) --- Python/symtable.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c index 52be910c0b6a9b..709918b27afcc8 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -3120,33 +3120,30 @@ _Py_Mangle(PyObject *privateobj, PyObject *ident) if (ipriv == plen) { return Py_NewRef(ident); /* Don't mangle if class is just underscores */ } - plen -= ipriv; - if (plen + nlen >= PY_SSIZE_T_MAX - 1) { + if (nlen + (plen - ipriv) >= PY_SSIZE_T_MAX - 1) { PyErr_SetString(PyExc_OverflowError, "private identifier too large to be mangled"); return NULL; } - Py_UCS4 maxchar = PyUnicode_MAX_CHAR_VALUE(ident); - if (PyUnicode_MAX_CHAR_VALUE(privateobj) > maxchar) { - maxchar = PyUnicode_MAX_CHAR_VALUE(privateobj); - } - - PyObject *result = PyUnicode_New(1 + nlen + plen, maxchar); - if (!result) { + PyUnicodeWriter *writer = PyUnicodeWriter_Create(1 + nlen + (plen - ipriv)); + if (!writer) { return NULL; } - /* ident = "_" + priv[ipriv:] + ident # i.e. 1+plen+nlen bytes */ - PyUnicode_WRITE(PyUnicode_KIND(result), PyUnicode_DATA(result), 0, '_'); - if (PyUnicode_CopyCharacters(result, 1, privateobj, ipriv, plen) < 0) { - Py_DECREF(result); - return NULL; + // ident = "_" + priv[ipriv:] + ident + if (PyUnicodeWriter_WriteChar(writer, '_') < 0) { + goto error; } - if (PyUnicode_CopyCharacters(result, plen+1, ident, 0, nlen) < 0) { - Py_DECREF(result); - return NULL; + if (PyUnicodeWriter_WriteSubstring(writer, privateobj, ipriv, plen) < 0) { + goto error; } - assert(_PyUnicode_CheckConsistency(result, 1)); - return result; + if (PyUnicodeWriter_WriteStr(writer, ident) < 0) { + goto error; + } + return PyUnicodeWriter_Finish(writer); + +error: + PyUnicodeWriter_Discard(writer); + return NULL; } From d501153aed6cd9c03b77836821ed8d47f0655a0b Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 9 Oct 2024 18:21:35 +0100 Subject: [PATCH 084/247] gh-119786: Move parser doc from devguide to InternalDocs (#125119) Co-authored-by: Jacob Coffee Co-authored-by: Carol Willing Co-Authored-By: Adam Turner <9087854+aa-turner@users.noreply.github.com> Co-Authored-By: Carl Friedrich Bolz-Tereick Co-Authored-By: Carol Willing Co-Authored-By: Erlend E. Aasland Co-Authored-By: Ezio Melotti Co-Authored-By: Hugo van Kemenade Co-Authored-By: Irit Katriel Co-Authored-By: Itamar Ostricher Co-Authored-By: Julien Palard Co-Authored-By: Mana Co-Authored-By: Muhammad Mahad Co-Authored-By: Ned Batchelder Co-Authored-By: Pablo Galindo Salgado Co-Authored-By: slateny <46876382+slateny@users.noreply.github.com> Co-Authored-By: wookie184 --- InternalDocs/README.md | 2 + InternalDocs/parser.md | 894 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 896 insertions(+) create mode 100644 InternalDocs/parser.md diff --git a/InternalDocs/README.md b/InternalDocs/README.md index 95181a420f1dfb..8956ecafed2039 100644 --- a/InternalDocs/README.md +++ b/InternalDocs/README.md @@ -12,6 +12,8 @@ it is not, please report that through the [issue tracker](https://github.com/python/cpython/issues). +[Guide to the parser](parser.md) + [Compiler Design](compiler.md) [Frames](frames.md) diff --git a/InternalDocs/parser.md b/InternalDocs/parser.md new file mode 100644 index 00000000000000..11aaf11253646d --- /dev/null +++ b/InternalDocs/parser.md @@ -0,0 +1,894 @@ + +Guide to the parser +=================== + +Abstract +-------- + +Python's Parser is currently a +[`PEG` (Parser Expression Grammar)](https://en.wikipedia.org/wiki/Parsing_expression_grammar) +parser. It was introduced in +[PEP 617: New PEG parser for CPython](https://peps.python.org/pep-0617/) to replace +the original [``LL(1)``](https://en.wikipedia.org/wiki/LL_parser) parser. + +The code implementing the parser is generated from a grammar definition by a +[parser generator](https://en.wikipedia.org/wiki/Compiler-compiler). +Therefore, changes to the Python language are made by modifying the +[grammar file](https://github.com/python/cpython/blob/main/Grammar/python.gram). +Developers rarely need to modify the generator itself. + +See the devguide's [Changing CPython's grammar](https://devguide.python.org/developer-workflow/grammar/#grammar) +for a detailed description of the grammar and the process for changing it. + +How PEG parsers work +==================== + +A PEG (Parsing Expression Grammar) grammar differs from a +[context-free grammar](https://en.wikipedia.org/wiki/Context-free_grammar) +in that the way it is written more closely reflects how the parser will operate +when parsing. The fundamental technical difference is that the choice operator +is ordered. This means that when writing: + +``` + rule: A | B | C +``` + +a parser that implements a context-free-grammar (such as an ``LL(1)`` parser) will +generate constructions that, given an input string, *deduce* which alternative +(``A``, ``B`` or ``C``) must be expanded. On the other hand, a PEG parser will +check each alternative, in the order in which they are specified, and select +that first one that succeeds. + +This means that in a PEG grammar, the choice operator is not commutative. +Furthermore, unlike context-free grammars, the derivation according to a +PEG grammar cannot be ambiguous: if a string parses, it has exactly one +valid parse tree. + +PEG parsers are usually constructed as a recursive descent parser in which every +rule in the grammar corresponds to a function in the program implementing the +parser, and the parsing expression (the "expansion" or "definition" of the rule) +represents the "code" in said function. Each parsing function conceptually takes +an input string as its argument, and yields one of the following results: + +* A "success" result. This result indicates that the expression can be parsed by + that rule and the function may optionally move forward or consume one or more + characters of the input string supplied to it. +* A "failure" result, in which case no input is consumed. + +Note that "failure" results do not imply that the program is incorrect, nor do +they necessarily mean that the parsing has failed. Since the choice operator is +ordered, a failure very often merely indicates "try the following option". A +direct implementation of a PEG parser as a recursive descent parser will present +exponential time performance in the worst case, because PEG parsers have +infinite lookahead (this means that they can consider an arbitrary number of +tokens before deciding for a rule). Usually, PEG parsers avoid this exponential +time complexity with a technique called +["packrat parsing"](https://pdos.csail.mit.edu/~baford/packrat/thesis/) +which not only loads the entire program in memory before parsing it but also +allows the parser to backtrack arbitrarily. This is made efficient by memoizing +the rules already matched for each position. The cost of the memoization cache +is that the parser will naturally use more memory than a simple ``LL(1)`` parser, +which normally are table-based. + + +Key ideas +--------- + +- Alternatives are ordered ( ``A | B`` is not the same as ``B | A`` ). +- If a rule returns a failure, it doesn't mean that the parsing has failed, + it just means "try something else". +- By default PEG parsers run in exponential time, which can be optimized to linear by + using memoization. +- If parsing fails completely (no rule succeeds in parsing all the input text), the + PEG parser doesn't have a concept of "where the + [``SyntaxError``](https://docs.python.org/3/library/exceptions.html#SyntaxError) is". + + +> [!IMPORTANT] +> Don't try to reason about a PEG grammar in the same way you would to with an +> [EBNF](https://en.wikipedia.org/wiki/Extended_Backus–Naur_form) +> or context free grammar. PEG is optimized to describe **how** input strings will +> be parsed, while context-free grammars are optimized to generate strings of the +> language they describe (in EBNF, to know whether a given string is in the +> language, you need to do work to find out as it is not immediately obvious from +> the grammar). + + +Consequences of the ordered choice operator +------------------------------------------- + +Although PEG may look like EBNF, its meaning is quite different. The fact +that the alternatives are ordered in a PEG grammer (which is at the core of +how PEG parsers work) has deep consequences, other than removing ambiguity. + +If a rule has two alternatives and the first of them succeeds, the second one is +**not** attempted even if the caller rule fails to parse the rest of the input. +Thus the parser is said to be "eager". To illustrate this, consider +the following two rules (in these examples, a token is an individual character): + +``` + first_rule: ( 'a' | 'aa' ) 'a' + second_rule: ('aa' | 'a' ) 'a' +``` + +In a regular EBNF grammar, both rules specify the language ``{aa, aaa}`` but +in PEG, one of these two rules accepts the string ``aaa`` but not the string +``aa``. The other does the opposite -- it accepts the string ``aa`` +but not the string ``aaa``. The rule ``('a'|'aa')'a'`` does +not accept ``aaa`` because ``'a'|'aa'`` consumes the first ``a``, letting the +final ``a`` in the rule consume the second, and leaving out the third ``a``. +As the rule has succeeded, no attempt is ever made to go back and let +``'a'|'aa'`` try the second alternative. The expression ``('aa'|'a')'a'`` does +not accept ``aa`` because ``'aa'|'a'`` accepts all of ``aa``, leaving nothing +for the final ``a``. Again, the second alternative of ``'aa'|'a'`` is not +tried. + +> [!CAUTION] +> The effects of ordered choice, such as the ones illustrated above, may be +> hidden by many levels of rules. + +For this reason, writing rules where an alternative is contained in the next +one is in almost all cases a mistake, for example: + +``` + my_rule: + | 'if' expression 'then' block + | 'if' expression 'then' block 'else' block +``` + +In this example, the second alternative will never be tried because the first one will +succeed first (even if the input string has an ``'else' block`` that follows). To correctly +write this rule you can simply alter the order: + +``` + my_rule: + | 'if' expression 'then' block 'else' block + | 'if' expression 'then' block +``` + +In this case, if the input string doesn't have an ``'else' block``, the first alternative +will fail and the second will be attempted. + +Grammar Syntax +============== + +The grammar consists of a sequence of rules of the form: + +``` + rule_name: expression +``` + +Optionally, a type can be included right after the rule name, which +specifies the return type of the C or Python function corresponding to +the rule: + +``` + rule_name[return_type]: expression +``` + +If the return type is omitted, then a ``void *`` is returned in C and an +``Any`` in Python. + +Grammar expressions +------------------- + +| Expression | Description and Example | +|-----------------|-----------------------------------------------------------------------------------------------------------------------| +| `# comment` | Python-style comments. | +| `e1 e2` | Match `e1`, then match `e2`.
`rule_name: first_rule second_rule` | +| `e1 \| e2` | Match `e1` or `e2`.
`rule_name[return_type]:`
` \| first_alt`
` \| second_alt` | +| `( e )` | Grouping operator: Match `e`.
`rule_name: (e)`
`rule_name: (e1 e2)*` | +| `[ e ]` or `e?` | Optionally match `e`.
`rule_name: [e]`
`rule_name: e (',' e)* [',']` | +| `e*` | Match zero or more occurrences of `e`.
`rule_name: (e1 e2)*` | +| `e+` | Match one or more occurrences of `e`.
`rule_name: (e1 e2)+` | +| `s.e+` | Match one or more occurrences of `e`, separated by `s`.
`rule_name: ','.e+` | +| `&e` | Positive lookahead: Succeed if `e` can be parsed, without consuming input. | +| `!e` | Negative lookahead: Fail if `e` can be parsed, without consuming input.
`primary: atom !'.' !'(' !'['` | +| `~` | Commit to the current alternative, even if it fails to parse (cut).
`rule_name: '(' ~ some_rule ')' \| some_alt` | + + +Left recursion +-------------- + +PEG parsers normally do not support left recursion, but CPython's parser +generator implements a technique similar to the one described in +[Medeiros et al.](https://arxiv.org/pdf/1207.0443) but using the memoization +cache instead of static variables. This approach is closer to the one described +in [Warth et al.](http://web.cs.ucla.edu/~todd/research/pepm08.pdf). This +allows us to write not only simple left-recursive rules but also more +complicated rules that involve indirect left-recursion like: + +``` + rule1: rule2 | 'a' + rule2: rule3 | 'b' + rule3: rule1 | 'c' +``` + +and "hidden left-recursion" like: + +``` + rule: 'optional'? rule '@' some_other_rule +``` + +Variables in the grammar +------------------------ + +A sub-expression can be named by preceding it with an identifier and an +``=`` sign. The name can then be used in the action (see below), like this: + +``` + rule_name[return_type]: '(' a=some_other_rule ')' { a } +``` + +Grammar actions +--------------- + +To avoid the intermediate steps that obscure the relationship between the +grammar and the AST generation, the PEG parser allows directly generating AST +nodes for a rule via grammar actions. Grammar actions are language-specific +expressions that are evaluated when a grammar rule is successfully parsed. These +expressions can be written in Python or C depending on the desired output of the +parser generator. This means that if one would want to generate a parser in +Python and another in C, two grammar files should be written, each one with a +different set of actions, keeping everything else apart from said actions +identical in both files. As an example of a grammar with Python actions, the +piece of the parser generator that parses grammar files is bootstrapped from a +meta-grammar file with Python actions that generate the grammar tree as a result +of the parsing. + +In the specific case of the PEG grammar for Python, having actions allows +directly describing how the AST is composed in the grammar itself, making it +more clear and maintainable. This AST generation process is supported by the use +of some helper functions that factor out common AST object manipulations and +some other required operations that are not directly related to the grammar. + +To indicate these actions each alternative can be followed by the action code +inside curly-braces, which specifies the return value of the alternative: + +``` + rule_name[return_type]: + | first_alt1 first_alt2 { first_alt1 } + | second_alt1 second_alt2 { second_alt1 } +``` + +If the action is omitted, a default action is generated: + +- If there is a single name in the rule, it gets returned. +- If there multiple names in the rule, a collection with all parsed + expressions gets returned (the type of the collection will be different + in C and Python). + +This default behaviour is primarily made for very simple situations and for +debugging purposes. + +> [!WARNING] +> It's important that the actions don't mutate any AST nodes that are passed +> into them via variables referring to other rules. The reason for mutation +> being not allowed is that the AST nodes are cached by memoization and could +> potentially be reused in a different context, where the mutation would be +> invalid. If an action needs to change an AST node, it should instead make a +> new copy of the node and change that. + +The full meta-grammar for the grammars supported by the PEG generator is: + +``` + start[Grammar]: grammar ENDMARKER { grammar } + + grammar[Grammar]: + | metas rules { Grammar(rules, metas) } + | rules { Grammar(rules, []) } + + metas[MetaList]: + | meta metas { [meta] + metas } + | meta { [meta] } + + meta[MetaTuple]: + | "@" NAME NEWLINE { (name.string, None) } + | "@" a=NAME b=NAME NEWLINE { (a.string, b.string) } + | "@" NAME STRING NEWLINE { (name.string, literal_eval(string.string)) } + + rules[RuleList]: + | rule rules { [rule] + rules } + | rule { [rule] } + + rule[Rule]: + | rulename ":" alts NEWLINE INDENT more_alts DEDENT { + Rule(rulename[0], rulename[1], Rhs(alts.alts + more_alts.alts)) } + | rulename ":" NEWLINE INDENT more_alts DEDENT { Rule(rulename[0], rulename[1], more_alts) } + | rulename ":" alts NEWLINE { Rule(rulename[0], rulename[1], alts) } + + rulename[RuleName]: + | NAME '[' type=NAME '*' ']' {(name.string, type.string+"*")} + | NAME '[' type=NAME ']' {(name.string, type.string)} + | NAME {(name.string, None)} + + alts[Rhs]: + | alt "|" alts { Rhs([alt] + alts.alts)} + | alt { Rhs([alt]) } + + more_alts[Rhs]: + | "|" alts NEWLINE more_alts { Rhs(alts.alts + more_alts.alts) } + | "|" alts NEWLINE { Rhs(alts.alts) } + + alt[Alt]: + | items '$' action { Alt(items + [NamedItem(None, NameLeaf('ENDMARKER'))], action=action) } + | items '$' { Alt(items + [NamedItem(None, NameLeaf('ENDMARKER'))], action=None) } + | items action { Alt(items, action=action) } + | items { Alt(items, action=None) } + + items[NamedItemList]: + | named_item items { [named_item] + items } + | named_item { [named_item] } + + named_item[NamedItem]: + | NAME '=' ~ item {NamedItem(name.string, item)} + | item {NamedItem(None, item)} + | it=lookahead {NamedItem(None, it)} + + lookahead[LookaheadOrCut]: + | '&' ~ atom {PositiveLookahead(atom)} + | '!' ~ atom {NegativeLookahead(atom)} + | '~' {Cut()} + + item[Item]: + | '[' ~ alts ']' {Opt(alts)} + | atom '?' {Opt(atom)} + | atom '*' {Repeat0(atom)} + | atom '+' {Repeat1(atom)} + | sep=atom '.' node=atom '+' {Gather(sep, node)} + | atom {atom} + + atom[Plain]: + | '(' ~ alts ')' {Group(alts)} + | NAME {NameLeaf(name.string) } + | STRING {StringLeaf(string.string)} + + # Mini-grammar for the actions + + action[str]: "{" ~ target_atoms "}" { target_atoms } + + target_atoms[str]: + | target_atom target_atoms { target_atom + " " + target_atoms } + | target_atom { target_atom } + + target_atom[str]: + | "{" ~ target_atoms "}" { "{" + target_atoms + "}" } + | NAME { name.string } + | NUMBER { number.string } + | STRING { string.string } + | "?" { "?" } + | ":" { ":" } +``` + +As an illustrative example this simple grammar file allows directly +generating a full parser that can parse simple arithmetic expressions and that +returns a valid C-based Python AST: + +``` + start[mod_ty]: a=expr_stmt* ENDMARKER { _PyAST_Module(a, NULL, p->arena) } + expr_stmt[stmt_ty]: a=expr NEWLINE { _PyAST_Expr(a, EXTRA) } + + expr[expr_ty]: + | l=expr '+' r=term { _PyAST_BinOp(l, Add, r, EXTRA) } + | l=expr '-' r=term { _PyAST_BinOp(l, Sub, r, EXTRA) } + | term + + term[expr_ty]: + | l=term '*' r=factor { _PyAST_BinOp(l, Mult, r, EXTRA) } + | l=term '/' r=factor { _PyAST_BinOp(l, Div, r, EXTRA) } + | factor + + factor[expr_ty]: + | '(' e=expr ')' { e } + | atom + + atom[expr_ty]: + | NAME + | NUMBER +``` + +Here ``EXTRA`` is a macro that expands to ``start_lineno, start_col_offset, +end_lineno, end_col_offset, p->arena``, those being variables automatically +injected by the parser; ``p`` points to an object that holds on to all state +for the parser. + +A similar grammar written to target Python AST objects: + +``` + start[ast.Module]: a=expr_stmt* ENDMARKER { ast.Module(body=a or [] } + expr_stmt: a=expr NEWLINE { ast.Expr(value=a, EXTRA) } + + expr: + | l=expr '+' r=term { ast.BinOp(left=l, op=ast.Add(), right=r, EXTRA) } + | l=expr '-' r=term { ast.BinOp(left=l, op=ast.Sub(), right=r, EXTRA) } + | term + + term: + | l=term '*' r=factor { ast.BinOp(left=l, op=ast.Mult(), right=r, EXTRA) } + | l=term '/' r=factor { ast.BinOp(left=l, op=ast.Div(), right=r, EXTRA) } + | factor + + factor: + | '(' e=expr ')' { e } + | atom + + atom: + | NAME + | NUMBER +``` + +Pegen +===== + +Pegen is the parser generator used in CPython to produce the final PEG parser +used by the interpreter. It is the program that can be used to read the python +grammar located in +[`Grammar/python.gram`](https://github.com/python/cpython/blob/main/Grammar/python.gram) +and produce the final C parser. It contains the following pieces: + +- A parser generator that can read a grammar file and produce a PEG parser + written in Python or C that can parse said grammar. The generator is located at + [`Tools/peg_generator/pegen`](https://github.com/python/cpython/blob/main/Tools/peg_generator/pegen). +- A PEG meta-grammar that automatically generates a Python parser which is used + for the parser generator itself (this means that there are no manually-written + parsers). The meta-grammar is located at + [`Tools/peg_generator/pegen/metagrammar.gram`](https://github.com/python/cpython/blob/main/Tools/peg_generator/pegen/metagrammar.gram). +- A generated parser (using the parser generator) that can directly produce C and Python AST objects. + +The source code for Pegen lives at +[`Tools/peg_generator/pegen`](https://github.com/python/cpython/blob/main/Tools/peg_generator/pegen) +but normally all typical commands to interact with the parser generator are executed from +the main makefile. + +How to regenerate the parser +---------------------------- + +Once you have made the changes to the grammar files, to regenerate the ``C`` +parser (the one used by the interpreter) just execute: + +``` + make regen-pegen +``` + +using the ``Makefile`` in the main directory. If you are on Windows you can +use the Visual Studio project files to regenerate the parser or to execute: + +``` + ./PCbuild/build.bat --regen +``` + +The generated parser file is located at +[`Parser/parser.c`](https://github.com/python/cpython/blob/main/Parser/parser.c). + +How to regenerate the meta-parser +--------------------------------- + +The meta-grammar (the grammar that describes the grammar for the grammar files +themselves) is located at +[`Tools/peg_generator/pegen/metagrammar.gram`](https://github.com/python/cpython/blob/main/Tools/peg_generator/pegen/metagrammar.gram). +Although it is very unlikely that you will ever need to modify it, if you make +any modifications to this file (in order to implement new Pegen features) you will +need to regenerate the meta-parser (the parser that parses the grammar files). +To do so just execute: + +``` + make regen-pegen-metaparser +``` + +If you are on Windows you can use the Visual Studio project files +to regenerate the parser or to execute: + +``` + ./PCbuild/build.bat --regen +``` + + +Grammatical elements and rules +------------------------------ + +Pegen has some special grammatical elements and rules: + +- Strings with single quotes (') (for example, ``'class'``) denote KEYWORDS. +- Strings with double quotes (") (for example, ``"match"``) denote SOFT KEYWORDS. +- Uppercase names (for example, ``NAME``) denote tokens in the + [`Grammar/Tokens`](https://github.com/python/cpython/blob/main/Grammar/Tokens) file. +- Rule names starting with ``invalid_`` are used for specialized syntax errors. + + - These rules are NOT used in the first pass of the parser. + - Only if the first pass fails to parse, a second pass including the invalid + rules will be executed. + - If the parser fails in the second phase with a generic syntax error, the + location of the generic failure of the first pass will be used (this avoids + reporting incorrect locations due to the invalid rules). + - The order of the alternatives involving invalid rules matter + (like any rule in PEG). + +Tokenization +------------ + +It is common among PEG parser frameworks that the parser does both the parsing +and the tokenization, but this does not happen in Pegen. The reason is that the +Python language needs a custom tokenizer to handle things like indentation +boundaries, some special keywords like ``ASYNC`` and ``AWAIT`` (for +compatibility purposes), backtracking errors (such as unclosed parenthesis), +dealing with encoding, interactive mode and much more. Some of these reasons +are also there for historical purposes, and some others are useful even today. + +The list of tokens (all uppercase names in the grammar) that you can use can +be found in thei +[`Grammar/Tokens`](https://github.com/python/cpython/blob/main/Grammar/Tokens) +file. If you change this file to add new tokens, make sure to regenerate the +files by executing: + +``` + make regen-token +``` + +If you are on Windows you can use the Visual Studio project files to regenerate +the tokens or to execute: + +``` + ./PCbuild/build.bat --regen +``` + +How tokens are generated and the rules governing this are completely up to the tokenizer +([`Parser/lexer`](https://github.com/python/cpython/blob/main/Parser/lexer) +and +[`Parser/tokenizer`](https://github.com/python/cpython/blob/main/Parser/tokenizer)); +the parser just receives tokens from it. + +Memoization +----------- + +As described previously, to avoid exponential time complexity in the parser, +memoization is used. + +The C parser used by Python is highly optimized and memoization can be expensive +both in memory and time. Although the memory cost is obvious (the parser needs +memory for storing previous results in the cache) the execution time cost comes +for continuously checking if the given rule has a cache hit or not. In many +situations, just parsing it again can be faster. Pegen **disables memoization +by default** except for rules with the special marker ``memo`` after the rule +name (and type, if present): + +``` + rule_name[typr] (memo): + ... +``` + +By selectively turning on memoization for a handful of rules, the parser becomes +faster and uses less memory. + +> [!NOTE] +> Left-recursive rules always use memoization, since the implementation of +> left-recursion depends on it. + +To determine whether a new rule needs memoization or not, benchmarking is required +(comparing execution times and memory usage of some considerably large files with +and without memoization). There is a very simple instrumentation API available +in the generated C parse code that allows to measure how much each rule uses +memoization (check the +[`Parser/pegen.c`](https://github.com/python/cpython/blob/main/Parser/pegen.c) +file for more information) but it needs to be manually activated. + +Automatic variables +------------------- + +To make writing actions easier, Pegen injects some automatic variables in the +namespace available when writing actions. In the C parser, some of these +automatic variable names are: + +- ``p``: The parser structure. +- ``EXTRA``: This is a macro that expands to + ``(_start_lineno, _start_col_offset, _end_lineno, _end_col_offset, p->arena)``, + which is normally used to create AST nodes as almost all constructors need these + attributes to be provided. All of the location variables are taken from the + location information of the current token. + +Hard and soft keywords +---------------------- + +> [!NOTE] +> In the grammar files, keywords are defined using **single quotes** (for example, +> ``'class'``) while soft keywords are defined using **double quotes** (for example, +> ``"match"``). + +There are two kinds of keywords allowed in pegen grammars: *hard* and *soft* +keywords. The difference between hard and soft keywords is that hard keywords +are always reserved words, even in positions where they make no sense +(for example, ``x = class + 1``), while soft keywords only get a special +meaning in context. Trying to use a hard keyword as a variable will always +fail: + +``` + >>> class = 3 + File "", line 1 + class = 3 + ^ + SyntaxError: invalid syntax + >>> foo(class=3) + File "", line 1 + foo(class=3) + ^^^^^ + SyntaxError: invalid syntax +``` + +While soft keywords don't have this limitation if used in a context other the +one where they are defined as keywords: + +``` + >>> match = 45 + >>> foo(match="Yeah!") +``` + +The ``match`` and ``case`` keywords are soft keywords, so that they are +recognized as keywords at the beginning of a match statement or case block +respectively, but are allowed to be used in other places as variable or +argument names. + +You can get a list of all keywords defined in the grammar from Python: + +``` + >>> import keyword + >>> keyword.kwlist + ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', + 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', + 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', + 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'] +``` + +as well as soft keywords: + +``` + >>> import keyword + >>> keyword.softkwlist + ['_', 'case', 'match'] +``` + +> [!CAUTION] +> Soft keywords can be a bit challenging to manage as they can be accepted in +> places you don't intend, given how the order alternatives behave in PEG +> parsers (see the +> [consequences of ordered choice](#consequences-of-the-ordered-choice-operator) +> section for some background on this). In general, try to define them in places +> where there are not many alternatives. + +Error handling +-------------- + +When a pegen-generated parser detects that an exception is raised, it will +**automatically stop parsing**, no matter what the current state of the parser +is, and it will unwind the stack and report the exception. This means that if a +[rule action](#grammar-actions) raises an exception, all parsing will +stop at that exact point. This is done to allow to correctly propagate any +exception set by calling Python's C API functions. This also includes +[``SyntaxError``](https://docs.python.org/3/library/exceptions.html#SyntaxError) +exceptions and it is the main mechanism the parser uses to report custom syntax +error messages. + +> [!NOTE] +> Tokenizer errors are normally reported by raising exceptions but some special +> tokenizer errors such as unclosed parenthesis will be reported only after the +> parser finishes without returning anything. + +How syntax errors are reported +------------------------------ + +As described previously in the [how PEG parsers work](#how-peg-parsers-work) +section, PEG parsers don't have a defined concept of where errors happened +in the grammar, because a rule failure doesn't imply a parsing failure like +in context free grammars. This means that a heuristic has to be used to report +generic errors unless something is explicitly declared as an error in the +grammar. + +To report generic syntax errors, pegen uses a common heuristic in PEG parsers: +the location of *generic* syntax errors is reported to be the furthest token that +was attempted to be matched but failed. This is only done if parsing has failed +(the parser returns ``NULL`` in C or ``None`` in Python) but no exception has +been raised. + +As the Python grammar was primordially written as an ``LL(1)`` grammar, this heuristic +has an extremely high success rate, but some PEG features, such as lookaheads, +can impact this. + +> [!CAUTION] +> Positive and negative lookaheads will try to match a token so they will affect +> the location of generic syntax errors. Use them carefully at boundaries +> between rules. + +To generate more precise syntax errors, custom rules are used. This is a common +practice also in context free grammars: the parser will try to accept some +construct that is known to be incorrect just to report a specific syntax error +for that construct. In pegen grammars, these rules start with the ``invalid_`` +prefix. This is because trying to match these rules normally has a performance +impact on parsing (and can also affect the 'correct' grammar itself in some +tricky cases, depending on the ordering of the rules) so the generated parser +acts in two phases: + +1. The first phase will try to parse the input stream without taking into + account rules that start with the ``invalid_`` prefix. If the parsing + succeeds it will return the generated AST and the second phase will be + skipped. + +2. If the first phase failed, a second parsing attempt is done including the + rules that start with an ``invalid_`` prefix. By design this attempt + **cannot succeed** and is only executed to give to the invalid rules a + chance to detect specific situations where custom, more precise, syntax + errors can be raised. This also allows to trade a bit of performance for + precision reporting errors: given that we know that the input text is + invalid, there is typically no need to be fast because execution is going + to stop anyway. + +> [!IMPORTANT] +> When defining invalid rules: +> +> - Make sure all custom invalid rules raise +> [``SyntaxError``](https://docs.python.org/3/library/exceptions.html#SyntaxError) +> exceptions (or a subclass of it). +> - Make sure **all** invalid rules start with the ``invalid_`` prefix to not +> impact performance of parsing correct Python code. +> - Make sure the parser doesn't behave differently for regular rules when you introduce invalid rules +> (see the [how PEG parsers work](#how-peg-parsers-work) section for more information). + +You can find a collection of macros to raise specialized syntax errors in the +[`Parser/pegen.h`](https://github.com/python/cpython/blob/main/Parser/pegen.h) +header file. These macros allow also to report ranges for +the custom errors, which will be highlighted in the tracebacks that will be +displayed when the error is reported. + + +> [!TIP] +> A good way to test whether an invalid rule will be triggered when you expect +> is to test if introducing a syntax error **after** valid code triggers the +> rule or not. For example: + +``` + $ 42 +``` + +should trigger the syntax error in the ``$`` character. If your rule is not correctly defined this +won't happen. As another example, suppose that you try to define a rule to match Python 2 style +``print`` statements in order to create a better error message and you define it as: + +``` + invalid_print: "print" expression +``` + +This will **seem** to work because the parser will correctly parse ``print(something)`` because it is valid +code and the second phase will never execute but if you try to parse ``print(something) $ 3`` the first pass +of the parser will fail (because of the ``$``) and in the second phase, the rule will match the +``print(something)`` as ``print`` followed by the variable ``something`` between parentheses and the error +will be reported there instead of the ``$`` character. + +Generating AST objects +---------------------- + +The output of the C parser used by CPython, which is generated from the +[grammar file](https://github.com/python/cpython/blob/main/Grammar/python.gram), +is a Python AST object (using C structures). This means that the actions in the +grammar file generate AST objects when they succeed. Constructing these objects +can be quite cumbersome (see the [AST compiler section](compiler.md#abstract-syntax-trees-ast) +for more information on how these objects are constructed and how they are used +by the compiler), so special helper functions are used. These functions are +declared in the +[`Parser/pegen.h`](https://github.com/python/cpython/blob/main/Parser/pegen.h) +header file and defined in the +[`Parser/action_helpers.c`](https://github.com/python/cpython/blob/main/Parser/action_helpers.c) +file. The helpers include functions that join AST sequences, get specific elements +from them or to perform extra processing on the generated tree. + + +> [!CAUTION] +> Actions must **never** be used to accept or reject rules. It may be tempting +> in some situations to write a very generic rule and then check the generated +> AST to decide whether it is valid or not, but this will render the +> (official grammar)[https://docs.python.org/3/reference/grammar.html] partially +> incorrect (because it does not include actions) and will make it more difficult +> for other Python implementations to adapt the grammar to their own needs. + +As a general rule, if an action spawns multiple lines or requires something more +complicated than a single expression of C code, is normally better to create a +custom helper in +[`Parser/action_helpers.c`](https://github.com/python/cpython/blob/main/Parser/action_helpers.c) +and expose it in the +[`Parser/pegen.h`](https://github.com/python/cpython/blob/main/Parser/pegen.h) +header file so that it can be used from the grammar. + +When parsing succeeds, the parser **must** return a **valid** AST object. + +Testing +======= + +There are three files that contain tests for the grammar and the parser: + +- [test_grammar.py](https://github.com/python/cpython/blob/main/Lib/test/test_grammar.py) +- [test_syntax.py](https://github.com/python/cpython/blob/main/Lib/test/test_syntax.py) +- [test_exceptions.py](https://github.com/python/cpython/blob/main/Lib/test/test_exceptions.py) + +Check the contents of these files to know which is the best place for new tests, depending +on the nature of the new feature you are adding. + +Tests for the parser generator itself can be found in the +[test_peg_generator](https://github.com/python/cpython/blob/main/Lib/test_peg_generator) +directory. + + +Debugging generated parsers +=========================== + +Making experiments +------------------ + +As the generated C parser is the one used by Python, this means that if +something goes wrong when adding some new rules to the grammar, you cannot +correctly compile and execute Python anymore. This makes it a bit challenging +to debug when something goes wrong, especially when experimenting. + +For this reason it is a good idea to experiment first by generating a Python +parser. To do this, you can go to the +[Tools/peg_generator](https://github.com/python/cpython/blob/main/Tools/peg_generator) +directory on the CPython repository and manually call the parser generator by executing: + +``` + $ python -m pegen python +``` + +This will generate a file called ``parse.py`` in the same directory that you +can use to parse some input: + +``` + $ python parse.py file_with_source_code_to_test.py +``` + +As the generated ``parse.py`` file is just Python code, you can modify it +and add breakpoints to debug or better understand some complex situations. + + +Verbose mode +------------ + +When Python is compiled in debug mode (by adding ``--with-pydebug`` when +running the configure step in Linux or by adding ``-d`` when calling the +[PCbuild/build.bat](https://github.com/python/cpython/blob/main/PCbuild/build.bat)), +it is possible to activate a **very** verbose mode in the generated parser. This +is very useful to debug the generated parser and to understand how it works, but it +can be a bit hard to understand at first. + +> [!NOTE] +> When activating verbose mode in the Python parser, it is better to not use +> interactive mode as it can be much harder to understand, because interactive +> mode involves some special steps compared to regular parsing. + +To activate verbose mode you can add the ``-d`` flag when executing Python: + +``` + $ python -d file_to_test.py +``` + +This will print **a lot** of output to ``stderr`` so it is probably better to dump +it to a file for further analysis. The output consists of trace lines with the +following structure:: + +``` + ('>'|'-'|'+'|'!') []: ... +``` + +Every line is indented by a different amount (````) depending on how +deep the call stack is. The next character marks the type of the trace: + +- ``>`` indicates that a rule is going to be attempted to be parsed. +- ``-`` indicates that a rule has failed to be parsed. +- ``+`` indicates that a rule has been parsed correctly. +- ``!`` indicates that an exception or an error has been detected and the parser is unwinding. + +The ```` part indicates the current index in the token array, +the ```` part indicates what rule is being parsed and +the ```` part indicates what alternative within that rule +is being attempted. + + +> [!NOTE] +> **Document history** +> +> Pablo Galindo Salgado - Original author +> Irit Katriel and Jacob Coffee - Convert to Markdown From f2cb39947093feda3ff85b8dc820922cc5e5f954 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 9 Oct 2024 11:32:16 -0600 Subject: [PATCH 085/247] gh-116510: Fix a Crash Due to Shared Immortal Interned Strings (gh-124865) Fix a crash caused by immortal interned strings being shared between sub-interpreters that use basic single-phase init. In that case, the string can be used by an interpreter that outlives the interpreter that created and interned it. For interpreters that share obmalloc state, also share the interned dict with the main interpreter. This is an un-revert of gh-124646 that then addresses the Py_TRACE_REFS failures identified by gh-124785. --- ...-09-26-18-21-06.gh-issue-116510.FacUWO.rst | 5 ++ Objects/object.c | 36 ++++++++++++ Objects/unicodeobject.c | 56 +++++++++++++++++-- 3 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst new file mode 100644 index 00000000000000..e3741321006548 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst @@ -0,0 +1,5 @@ +Fix a crash caused by immortal interned strings being shared between +sub-interpreters that use basic single-phase init. In that case, the string +can be used by an interpreter that outlives the interpreter that created and +interned it. For interpreters that share obmalloc state, also share the +interned dict with the main interpreter. diff --git a/Objects/object.c b/Objects/object.c index 8a819dd336e421..8d809158a6c1da 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2491,6 +2491,42 @@ _Py_ResurrectReference(PyObject *op) #ifdef Py_TRACE_REFS +/* Make sure the ref is associated with the right interpreter. + * This only needs special attention for heap-allocated objects + * that have been immortalized, and only when the object might + * outlive the interpreter where it was created. That means the + * object was necessarily created using a global allocator + * (i.e. from the main interpreter). Thus in that specific case + * we move the object over to the main interpreter's refchain. + * + * This was added for the sake of the immortal interned strings, + * where legacy subinterpreters share the main interpreter's + * interned dict (and allocator), and therefore the strings can + * outlive the subinterpreter. + * + * It may make sense to fold this into _Py_SetImmortalUntracked(), + * but that requires further investigation. In the meantime, it is + * up to the caller to know if this is needed. There should be + * very few cases. + */ +void +_Py_NormalizeImmortalReference(PyObject *op) +{ + assert(_Py_IsImmortal(op)); + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!_PyRefchain_IsTraced(interp, op)) { + return; + } + PyInterpreterState *main_interp = _PyInterpreterState_Main(); + if (interp != main_interp + && interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC) + { + assert(!_PyRefchain_IsTraced(main_interp, op)); + _PyRefchain_Remove(interp, op); + _PyRefchain_Trace(main_interp, op); + } +} + void _Py_ForgetReference(PyObject *op) { diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index bd5bb5048fdacc..4ea7d5f380e9a2 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -281,13 +281,37 @@ hashtable_unicode_compare(const void *key1, const void *key2) } } +/* Return true if this interpreter should share the main interpreter's + intern_dict. That's important for interpreters which load basic + single-phase init extension modules (m_size == -1). There could be interned + immortal strings that are shared between interpreters, due to the + PyDict_Update(mdict, m_copy) call in import_find_extension(). + + It's not safe to deallocate those strings until all interpreters that + potentially use them are freed. By storing them in the main interpreter, we + ensure they get freed after all other interpreters are freed. +*/ +static bool +has_shared_intern_dict(PyInterpreterState *interp) +{ + PyInterpreterState *main_interp = _PyInterpreterState_Main(); + return interp != main_interp && interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC; +} + static int init_interned_dict(PyInterpreterState *interp) { assert(get_interned_dict(interp) == NULL); - PyObject *interned = interned = PyDict_New(); - if (interned == NULL) { - return -1; + PyObject *interned; + if (has_shared_intern_dict(interp)) { + interned = get_interned_dict(_PyInterpreterState_Main()); + Py_INCREF(interned); + } + else { + interned = PyDict_New(); + if (interned == NULL) { + return -1; + } } _Py_INTERP_CACHED_OBJECT(interp, interned_strings) = interned; return 0; @@ -298,7 +322,10 @@ clear_interned_dict(PyInterpreterState *interp) { PyObject *interned = get_interned_dict(interp); if (interned != NULL) { - PyDict_Clear(interned); + if (!has_shared_intern_dict(interp)) { + // only clear if the dict belongs to this interpreter + PyDict_Clear(interned); + } Py_DECREF(interned); _Py_INTERP_CACHED_OBJECT(interp, interned_strings) = NULL; } @@ -15401,6 +15428,10 @@ _PyUnicode_InternStatic(PyInterpreterState *interp, PyObject **p) assert(*p); } +#ifdef Py_TRACE_REFS +extern void _Py_NormalizeImmortalReference(PyObject *); +#endif + static void immortalize_interned(PyObject *s) { @@ -15416,6 +15447,10 @@ immortalize_interned(PyObject *s) #endif _PyUnicode_STATE(s).interned = SSTATE_INTERNED_IMMORTAL; _Py_SetImmortal(s); +#ifdef Py_TRACE_REFS + /* Make sure the ref is associated with the right interpreter. */ + _Py_NormalizeImmortalReference(s); +#endif } static /* non-null */ PyObject* @@ -15609,6 +15644,13 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) } assert(PyDict_CheckExact(interned)); + if (has_shared_intern_dict(interp)) { + // the dict doesn't belong to this interpreter, skip the debug + // checks on it and just clear the pointer to it + clear_interned_dict(interp); + return; + } + #ifdef INTERNED_STATS fprintf(stderr, "releasing %zd interned strings\n", PyDict_GET_SIZE(interned)); @@ -16117,8 +16159,10 @@ _PyUnicode_Fini(PyInterpreterState *interp) { struct _Py_unicode_state *state = &interp->unicode; - // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini() - assert(get_interned_dict(interp) == NULL); + if (!has_shared_intern_dict(interp)) { + // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini() + assert(get_interned_dict(interp) == NULL); + } _PyUnicode_FiniEncodings(&state->fs_codec); From cbfd39247983309a9ef0ae6da6c61cc71665b967 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Wed, 9 Oct 2024 21:50:03 +0100 Subject: [PATCH 086/247] GH-121970: Extract ``availability`` into a new extension (#125082) --- Doc/conf.py | 1 + Doc/tools/extensions/availability.py | 125 +++++++++++++++++++++++++++ Doc/tools/extensions/pyspecific.py | 76 ---------------- 3 files changed, 126 insertions(+), 76 deletions(-) create mode 100644 Doc/tools/extensions/availability.py diff --git a/Doc/conf.py b/Doc/conf.py index 5f22340ac434c9..287e0da46eb11c 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -21,6 +21,7 @@ extensions = [ 'audit_events', + 'availability', 'c_annotations', 'glossary_search', 'lexers', diff --git a/Doc/tools/extensions/availability.py b/Doc/tools/extensions/availability.py new file mode 100644 index 00000000000000..47833fdcb87590 --- /dev/null +++ b/Doc/tools/extensions/availability.py @@ -0,0 +1,125 @@ +"""Support for documenting platform availability""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from docutils import nodes +from sphinx import addnodes +from sphinx.util import logging +from sphinx.util.docutils import SphinxDirective + +if TYPE_CHECKING: + from sphinx.application import Sphinx + from sphinx.util.typing import ExtensionMetadata + +logger = logging.getLogger("availability") + +# known platform, libc, and threading implementations +_PLATFORMS = frozenset({ + "AIX", + "Android", + "BSD", + "DragonFlyBSD", + "Emscripten", + "FreeBSD", + "GNU/kFreeBSD", + "iOS", + "Linux", + "macOS", + "NetBSD", + "OpenBSD", + "POSIX", + "Solaris", + "Unix", + "VxWorks", + "WASI", + "Windows", +}) +_LIBC = frozenset({ + "BSD libc", + "glibc", + "musl", +}) +_THREADING = frozenset({ + # POSIX platforms with pthreads + "pthreads", +}) +KNOWN_PLATFORMS = _PLATFORMS | _LIBC | _THREADING + + +class Availability(SphinxDirective): + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + + def run(self) -> list[nodes.container]: + title = "Availability" + refnode = addnodes.pending_xref( + title, + nodes.inline(title, title, classes=["xref", "std", "std-ref"]), + refdoc=self.env.docname, + refdomain="std", + refexplicit=True, + reftarget="availability", + reftype="ref", + refwarn=True, + ) + sep = nodes.Text(": ") + parsed, msgs = self.state.inline_text(self.arguments[0], self.lineno) + pnode = nodes.paragraph(title, "", refnode, sep, *parsed, *msgs) + self.set_source_info(pnode) + cnode = nodes.container("", pnode, classes=["availability"]) + self.set_source_info(cnode) + if self.content: + self.state.nested_parse(self.content, self.content_offset, cnode) + self.parse_platforms() + + return [cnode] + + def parse_platforms(self) -> dict[str, str | bool]: + """Parse platform information from arguments + + Arguments is a comma-separated string of platforms. A platform may + be prefixed with "not " to indicate that a feature is not available. + + Example:: + + .. availability:: Windows, Linux >= 4.2, not WASI + + Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not + parsed into separate tokens. + """ + platforms = {} + for arg in self.arguments[0].rstrip(".").split(","): + arg = arg.strip() + platform, _, version = arg.partition(" >= ") + if platform.startswith("not "): + version = False + platform = platform.removeprefix("not ") + elif not version: + version = True + platforms[platform] = version + + if unknown := set(platforms).difference(KNOWN_PLATFORMS): + logger.warning( + "Unknown platform%s or syntax '%s' in '.. availability:: %s', " + "see %s:KNOWN_PLATFORMS for a set of known platforms.", + "s" if len(platforms) != 1 else "", + " ".join(sorted(unknown)), + self.arguments[0], + __file__, + ) + + return platforms + + +def setup(app: Sphinx) -> ExtensionMetadata: + app.add_directive("availability", Availability) + + return { + "version": "1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index b6623a2b8e01f1..bcb8a421e32d09 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -24,7 +24,6 @@ from sphinx.domains.changeset import VersionChange, versionlabels, versionlabel_classes from sphinx.domains.python import PyFunction, PyMethod, PyModule from sphinx.locale import _ as sphinx_gettext -from sphinx.util import logging from sphinx.util.docutils import SphinxDirective from sphinx.writers.text import TextWriter, TextTranslator from sphinx.util.display import status_iterator @@ -108,80 +107,6 @@ def run(self): return [pnode] -# Support for documenting platform availability - -class Availability(SphinxDirective): - - has_content = True - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = True - - # known platform, libc, and threading implementations - known_platforms = frozenset({ - "AIX", "Android", "BSD", "DragonFlyBSD", "Emscripten", "FreeBSD", - "GNU/kFreeBSD", "Linux", "NetBSD", "OpenBSD", "POSIX", "Solaris", - "Unix", "VxWorks", "WASI", "Windows", "macOS", "iOS", - # libc - "BSD libc", "glibc", "musl", - # POSIX platforms with pthreads - "pthreads", - }) - - def run(self): - availability_ref = ':ref:`Availability `: ' - avail_nodes, avail_msgs = self.state.inline_text( - availability_ref + self.arguments[0], - self.lineno) - pnode = nodes.paragraph(availability_ref + self.arguments[0], - '', *avail_nodes, *avail_msgs) - self.set_source_info(pnode) - cnode = nodes.container("", pnode, classes=["availability"]) - self.set_source_info(cnode) - if self.content: - self.state.nested_parse(self.content, self.content_offset, cnode) - self.parse_platforms() - - return [cnode] - - def parse_platforms(self): - """Parse platform information from arguments - - Arguments is a comma-separated string of platforms. A platform may - be prefixed with "not " to indicate that a feature is not available. - - Example:: - - .. availability:: Windows, Linux >= 4.2, not WASI - - Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not - parsed into separate tokens. - """ - platforms = {} - for arg in self.arguments[0].rstrip(".").split(","): - arg = arg.strip() - platform, _, version = arg.partition(" >= ") - if platform.startswith("not "): - version = False - platform = platform[4:] - elif not version: - version = True - platforms[platform] = version - - unknown = set(platforms).difference(self.known_platforms) - if unknown: - cls = type(self) - logger = logging.getLogger(cls.__qualname__) - logger.warning( - f"Unknown platform(s) or syntax '{' '.join(sorted(unknown))}' " - f"in '.. availability:: {self.arguments[0]}', see " - f"{__file__}:{cls.__qualname__}.known_platforms for a set " - "known platforms." - ) - - return platforms - - # Support for documenting decorators class PyDecoratorMixin(object): @@ -492,7 +417,6 @@ def setup(app): app.add_role('issue', issue_role) app.add_role('gh', gh_issue_role) app.add_directive('impl-detail', ImplementationDetail) - app.add_directive('availability', Availability) app.add_directive('versionadded', PyVersionChange, override=True) app.add_directive('versionchanged', PyVersionChange, override=True) app.add_directive('versionremoved', PyVersionChange, override=True) From 7d2c39752fa6f685f15ad9c585d83a62553477c2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 10 Oct 2024 00:20:53 +0300 Subject: [PATCH 087/247] gh-91818: Use default program name in the CLI of many modules (GH-124867) As argparse now detects by default when the code was run as a module. This leads to using the actual executable name instead of simply "python" to display in the usage message ("usage: python -m ..."). --- Lib/ast.py | 2 +- Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_uninstall.py | 2 +- Lib/json/tool.py | 3 +-- Lib/pdb.py | 3 +-- Lib/sqlite3/__main__.py | 1 - Lib/test/test_sqlite3/test_cli.py | 4 +++- Lib/tokenize.py | 2 +- Lib/venv/__init__.py | 3 +-- .../Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst | 4 ++++ 10 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst diff --git a/Lib/ast.py b/Lib/ast.py index a954d4a97d3c22..154d2c8c1f9ebb 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1743,7 +1743,7 @@ def unparse(ast_obj): def main(): import argparse - parser = argparse.ArgumentParser(prog='python -m ast') + parser = argparse.ArgumentParser() parser.add_argument('infile', nargs='?', default='-', help='the file to parse; defaults to stdin') parser.add_argument('-m', '--mode', default='exec', diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index c5350df270487a..585afc85836c06 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -205,7 +205,7 @@ def _uninstall_helper(*, verbosity=0): def _main(argv=None): import argparse - parser = argparse.ArgumentParser(prog="python -m ensurepip") + parser = argparse.ArgumentParser() parser.add_argument( "--version", action="version", diff --git a/Lib/ensurepip/_uninstall.py b/Lib/ensurepip/_uninstall.py index b257904328d2f5..4183c28a809008 100644 --- a/Lib/ensurepip/_uninstall.py +++ b/Lib/ensurepip/_uninstall.py @@ -6,7 +6,7 @@ def _main(argv=None): - parser = argparse.ArgumentParser(prog="python -m ensurepip._uninstall") + parser = argparse.ArgumentParser() parser.add_argument( "--version", action="version", diff --git a/Lib/json/tool.py b/Lib/json/tool.py index 9028e517fb9f7d..1ba91384c81f27 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -9,10 +9,9 @@ def main(): - prog = 'python -m json' description = ('A simple command line interface for json module ' 'to validate and pretty-print JSON objects.') - parser = argparse.ArgumentParser(prog=prog, description=description) + parser = argparse.ArgumentParser(description=description) parser.add_argument('infile', nargs='?', help='a JSON file to be validated or pretty-printed', default='-') diff --git a/Lib/pdb.py b/Lib/pdb.py index aea6fb70ae3106..d9aed24bfcd8e7 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -2423,8 +2423,7 @@ def help(): def main(): import argparse - parser = argparse.ArgumentParser(prog="pdb", - usage="%(prog)s [-h] [-c command] (-m module | pyfile) [args ...]", + parser = argparse.ArgumentParser(usage="%(prog)s [-h] [-c command] (-m module | pyfile) [args ...]", description=_usage, formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index d9423c25e34135..cfdee61403d1fa 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -65,7 +65,6 @@ def runsource(self, source, filename="", symbol="single"): def main(*args): parser = ArgumentParser( description="Python sqlite3 CLI", - prog="python -m sqlite3", ) parser.add_argument( "filename", type=str, default=":memory:", nargs="?", diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index 303f9e03b5383f..d014a9ce841607 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -34,7 +34,9 @@ def expect_failure(self, *args): def test_cli_help(self): out = self.expect_success("-h") - self.assertIn("usage: python -m sqlite3", out) + self.assertIn("usage: ", out) + self.assertIn(" [-h] [-v] [filename] [sql]", out) + self.assertIn("Python sqlite3 CLI", out) def test_cli_version(self): out = self.expect_success("-v") diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 4b4c3cfe16999b..7ece4e9b70d31b 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -510,7 +510,7 @@ def error(message, filename=None, location=None): sys.exit(1) # Parse the arguments and options - parser = argparse.ArgumentParser(prog='python -m tokenize') + parser = argparse.ArgumentParser() parser.add_argument(dest='filename', nargs='?', metavar='filename.py', help='the file to tokenize; defaults to stdin') diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index a5cb2bdb064692..a00fa690fa0b88 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -575,8 +575,7 @@ def create(env_dir, system_site_packages=False, clear=False, def main(args=None): import argparse - parser = argparse.ArgumentParser(prog=__name__, - description='Creates virtual Python ' + parser = argparse.ArgumentParser(description='Creates virtual Python ' 'environments in one or ' 'more target ' 'directories.', diff --git a/Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst b/Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst new file mode 100644 index 00000000000000..f45f00e48a3830 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst @@ -0,0 +1,4 @@ +The CLI of many modules (:mod:`ast`, :mod:`ensurepip`, :mod:`json`, +:mod:`pdb`, :mod:`sqlite3`, :mod:`tokenize`, :mod:`venv`) now uses the +actual executable name instead of simply "python" to display in the usage +message. From 52f70da19cf3c7198be37faeac233ef803080f6f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 9 Oct 2024 23:56:30 +0200 Subject: [PATCH 088/247] gh-125196: Use PyUnicodeWriter for repr(list) (#125202) Replace the private _PyUnicodeWriter with the public PyUnicodeWriter. Replace PyObject_Repr() + _PyUnicodeWriter_WriteStr() with PyUnicodeWriter_WriteRepr(). --- Objects/listobject.c | 45 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 8abe15d6674140..e7090f20001a39 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -522,49 +522,50 @@ list_dealloc(PyObject *self) static PyObject * list_repr_impl(PyListObject *v) { - PyObject *s; - _PyUnicodeWriter writer; - Py_ssize_t i = Py_ReprEnter((PyObject*)v); - if (i != 0) { - return i > 0 ? PyUnicode_FromString("[...]") : NULL; + int res = Py_ReprEnter((PyObject*)v); + if (res != 0) { + return (res > 0 ? PyUnicode_FromString("[...]") : NULL); } - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; /* "[" + "1" + ", 2" * (len - 1) + "]" */ - writer.min_length = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1; + Py_ssize_t prealloc = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1; + PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc); + if (writer == NULL) { + goto error; + } - if (_PyUnicodeWriter_WriteChar(&writer, '[') < 0) + if (PyUnicodeWriter_WriteChar(writer, '[') < 0) { goto error; + } /* Do repr() on each element. Note that this may mutate the list, so must refetch the list size on each iteration. */ - for (i = 0; i < Py_SIZE(v); ++i) { + for (Py_ssize_t i = 0; i < Py_SIZE(v); ++i) { if (i > 0) { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) + if (PyUnicodeWriter_WriteChar(writer, ',') < 0) { + goto error; + } + if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) { goto error; + } } - s = PyObject_Repr(v->ob_item[i]); - if (s == NULL) - goto error; - - if (_PyUnicodeWriter_WriteStr(&writer, s) < 0) { - Py_DECREF(s); + if (PyUnicodeWriter_WriteRepr(writer, v->ob_item[i]) < 0) { goto error; } - Py_DECREF(s); } - writer.overallocate = 0; - if (_PyUnicodeWriter_WriteChar(&writer, ']') < 0) + if (PyUnicodeWriter_WriteChar(writer, ']') < 0) { goto error; + } Py_ReprLeave((PyObject *)v); - return _PyUnicodeWriter_Finish(&writer); + return PyUnicodeWriter_Finish(writer); error: - _PyUnicodeWriter_Dealloc(&writer); + if (writer != NULL) { + PyUnicodeWriter_Discard(writer); + } Py_ReprLeave((PyObject *)v); return NULL; } From 0c5a48c1c9039eb1ce25a96c43505c4de0a0b9d7 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 9 Oct 2024 15:56:50 -0600 Subject: [PATCH 089/247] GH-124693: Support parsing negative scientific and complex numbers argparse (GH-124823) Co-authored-by: Serhiy Storchaka --- Lib/argparse.py | 2 +- Lib/test/test_argparse.py | 27 ++++++++++++++----- ...-10-01-02-31-13.gh-issue-124693.qzbXKB.rst | 1 + 3 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index 21299b69ecd74c..d1f8fa2ace8611 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1367,7 +1367,7 @@ def __init__(self, self._defaults = {} # determines whether an "option" looks like a negative number - self._negative_number_matcher = _re.compile(r'^-(?:\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?|\.\d+(?:_\d+)*)$') + self._negative_number_matcher = _re.compile(r'-\.?\d') # whether or not there are any optionals that look like negative # numbers -- uses a list so it can be shared and edited diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 1bf812b36fc2c6..c9e79eb18a08fb 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2195,20 +2195,33 @@ class TestNegativeNumber(ParserTestCase): argument_signatures = [ Sig('--int', type=int), Sig('--float', type=float), + Sig('--complex', type=complex), ] failures = [ '--float -_.45', '--float -1__000.0', + '--float -1.0.0', '--int -1__000', + '--int -1.0', + '--complex -1__000.0j', + '--complex -1.0jj', + '--complex -_.45j', ] successes = [ - ('--int -1000 --float -1000.0', NS(int=-1000, float=-1000.0)), - ('--int -1_000 --float -1_000.0', NS(int=-1000, float=-1000.0)), - ('--int -1_000_000 --float -1_000_000.0', NS(int=-1000000, float=-1000000.0)), - ('--float -1_000.0', NS(int=None, float=-1000.0)), - ('--float -1_000_000.0_0', NS(int=None, float=-1000000.0)), - ('--float -.5', NS(int=None, float=-0.5)), - ('--float -.5_000', NS(int=None, float=-0.5)), + ('--int -1000 --float -1000.0', NS(int=-1000, float=-1000.0, complex=None)), + ('--int -1_000 --float -1_000.0', NS(int=-1000, float=-1000.0, complex=None)), + ('--int -1_000_000 --float -1_000_000.0', NS(int=-1000000, float=-1000000.0, complex=None)), + ('--float -1_000.0', NS(int=None, float=-1000.0, complex=None)), + ('--float -1_000_000.0_0', NS(int=None, float=-1000000.0, complex=None)), + ('--float -.5', NS(int=None, float=-0.5, complex=None)), + ('--float -.5_000', NS(int=None, float=-0.5, complex=None)), + ('--float -1e3', NS(int=None, float=-1000, complex=None)), + ('--float -1e-3', NS(int=None, float=-0.001, complex=None)), + ('--complex -1j', NS(int=None, float=None, complex=-1j)), + ('--complex -1_000j', NS(int=None, float=None, complex=-1000j)), + ('--complex -1_000.0j', NS(int=None, float=None, complex=-1000.0j)), + ('--complex -1e3j', NS(int=None, float=None, complex=-1000j)), + ('--complex -1e-3j', NS(int=None, float=None, complex=-0.001j)), ] class TestInvalidAction(TestCase): diff --git a/Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst b/Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst new file mode 100644 index 00000000000000..3e87eb457d9911 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst @@ -0,0 +1 @@ +Fix a bug where :mod:`argparse` doesn't recognize negative complex numbers or negative numbers using scientific notation. From ee3167b9787bf9424d5637a224233de775450231 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 00:01:02 +0200 Subject: [PATCH 090/247] gh-125196: Add fast-path for int in PyUnicodeWriter_WriteStr() (#125214) PyUnicodeWriter_WriteStr() and PyUnicodeWriter_WriteRepr() now call directly _PyLong_FormatWriter() if the argument is an int. --- Objects/unicodeobject.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4ea7d5f380e9a2..a9b33248163880 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13632,6 +13632,10 @@ _PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str) int PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj) { + if (Py_TYPE(obj) == &PyLong_Type) { + return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0); + } + PyObject *str = PyObject_Str(obj); if (str == NULL) { return -1; @@ -13646,6 +13650,10 @@ PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj) int PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj) { + if (Py_TYPE(obj) == &PyLong_Type) { + return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0); + } + PyObject *repr = PyObject_Repr(obj); if (repr == NULL) { return -1; From 1877543d03d323d581b5fc0f19eff501926ba151 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 00:04:50 +0200 Subject: [PATCH 091/247] gh-125196: Use PyUnicodeWriter for repr(structseq) (#125219) Replace the private _PyUnicodeWriter with the public PyUnicodeWriter. * Avoid temporary PyUnicode_DecodeUTF8(): call PyUnicodeWriter_WriteUTF8() instead. * Avoid temporary PyObject_Repr(): call PyUnicodeWriter_WriteRepr() instead. --- Objects/structseq.c | 65 +++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/Objects/structseq.c b/Objects/structseq.c index ee3dbf9d4c047a..6092742835400b 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -266,83 +266,66 @@ static PyObject * structseq_repr(PyStructSequence *obj) { PyTypeObject *typ = Py_TYPE(obj); - _PyUnicodeWriter writer; - /* Write "typename(" */ - PyObject *type_name = PyUnicode_DecodeUTF8(typ->tp_name, - strlen(typ->tp_name), - NULL); - if (type_name == NULL) { + // count 5 characters per item: "x=1, " + Py_ssize_t type_name_len = strlen(typ->tp_name); + Py_ssize_t prealloc = (type_name_len + 1 + + VISIBLE_SIZE(obj) * 5 + 1); + PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc); + if (writer == NULL) { return NULL; } - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; - /* count 5 characters per item: "x=1, " */ - writer.min_length = (PyUnicode_GET_LENGTH(type_name) + 1 - + VISIBLE_SIZE(obj) * 5 + 1); - - if (_PyUnicodeWriter_WriteStr(&writer, type_name) < 0) { - Py_DECREF(type_name); + // Write "typename(" + if (PyUnicodeWriter_WriteUTF8(writer, typ->tp_name, type_name_len) < 0) { goto error; } - Py_DECREF(type_name); - - if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) { + if (PyUnicodeWriter_WriteChar(writer, '(') < 0) { goto error; } for (Py_ssize_t i=0; i < VISIBLE_SIZE(obj); i++) { if (i > 0) { - /* Write ", " */ - if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { + // Write ", " + if (PyUnicodeWriter_WriteChar(writer, ',') < 0) { + goto error; + } + if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) { goto error; } } - /* Write "name=repr" */ + // Write name const char *name_utf8 = typ->tp_members[i].name; if (name_utf8 == NULL) { - PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %zd name is NULL" + PyErr_Format(PyExc_SystemError, + "In structseq_repr(), member %zd name is NULL" " for type %.500s", i, typ->tp_name); goto error; } - - PyObject *name = PyUnicode_DecodeUTF8(name_utf8, strlen(name_utf8), NULL); - if (name == NULL) { - goto error; - } - if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) { - Py_DECREF(name); + if (PyUnicodeWriter_WriteUTF8(writer, name_utf8, -1) < 0) { goto error; } - Py_DECREF(name); - if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { + // Write "=" + repr(value) + if (PyUnicodeWriter_WriteChar(writer, '=') < 0) { goto error; } - PyObject *value = PyStructSequence_GetItem((PyObject*)obj, i); assert(value != NULL); - PyObject *repr = PyObject_Repr(value); - if (repr == NULL) { - goto error; - } - if (_PyUnicodeWriter_WriteStr(&writer, repr) < 0) { - Py_DECREF(repr); + if (PyUnicodeWriter_WriteRepr(writer, value) < 0) { goto error; } - Py_DECREF(repr); } - if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) { + if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { goto error; } - return _PyUnicodeWriter_Finish(&writer); + return PyUnicodeWriter_Finish(writer); error: - _PyUnicodeWriter_Dealloc(&writer); + PyUnicodeWriter_Discard(writer); return NULL; } From c7d5d1d93b630e352abd9a0c93ea6d34c443f444 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Wed, 9 Oct 2024 23:30:56 +0100 Subject: [PATCH 092/247] gh-125140: Remove the current directory from sys.path when using pyrepl (GH-125212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pablo Galindo Co-authored-by: Łukasz Langa Co-authored-by: Peter Bierma --- Lib/site.py | 11 ++++++++--- .../2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst diff --git a/Lib/site.py b/Lib/site.py index b3194d79fb5ab8..07a6361fad44e5 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -503,9 +503,14 @@ def register_readline(): if PYTHON_BASIC_REPL: CAN_USE_PYREPL = False else: - import _pyrepl.readline - import _pyrepl.unix_console - from _pyrepl.main import CAN_USE_PYREPL + original_path = sys.path + sys.path = [p for p in original_path if p != ''] + try: + import _pyrepl.readline + import _pyrepl.unix_console + from _pyrepl.main import CAN_USE_PYREPL + finally: + sys.path = original_path except ImportError: return diff --git a/Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst b/Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst new file mode 100644 index 00000000000000..f4a49302372647 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst @@ -0,0 +1 @@ +Remove the current directory from ``sys.path`` when using PyREPL. From 9ad55e85d78c5338b1ad170e614345652bd1b651 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 10 Oct 2024 02:30:14 +0300 Subject: [PATCH 093/247] gh-124969: Skip the test for ALT_DIGITS also on iOS (#125177) Skip the locale.ALT_DIGITS test on all Apple platforms, not just macOS. --- Lib/test/test__locale.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py index 02d2acc6d1c417..e403c2a822788d 100644 --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -209,8 +209,8 @@ def test_alt_digits_nl_langinfo(self): with self.subTest(locale=loc): alt_digits = nl_langinfo(locale.ALT_DIGITS) self.assertIsInstance(alt_digits, tuple) - if count and not alt_digits and sys.platform == 'darwin': - self.skipTest(f'ALT_DIGITS is not set for locale {loc!r} on macOS') + if count and not alt_digits and support.is_apple: + self.skipTest(f'ALT_DIGITS is not set for locale {loc!r} on Apple platforms') self.assertEqual(len(alt_digits), count) for i in samples: self.assertEqual(alt_digits[i], samples[i]) From 1b2a5485f94ccbe43a45eb9990a5649ae3d2499e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 01:32:02 +0200 Subject: [PATCH 094/247] gh-125196: PyUnicodeWriter_Discard(NULL) does nothing (#125222) --- Doc/c-api/unicode.rst | 2 ++ Objects/listobject.c | 4 +--- Objects/unicodeobject.c | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index f5704cffa199a5..4daf9e9fdbf2f1 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1600,6 +1600,8 @@ object. Discard the internal Unicode buffer and destroy the writer instance. + If *writer* is ``NULL``, no operation is performed. + .. c:function:: int PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch) Write the single Unicode character *ch* into *writer*. diff --git a/Objects/listobject.c b/Objects/listobject.c index e7090f20001a39..930aefde325a7c 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -563,9 +563,7 @@ list_repr_impl(PyListObject *v) return PyUnicodeWriter_Finish(writer); error: - if (writer != NULL) { - PyUnicodeWriter_Discard(writer); - } + PyUnicodeWriter_Discard(writer); Py_ReprLeave((PyObject *)v); return NULL; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index a9b33248163880..93c1025b6a3cae 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13455,6 +13455,9 @@ PyUnicodeWriter_Create(Py_ssize_t length) void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) { + if (writer == NULL) { + return; + } _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer); PyMem_Free(writer); } From 942916378aa6a0946b1385c2c7ca6935620d710a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 01:37:14 +0200 Subject: [PATCH 095/247] gh-125196: Use PyUnicodeWriter for repr(contextvars.Token) (#125220) Replace the private _PyUnicodeWriter with the public PyUnicodeWriter. --- Lib/test/test_context.py | 8 ++++++++ Python/context.c | 39 +++++++++++---------------------------- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_context.py b/Lib/test/test_context.py index 255be306156c0b..b06b9df9f5b0b8 100644 --- a/Lib/test/test_context.py +++ b/Lib/test/test_context.py @@ -60,6 +60,14 @@ def test_context_var_repr_1(self): c.reset(t) self.assertIn(' used ', repr(t)) + @isolated_context + def test_token_repr_1(self): + c = contextvars.ContextVar('a') + tok = c.set(1) + self.assertRegex(repr(tok), + r"^ at 0x[0-9a-fA-F]+>$") + def test_context_subclassing_1(self): with self.assertRaisesRegex(TypeError, 'not an acceptable base type'): class MyContextVar(contextvars.ContextVar): diff --git a/Python/context.c b/Python/context.c index ddb03555f9e402..36e2677c398f59 100644 --- a/Python/context.c +++ b/Python/context.c @@ -1154,48 +1154,31 @@ token_tp_dealloc(PyContextToken *self) static PyObject * token_tp_repr(PyContextToken *self) { - _PyUnicodeWriter writer; - - _PyUnicodeWriter_Init(&writer); - - if (_PyUnicodeWriter_WriteASCIIString(&writer, "tok_used) { - if (_PyUnicodeWriter_WriteASCIIString(&writer, " used", 5) < 0) { + if (PyUnicodeWriter_WriteUTF8(writer, " used", 5) < 0) { goto error; } } - - if (_PyUnicodeWriter_WriteASCIIString(&writer, " var=", 5) < 0) { + if (PyUnicodeWriter_WriteUTF8(writer, " var=", 5) < 0) { goto error; } - - PyObject *var = PyObject_Repr((PyObject *)self->tok_var); - if (var == NULL) { + if (PyUnicodeWriter_WriteRepr(writer, (PyObject *)self->tok_var) < 0) { goto error; } - if (_PyUnicodeWriter_WriteStr(&writer, var) < 0) { - Py_DECREF(var); - goto error; - } - Py_DECREF(var); - - PyObject *addr = PyUnicode_FromFormat(" at %p>", self); - if (addr == NULL) { - goto error; - } - if (_PyUnicodeWriter_WriteStr(&writer, addr) < 0) { - Py_DECREF(addr); + if (PyUnicodeWriter_Format(writer, " at %p>", self) < 0) { goto error; } - Py_DECREF(addr); - - return _PyUnicodeWriter_Finish(&writer); + return PyUnicodeWriter_Finish(writer); error: - _PyUnicodeWriter_Dealloc(&writer); + PyUnicodeWriter_Discard(writer); return NULL; } From 99400930ac1d4e5e10a5ae30f8202d8bc2661e39 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 9 Oct 2024 19:44:03 -0400 Subject: [PATCH 096/247] gh-124872: Refine contextvars documentation (#124773) * Add definitions for "context", "current context", and "context management protocol". * Update related definitions to be consistent with the new definitions. * Restructure the documentation for the `contextvars.Context` class to prepare for adding context manager support, and for consistency with the definitions. * Use `testcode` and `testoutput` to test the `Context.run` example. * Expand the documentation for the `Py_CONTEXT_EVENT_ENTER` and `Py_CONTEXT_EVENT_EXIT` events to clarify and to prepare for planned changes. --- Doc/c-api/contextvars.rst | 20 ++-- Doc/glossary.rst | 40 ++++++-- Doc/library/contextvars.rst | 98 +++++++++++++------ Include/cpython/context.h | 23 +++-- ...-09-29-18-14-52.gh-issue-119333.7tinr0.rst | 3 + 5 files changed, 132 insertions(+), 52 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2024-09-29-18-14-52.gh-issue-119333.7tinr0.rst diff --git a/Doc/c-api/contextvars.rst b/Doc/c-api/contextvars.rst index 0de135b232aaaf..59e74ba1ac7022 100644 --- a/Doc/c-api/contextvars.rst +++ b/Doc/c-api/contextvars.rst @@ -122,18 +122,24 @@ Context object management functions: .. c:type:: PyContextEvent Enumeration of possible context object watcher events: - - ``Py_CONTEXT_EVENT_ENTER`` - - ``Py_CONTEXT_EVENT_EXIT`` + + - ``Py_CONTEXT_EVENT_ENTER``: A context has been entered, causing the + :term:`current context` to switch to it. The object passed to the watch + callback is the now-current :class:`contextvars.Context` object. Each + enter event will eventually have a corresponding exit event for the same + context object after any subsequently entered contexts have themselves been + exited. + - ``Py_CONTEXT_EVENT_EXIT``: A context is about to be exited, which will + cause the :term:`current context` to switch back to what it was before the + context was entered. The object passed to the watch callback is the + still-current :class:`contextvars.Context` object. .. versionadded:: 3.14 .. c:type:: int (*PyContext_WatchCallback)(PyContextEvent event, PyContext* ctx) - Type of a context object watcher callback function. - If *event* is ``Py_CONTEXT_EVENT_ENTER``, then the callback is invoked - after *ctx* has been set as the current context for the current thread. - Otherwise, the callback is invoked before the deactivation of *ctx* as the current context - and the restoration of the previous contex object for the current thread. + Context object watcher callback function. The object passed to the callback + is event-specific; see :c:type:`PyContextEvent` for details. If the callback returns with an exception set, it must return ``-1``; this exception will be printed as an unraisable exception using diff --git a/Doc/glossary.rst b/Doc/glossary.rst index cb7e0a2b89d037..1d407732eef576 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -265,19 +265,33 @@ Glossary advanced mathematical feature. If you're not aware of a need for them, it's almost certain you can safely ignore them. + context + This term has different meanings depending on where and how it is used. + Some common meanings: + + * The temporary state or environment established by a :term:`context + manager` via a :keyword:`with` statement. + * The collection of key­value bindings associated with a particular + :class:`contextvars.Context` object and accessed via + :class:`~contextvars.ContextVar` objects. Also see :term:`context + variable`. + * A :class:`contextvars.Context` object. Also see :term:`current + context`. + + context management protocol + The :meth:`~object.__enter__` and :meth:`~object.__exit__` methods called + by the :keyword:`with` statement. See :pep:`343`. + context manager - An object which controls the environment seen in a :keyword:`with` - statement by defining :meth:`~object.__enter__` and :meth:`~object.__exit__` methods. - See :pep:`343`. + An object which implements the :term:`context management protocol` and + controls the environment seen in a :keyword:`with` statement. See + :pep:`343`. context variable - A variable which can have different values depending on its context. - This is similar to Thread-Local Storage in which each execution - thread may have a different value for a variable. However, with context - variables, there may be several contexts in one execution thread and the - main usage for context variables is to keep track of variables in + A variable whose value depends on which context is the :term:`current + context`. Values are accessed via :class:`contextvars.ContextVar` + objects. Context variables are primarily used to isolate state between concurrent asynchronous tasks. - See :mod:`contextvars`. contiguous .. index:: C-contiguous, Fortran contiguous @@ -311,6 +325,14 @@ Glossary is used when necessary to distinguish this implementation from others such as Jython or IronPython. + current context + The :term:`context` (:class:`contextvars.Context` object) that is + currently used by :class:`~contextvars.ContextVar` objects to access (get + or set) the values of :term:`context variables `. Each + thread has its own current context. Frameworks for executing asynchronous + tasks (see :mod:`asyncio`) associate each task with a context which + becomes the current context whenever the task starts or resumes execution. + decorator A function returning another function, usually applied as a function transformation using the ``@wrapper`` syntax. Common examples for diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 2a79dfe8f81e26..2b1fb9fdd29cd8 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -144,51 +144,89 @@ Manual Context Management To get a copy of the current context use the :func:`~contextvars.copy_context` function. - Every thread will have a different top-level :class:`~contextvars.Context` - object. This means that a :class:`ContextVar` object behaves in a similar - fashion to :func:`threading.local` when values are assigned in different - threads. + Each thread has its own effective stack of :class:`!Context` objects. The + :term:`current context` is the :class:`!Context` object at the top of the + current thread's stack. All :class:`!Context` objects in the stacks are + considered to be *entered*. + + *Entering* a context, which can be done by calling its :meth:`~Context.run` + method, makes the context the current context by pushing it onto the top of + the current thread's context stack. + + *Exiting* from the current context, which can be done by returning from the + callback passed to the :meth:`~Context.run` method, restores the current + context to what it was before the context was entered by popping the context + off the top of the context stack. + + Since each thread has its own context stack, :class:`ContextVar` objects + behave in a similar fashion to :func:`threading.local` when values are + assigned in different threads. + + Attempting to enter an already entered context, including contexts entered in + other threads, raises a :exc:`RuntimeError`. + + After exiting a context, it can later be re-entered (from any thread). + + Any changes to :class:`ContextVar` values via the :meth:`ContextVar.set` + method are recorded in the current context. The :meth:`ContextVar.get` + method returns the value associated with the current context. Exiting a + context effectively reverts any changes made to context variables while the + context was entered (if needed, the values can be restored by re-entering the + context). Context implements the :class:`collections.abc.Mapping` interface. .. method:: run(callable, *args, **kwargs) - Execute ``callable(*args, **kwargs)`` code in the context object - the *run* method is called on. Return the result of the execution - or propagate an exception if one occurred. + Enters the Context, executes ``callable(*args, **kwargs)``, then exits the + Context. Returns *callable*'s return value, or propagates an exception if + one occurred. + + Example: + + .. testcode:: + + import contextvars - Any changes to any context variables that *callable* makes will - be contained in the context object:: + var = contextvars.ContextVar('var') + var.set('spam') + print(var.get()) # 'spam' - var = ContextVar('var') - var.set('spam') + ctx = contextvars.copy_context() - def main(): - # 'var' was set to 'spam' before - # calling 'copy_context()' and 'ctx.run(main)', so: - # var.get() == ctx[var] == 'spam' + def main(): + # 'var' was set to 'spam' before + # calling 'copy_context()' and 'ctx.run(main)', so: + print(var.get()) # 'spam' + print(ctx[var]) # 'spam' - var.set('ham') + var.set('ham') - # Now, after setting 'var' to 'ham': - # var.get() == ctx[var] == 'ham' + # Now, after setting 'var' to 'ham': + print(var.get()) # 'ham' + print(ctx[var]) # 'ham' - ctx = copy_context() + # Any changes that the 'main' function makes to 'var' + # will be contained in 'ctx'. + ctx.run(main) - # Any changes that the 'main' function makes to 'var' - # will be contained in 'ctx'. - ctx.run(main) + # The 'main()' function was run in the 'ctx' context, + # so changes to 'var' are contained in it: + print(ctx[var]) # 'ham' - # The 'main()' function was run in the 'ctx' context, - # so changes to 'var' are contained in it: - # ctx[var] == 'ham' + # However, outside of 'ctx', 'var' is still set to 'spam': + print(var.get()) # 'spam' - # However, outside of 'ctx', 'var' is still set to 'spam': - # var.get() == 'spam' + .. testoutput:: + :hide: - The method raises a :exc:`RuntimeError` when called on the same - context object from more than one OS thread, or when called - recursively. + spam + spam + spam + ham + ham + ham + spam .. method:: copy() diff --git a/Include/cpython/context.h b/Include/cpython/context.h index ec72966e82c6f9..d722b4d93134f7 100644 --- a/Include/cpython/context.h +++ b/Include/cpython/context.h @@ -28,15 +28,26 @@ PyAPI_FUNC(int) PyContext_Enter(PyObject *); PyAPI_FUNC(int) PyContext_Exit(PyObject *); typedef enum { - Py_CONTEXT_EVENT_ENTER, - Py_CONTEXT_EVENT_EXIT, + /* + * A context has been entered, causing the "current context" to switch to + * it. The object passed to the watch callback is the now-current + * contextvars.Context object. Each enter event will eventually have a + * corresponding exit event for the same context object after any + * subsequently entered contexts have themselves been exited. + */ + Py_CONTEXT_EVENT_ENTER, + /* + * A context is about to be exited, which will cause the "current context" + * to switch back to what it was before the context was entered. The + * object passed to the watch callback is the still-current + * contextvars.Context object. + */ + Py_CONTEXT_EVENT_EXIT, } PyContextEvent; /* - * Callback to be invoked when a context object is entered or exited. - * - * The callback is invoked with the event and a reference to - * the context after its entered and before its exited. + * Context object watcher callback function. The object passed to the callback + * is event-specific; see PyContextEvent for details. * * if the callback returns with an exception set, it must return -1. Otherwise * it should return 0 diff --git a/Misc/NEWS.d/next/Documentation/2024-09-29-18-14-52.gh-issue-119333.7tinr0.rst b/Misc/NEWS.d/next/Documentation/2024-09-29-18-14-52.gh-issue-119333.7tinr0.rst new file mode 100644 index 00000000000000..69a5c764d05a2e --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2024-09-29-18-14-52.gh-issue-119333.7tinr0.rst @@ -0,0 +1,3 @@ +Added definitions for :term:`context`, :term:`current context`, and +:term:`context management protocol`, updated related definitions to be +consistent, and expanded the documentation for :class:`contextvars.Context`. From 7a10cdec359750b5154490fa9e24475c90d05aab Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:34:55 +0100 Subject: [PATCH 097/247] Pin the doctest workflow to Ubuntu 22.04 (#125236) --- .github/workflows/reusable-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 4b021b3dc32f15..7755cb431bd301 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -95,7 +95,7 @@ jobs: # Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release doctest: name: 'Doctest' - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 timeout-minutes: 60 steps: - uses: actions/checkout@v4 From 1639d934b9180c278ac9c02be43cbb1beada494a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 12:11:06 +0200 Subject: [PATCH 098/247] gh-125196: Add a free list to PyUnicodeWriter (#125227) --- Include/internal/pycore_freelist_state.h | 2 ++ Objects/object.c | 1 + Objects/unicodeobject.c | 13 +++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 762c583ce94e9a..4e04cf431e0b31 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -20,6 +20,7 @@ extern "C" { # define Py_async_gen_asends_MAXFREELIST 80 # define Py_futureiters_MAXFREELIST 255 # define Py_object_stack_chunks_MAXFREELIST 4 +# define Py_unicode_writers_MAXFREELIST 1 // A generic freelist of either PyObjects or other data structures. struct _Py_freelist { @@ -44,6 +45,7 @@ struct _Py_freelists { struct _Py_freelist async_gen_asends; struct _Py_freelist futureiters; struct _Py_freelist object_stack_chunks; + struct _Py_freelist unicode_writers; }; #ifdef __cplusplus diff --git a/Objects/object.c b/Objects/object.c index 8d809158a6c1da..a97a900890320d 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -862,6 +862,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) // stacks during GC, so emptying the free-list is counterproductive. clear_freelist(&freelists->object_stack_chunks, 1, PyMem_RawFree); } + clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); } /* diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 93c1025b6a3cae..b94a74c2c688a9 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -46,6 +46,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_codecs.h" // _PyCodec_Lookup() #include "pycore_critical_section.h" // Py_*_CRITICAL_SECTION_SEQUENCE_FAST #include "pycore_format.h" // F_LJUST +#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // PyInterpreterState.fs_codec #include "pycore_long.h" // _PyLong_FormatWriter() @@ -13436,9 +13437,13 @@ PyUnicodeWriter_Create(Py_ssize_t length) } const size_t size = sizeof(_PyUnicodeWriter); - PyUnicodeWriter *pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size); + PyUnicodeWriter *pub_writer; + pub_writer = _Py_FREELIST_POP_MEM(unicode_writers); if (pub_writer == NULL) { - return (PyUnicodeWriter *)PyErr_NoMemory(); + pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size); + if (pub_writer == NULL) { + return (PyUnicodeWriter *)PyErr_NoMemory(); + } } _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer; @@ -13459,7 +13464,7 @@ void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) return; } _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer); - PyMem_Free(writer); + _Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free); } @@ -13881,7 +13886,7 @@ PyUnicodeWriter_Finish(PyUnicodeWriter *writer) { PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer); assert(((_PyUnicodeWriter*)writer)->buffer == NULL); - PyMem_Free(writer); + _Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free); return str; } From 82dfdc328779778295075d791ee30a0308fb9af4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 12:20:53 +0200 Subject: [PATCH 099/247] gh-125196: Use PyUnicodeWriter for repr(tuple) (#125242) --- Objects/tupleobject.c | 50 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 47134697918052..f3132e0933ac30 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -232,56 +232,54 @@ tuple_repr(PyObject *self) return res > 0 ? PyUnicode_FromString("(...)") : NULL; } - _PyUnicodeWriter writer; - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; + Py_ssize_t prealloc; if (n > 1) { - /* "(" + "1" + ", 2" * (len - 1) + ")" */ - writer.min_length = 1 + 1 + (2 + 1) * (n - 1) + 1; + // "(" + "1" + ", 2" * (len - 1) + ")" + prealloc = 1 + 1 + (2 + 1) * (n - 1) + 1; } else { - /* "(1,)" */ - writer.min_length = 4; + // "(1,)" + prealloc = 4; + } + PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc); + if (writer == NULL) { + goto error; } - if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) + if (PyUnicodeWriter_WriteChar(writer, '(') < 0) { goto error; + } /* Do repr() on each element. */ for (Py_ssize_t i = 0; i < n; ++i) { - PyObject *s; - if (i > 0) { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) + if (PyUnicodeWriter_WriteChar(writer, ',') < 0) { goto error; + } + if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) { + goto error; + } } - s = PyObject_Repr(v->ob_item[i]); - if (s == NULL) - goto error; - - if (_PyUnicodeWriter_WriteStr(&writer, s) < 0) { - Py_DECREF(s); + if (PyUnicodeWriter_WriteRepr(writer, v->ob_item[i]) < 0) { goto error; } - Py_DECREF(s); } - writer.overallocate = 0; - if (n > 1) { - if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) + if (n == 1) { + if (PyUnicodeWriter_WriteChar(writer, ',') < 0) { goto error; + } } - else { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ",)", 2) < 0) - goto error; + if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { + goto error; } Py_ReprLeave((PyObject *)v); - return _PyUnicodeWriter_Finish(&writer); + return PyUnicodeWriter_Finish(writer); error: - _PyUnicodeWriter_Dealloc(&writer); + PyUnicodeWriter_Discard(writer); Py_ReprLeave((PyObject *)v); return NULL; } From f9ae5d1cee2f8927a71cd4f1f66f10050a4f658a Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:21:12 +0100 Subject: [PATCH 100/247] gh-71784: [doc] add usage examples for traceback.TracebackException (#125189) Co-authored-by: Alex Waygood --- Doc/library/traceback.rst | 133 +++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 15 deletions(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 401e12be45f418..100a92b73d5497 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -8,11 +8,15 @@ -------------- -This module provides a standard interface to extract, format and print stack -traces of Python programs. It exactly mimics the behavior of the Python -interpreter when it prints a stack trace. This is useful when you want to print -stack traces under program control, such as in a "wrapper" around the -interpreter. +This module provides a standard interface to extract, format and print +stack traces of Python programs. It is more flexible than the +interpreter's default traceback display, and therefore makes it +possible to configure certain aspects of the output. Finally, +it contains a utility for capturing enough information about an +exception to print it later, without the need to save a reference +to the actual exception. Since exceptions can be the roots of large +objects graph, this utility can significantly improve +memory management. .. index:: pair: object; traceback @@ -29,7 +33,20 @@ which are assigned to the :attr:`~BaseException.__traceback__` field of Module :mod:`pdb` Interactive source code debugger for Python programs. -The module defines the following functions: +The module's API can be divided into two parts: + +* Module-level functions offering basic functionality, which are useful for interactive + inspection of exceptions and tracebacks. + +* :class:`TracebackException` class and its helper classes + :class:`StackSummary` and :class:`FrameSummary`. These offer both more + flexibility in the output generated and the ability to store the information + necessary for later formatting without holding references to actual exception + and traceback objects. + + +Module-Level Functions +---------------------- .. function:: print_tb(tb, limit=None, file=None) @@ -237,7 +254,6 @@ The module defines the following functions: .. versionadded:: 3.5 -The module also defines the following classes: :class:`!TracebackException` Objects ------------------------------------ @@ -245,12 +261,17 @@ The module also defines the following classes: .. versionadded:: 3.5 :class:`!TracebackException` objects are created from actual exceptions to -capture data for later printing in a lightweight fashion. +capture data for later printing. They offer a more lightweight method of +storing this information by avoiding holding references to +:ref:`traceback` and :ref:`frame` objects +In addition, they expose more options to configure the output compared to +the module-level functions described above. .. class:: TracebackException(exc_type, exc_value, exc_traceback, *, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10) - Capture an exception for later rendering. *limit*, *lookup_lines* and - *capture_locals* are as for the :class:`StackSummary` class. + Capture an exception for later rendering. The meaning of *limit*, + *lookup_lines* and *capture_locals* are as for the :class:`StackSummary` + class. If *compact* is true, only data that is required by :class:`!TracebackException`'s :meth:`format` method @@ -509,8 +530,8 @@ in a :ref:`traceback `. .. _traceback-example: -Traceback Examples ------------------- +Examples of Using the Module-Level Functions +-------------------------------------------- This simple example implements a basic read-eval-print loop, similar to (but less useful than) the standard Python interactive interpreter loop. For a more @@ -549,8 +570,7 @@ exception and traceback: try: lumberjack() - except IndexError: - exc = sys.exception() + except IndexError as exc: print("*** print_tb:") traceback.print_tb(exc.__traceback__, limit=1, file=sys.stdout) print("*** print_exception:") @@ -653,5 +673,88 @@ This last example demonstrates the final few formatting functions: [' File "spam.py", line 3, in \n spam.eggs()\n', ' File "eggs.py", line 42, in eggs\n return "bacon"\n'] >>> an_error = IndexError('tuple index out of range') - >>> traceback.format_exception_only(type(an_error), an_error) + >>> traceback.format_exception_only(an_error) ['IndexError: tuple index out of range\n'] + + +Examples of Using :class:`TracebackException` +--------------------------------------------- + +With the helper class, we have more options:: + + >>> import sys + >>> from traceback import TracebackException + >>> + >>> def lumberjack(): + ... bright_side_of_life() + ... + >>> def bright_side_of_life(): + ... t = "bright", "side", "of", "life" + ... return t[5] + ... + >>> try: + ... lumberjack() + ... except IndexError as e: + ... exc = e + ... + >>> try: + ... try: + ... lumberjack() + ... except: + ... 1/0 + ... except Exception as e: + ... chained_exc = e + ... + >>> # limit works as with the module-level functions + >>> TracebackException.from_exception(exc, limit=-2).print() + Traceback (most recent call last): + File "", line 6, in lumberjack + bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ + File "", line 10, in bright_side_of_life + return t[5] + ~^^^ + IndexError: tuple index out of range + + >>> # capture_locals adds local variables in frames + >>> TracebackException.from_exception(exc, limit=-2, capture_locals=True).print() + Traceback (most recent call last): + File "", line 6, in lumberjack + bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ + File "", line 10, in bright_side_of_life + return t[5] + ~^^^ + t = ("bright", "side", "of", "life") + IndexError: tuple index out of range + + >>> # The *chain* kwarg to print() controls whether chained + >>> # exceptions are displayed + >>> TracebackException.from_exception(chained_exc).print() + Traceback (most recent call last): + File "", line 4, in + lumberjack() + ~~~~~~~~~~^^ + File "", line 7, in lumberjack + bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ + File "", line 11, in bright_side_of_life + return t[5] + ~^^^ + IndexError: tuple index out of range + + During handling of the above exception, another exception occurred: + + Traceback (most recent call last): + File "", line 6, in + 1/0 + ~^~ + ZeroDivisionError: division by zero + + >>> TracebackException.from_exception(chained_exc).print(chain=False) + Traceback (most recent call last): + File "", line 6, in + 1/0 + ~^~ + ZeroDivisionError: division by zero + From e4cab488d4445e8444932f3bed1c329c0d9e5038 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Thu, 10 Oct 2024 21:39:53 +0900 Subject: [PATCH 101/247] gh-124471: Set name for unnamed reusable workflow (#124475) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- .github/workflows/reusable-change-detection.yml | 4 +--- .github/workflows/reusable-docs.yml | 2 +- .github/workflows/reusable-macos.yml | 2 ++ .github/workflows/reusable-tsan.yml | 2 ++ .github/workflows/reusable-ubuntu.yml | 2 ++ .github/workflows/reusable-wasi.yml | 2 ++ .github/workflows/reusable-windows-msi.yml | 2 +- .github/workflows/reusable-windows.yml | 2 ++ 8 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable-change-detection.yml b/.github/workflows/reusable-change-detection.yml index 6f599f75547ceb..5cd6fb39f1e12f 100644 --- a/.github/workflows/reusable-change-detection.yml +++ b/.github/workflows/reusable-change-detection.yml @@ -1,6 +1,4 @@ ---- - -name: Change detection +name: Reusable change detection on: # yamllint disable-line rule:truthy workflow_call: diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 7755cb431bd301..3809f24dcc977e 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -1,4 +1,4 @@ -name: Docs +name: Reusable Docs on: workflow_call: diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml index b4227545887ad1..b3a160fbbf8053 100644 --- a/.github/workflows/reusable-macos.yml +++ b/.github/workflows/reusable-macos.yml @@ -1,3 +1,5 @@ +name: Reusable macOS + on: workflow_call: inputs: diff --git a/.github/workflows/reusable-tsan.yml b/.github/workflows/reusable-tsan.yml index 27f4eacd86fd95..f4c976ca996410 100644 --- a/.github/workflows/reusable-tsan.yml +++ b/.github/workflows/reusable-tsan.yml @@ -1,3 +1,5 @@ +name: Reusable Thread Sanitizer + on: workflow_call: inputs: diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml index 769f1210de4d3c..0cf40ba8a9b03b 100644 --- a/.github/workflows/reusable-ubuntu.yml +++ b/.github/workflows/reusable-ubuntu.yml @@ -1,3 +1,5 @@ +name: Reusable Ubuntu + on: workflow_call: inputs: diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml index 1b1a68c0badc76..4c8137c958a312 100644 --- a/.github/workflows/reusable-wasi.yml +++ b/.github/workflows/reusable-wasi.yml @@ -1,3 +1,5 @@ +name: Reusable WASI + on: workflow_call: inputs: diff --git a/.github/workflows/reusable-windows-msi.yml b/.github/workflows/reusable-windows-msi.yml index fc34ab7c3eb1f2..abdb1a1982fef8 100644 --- a/.github/workflows/reusable-windows-msi.yml +++ b/.github/workflows/reusable-windows-msi.yml @@ -1,4 +1,4 @@ -name: TestsMSI +name: Reusable Windows MSI on: workflow_call: diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml index e9c3c8e05a801c..dcfc62d7f5d145 100644 --- a/.github/workflows/reusable-windows.yml +++ b/.github/workflows/reusable-windows.yml @@ -1,3 +1,5 @@ +name: Reusable Windows + on: workflow_call: inputs: From 87d7315ac57250046372b0d9ae4619ba619c8c87 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 10 Oct 2024 15:42:03 +0300 Subject: [PATCH 102/247] gh-125118: don't copy arbitrary values to _Bool in the struct module (GH-125169) memcopy'ing arbitrary values to _Bool variable triggers undefined behaviour. Avoid this. We assume that `false` is represented by all zero bytes. Credits to Alex Gaynor. Co-authored-by: Sam Gross Co-authored-by: Victor Stinner Co-authored-by: Petr Viktorin --- Lib/test/test_struct.py | 3 +++ .../Library/2024-10-09-07-09-00.gh-issue-125118.J9rQ1S.rst | 1 + Modules/_struct.c | 5 ++--- 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-09-07-09-00.gh-issue-125118.J9rQ1S.rst diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index e3193c7863fbae..04ec3ed0837c82 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -540,6 +540,9 @@ def __bool__(self): for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']: self.assertTrue(struct.unpack('>?', c)[0]) + self.assertTrue(struct.unpack(' Date: Thu, 10 Oct 2024 21:57:13 +0900 Subject: [PATCH 103/247] gh-124153: Simplify PyType_GetBaseByToken (GH-124488) --- Objects/typeobject.c | 123 +++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 80 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6484e8921f8122..5380633fa1149e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5269,11 +5269,10 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) static PyTypeObject * -get_base_by_token_recursive(PyTypeObject *type, void *token) +get_base_by_token_recursive(PyObject *bases, void *token) { - assert(PyType_GetSlot(type, Py_tp_token) != token); - PyObject *bases = lookup_tp_bases(type); assert(bases != NULL); + PyTypeObject *res = NULL; Py_ssize_t n = PyTuple_GET_SIZE(bases); for (Py_ssize_t i = 0; i < n; i++) { PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i)); @@ -5281,112 +5280,76 @@ get_base_by_token_recursive(PyTypeObject *type, void *token) continue; } if (((PyHeapTypeObject*)base)->ht_token == token) { - return base; + res = base; + break; } - base = get_base_by_token_recursive(base, token); + base = get_base_by_token_recursive(lookup_tp_bases(base), token); if (base != NULL) { - return base; + res = base; + break; } } - return NULL; + return res; // Prefer to return recursively from one place } -static inline PyTypeObject * -get_base_by_token_from_mro(PyTypeObject *type, void *token) +int +PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result) { - // Bypass lookup_tp_mro() as PyType_IsSubtype() does - PyObject *mro = type->tp_mro; - assert(mro != NULL); - assert(PyTuple_Check(mro)); - // mro_invoke() ensures that the type MRO cannot be empty. - assert(PyTuple_GET_SIZE(mro) >= 1); - // Also, the first item in the MRO is the type itself, which is supposed - // to be already checked by the caller. We skip it in the loop. - assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type); - assert(PyType_GetSlot(type, Py_tp_token) != token); - - Py_ssize_t n = PyTuple_GET_SIZE(mro); - for (Py_ssize_t i = 1; i < n; i++) { - PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(mro, i)); - if (!_PyType_HasFeature(base, Py_TPFLAGS_HEAPTYPE)) { - continue; - } - if (((PyHeapTypeObject*)base)->ht_token == token) { - return base; - } + if (result != NULL) { + *result = NULL; } - return NULL; -} -static int -check_base_by_token(PyTypeObject *type, void *token) { - // Chain the branches, which will be optimized exclusive here if (token == NULL) { PyErr_Format(PyExc_SystemError, "PyType_GetBaseByToken called with token=NULL"); return -1; } - else if (!PyType_Check(type)) { + if (!PyType_Check(type)) { PyErr_Format(PyExc_TypeError, "expected a type, got a '%T' object", type); return -1; } - else if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { - return 0; - } - else if (((PyHeapTypeObject*)type)->ht_token == token) { - return 1; - } - else if (type->tp_mro != NULL) { - // This will not be inlined - return get_base_by_token_from_mro(type, token) ? 1 : 0; - } - else { - return get_base_by_token_recursive(type, token) ? 1 : 0; - } -} -int -PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result) -{ - if (result == NULL) { - // If the `result` is checked only once here, the subsequent - // branches will become trivial to optimize. - return check_base_by_token(type, token); - } - if (token == NULL || !PyType_Check(type)) { - *result = NULL; - return check_base_by_token(type, token); - } - - // Chain the branches, which will be optimized exclusive here - PyTypeObject *base; if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { // No static type has a heaptype superclass, // which is ensured by type_ready_mro(). - *result = NULL; return 0; } - else if (((PyHeapTypeObject*)type)->ht_token == token) { - *result = (PyTypeObject *)Py_NewRef(type); + if (((PyHeapTypeObject*)type)->ht_token == token) { +found: + if (result != NULL) { + *result = (PyTypeObject *)Py_NewRef(type); + } return 1; } - else if (type->tp_mro != NULL) { - // Expect this to be inlined - base = get_base_by_token_from_mro(type, token); - } - else { - base = get_base_by_token_recursive(type, token); - } - if (base != NULL) { - *result = (PyTypeObject *)Py_NewRef(base); - return 1; - } - else { - *result = NULL; + PyObject *mro = type->tp_mro; // No lookup, following PyType_IsSubtype() + if (mro == NULL) { + PyTypeObject *base; + base = get_base_by_token_recursive(lookup_tp_bases(type), token); + if (base != NULL) { + // Copying the given type can cause a slowdown, + // unlike the overwrite below. + type = base; + goto found; + } return 0; } + // mro_invoke() ensures that the type MRO cannot be empty. + assert(PyTuple_GET_SIZE(mro) >= 1); + // Also, the first item in the MRO is the type itself, which + // we already checked above. We skip it in the loop. + assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type); + Py_ssize_t n = PyTuple_GET_SIZE(mro); + for (Py_ssize_t i = 1; i < n; i++) { + PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i); + if (_PyType_HasFeature(base, Py_TPFLAGS_HEAPTYPE) + && ((PyHeapTypeObject*)base)->ht_token == token) { + type = base; + goto found; + } + } + return 0; } From c914212474792312bb125211bae5719650fe2f58 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 15:33:00 +0200 Subject: [PATCH 104/247] gh-125196: Use PyUnicodeWriter for JSON encoder (#125249) Replace the private _PyUnicodeWriter with the public PyUnicodeWriter. --- Modules/_json.c | 87 ++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/Modules/_json.c b/Modules/_json.c index 9e29de0f22465f..ce0093ab431d05 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -86,11 +86,11 @@ encoder_dealloc(PyObject *self); static int encoder_clear(PyEncoderObject *self); static int -encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer, PyObject *seq, PyObject *newline_indent); +encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *seq, PyObject *newline_indent); static int -encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer, PyObject *obj, PyObject *newline_indent); +encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *obj, PyObject *newline_indent); static int -encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer, PyObject *dct, PyObject *newline_indent); +encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *dct, PyObject *newline_indent); static PyObject * _encoded_const(PyObject *obj); static void @@ -1268,38 +1268,39 @@ encoder_call(PyEncoderObject *self, PyObject *args, PyObject *kwds) { /* Python callable interface to encode_listencode_obj */ static char *kwlist[] = {"obj", "_current_indent_level", NULL}; - PyObject *obj, *result; + PyObject *obj; Py_ssize_t indent_level; - _PyUnicodeWriter writer; if (!PyArg_ParseTupleAndKeywords(args, kwds, "On:_iterencode", kwlist, - &obj, &indent_level)) + &obj, &indent_level)) return NULL; - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; + PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); + if (writer == NULL) { + return NULL; + } PyObject *newline_indent = NULL; if (self->indent != Py_None) { newline_indent = _create_newline_indent(self->indent, indent_level); if (newline_indent == NULL) { - _PyUnicodeWriter_Dealloc(&writer); + PyUnicodeWriter_Discard(writer); return NULL; } } - if (encoder_listencode_obj(self, &writer, obj, newline_indent)) { - _PyUnicodeWriter_Dealloc(&writer); + if (encoder_listencode_obj(self, writer, obj, newline_indent)) { + PyUnicodeWriter_Discard(writer); Py_XDECREF(newline_indent); return NULL; } Py_XDECREF(newline_indent); - result = PyTuple_New(1); - if (result == NULL || - PyTuple_SetItem(result, 0, _PyUnicodeWriter_Finish(&writer)) < 0) { - Py_XDECREF(result); + PyObject *str = PyUnicodeWriter_Finish(writer); + if (str == NULL) { return NULL; } + PyObject *result = PyTuple_Pack(1, str); + Py_DECREF(str); return result; } @@ -1370,16 +1371,16 @@ encoder_encode_string(PyEncoderObject *s, PyObject *obj) } static int -_steal_accumulate(_PyUnicodeWriter *writer, PyObject *stolen) +_steal_accumulate(PyUnicodeWriter *writer, PyObject *stolen) { /* Append stolen and then decrement its reference count */ - int rval = _PyUnicodeWriter_WriteStr(writer, stolen); + int rval = PyUnicodeWriter_WriteStr(writer, stolen); Py_DECREF(stolen); return rval; } static int -encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer, +encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *obj, PyObject *newline_indent) { /* Encode Python object obj to a JSON term */ @@ -1387,13 +1388,13 @@ encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer, int rv; if (obj == Py_None) { - return _PyUnicodeWriter_WriteASCIIString(writer, "null", 4); + return PyUnicodeWriter_WriteUTF8(writer, "null", 4); } else if (obj == Py_True) { - return _PyUnicodeWriter_WriteASCIIString(writer, "true", 4); + return PyUnicodeWriter_WriteUTF8(writer, "true", 4); } else if (obj == Py_False) { - return _PyUnicodeWriter_WriteASCIIString(writer, "false", 5); + return PyUnicodeWriter_WriteUTF8(writer, "false", 5); } else if (PyUnicode_Check(obj)) { PyObject *encoded = encoder_encode_string(s, obj); @@ -1402,6 +1403,10 @@ encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer, return _steal_accumulate(writer, encoded); } else if (PyLong_Check(obj)) { + if (PyLong_CheckExact(obj)) { + // Fast-path for exact integers + return PyUnicodeWriter_WriteRepr(writer, obj); + } PyObject *encoded = PyLong_Type.tp_repr(obj); if (encoded == NULL) return -1; @@ -1478,7 +1483,7 @@ encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer, } static int -encoder_encode_key_value(PyEncoderObject *s, _PyUnicodeWriter *writer, bool *first, +encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *first, PyObject *dct, PyObject *key, PyObject *value, PyObject *newline_indent, PyObject *item_separator) @@ -1518,7 +1523,7 @@ encoder_encode_key_value(PyEncoderObject *s, _PyUnicodeWriter *writer, bool *fir *first = false; } else { - if (_PyUnicodeWriter_WriteStr(writer, item_separator) < 0) { + if (PyUnicodeWriter_WriteStr(writer, item_separator) < 0) { Py_DECREF(keystr); return -1; } @@ -1533,7 +1538,7 @@ encoder_encode_key_value(PyEncoderObject *s, _PyUnicodeWriter *writer, bool *fir if (_steal_accumulate(writer, encoded) < 0) { return -1; } - if (_PyUnicodeWriter_WriteStr(writer, s->key_separator) < 0) { + if (PyUnicodeWriter_WriteStr(writer, s->key_separator) < 0) { return -1; } if (encoder_listencode_obj(s, writer, value, newline_indent) < 0) { @@ -1544,7 +1549,7 @@ encoder_encode_key_value(PyEncoderObject *s, _PyUnicodeWriter *writer, bool *fir } static int -encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer, +encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *dct, PyObject *newline_indent) { /* Encode Python dict dct a JSON term */ @@ -1555,8 +1560,10 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer, PyObject *new_newline_indent = NULL; PyObject *separator_indent = NULL; - if (PyDict_GET_SIZE(dct) == 0) /* Fast path */ - return _PyUnicodeWriter_WriteASCIIString(writer, "{}", 2); + if (PyDict_GET_SIZE(dct) == 0) { + /* Fast path */ + return PyUnicodeWriter_WriteUTF8(writer, "{}", 2); + } if (s->markers != Py_None) { int has_key; @@ -1574,8 +1581,9 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer, } } - if (_PyUnicodeWriter_WriteChar(writer, '{')) + if (PyUnicodeWriter_WriteChar(writer, '{')) { goto bail; + } PyObject *current_item_separator = s->item_separator; // borrowed reference if (s->indent != Py_None) { @@ -1589,7 +1597,7 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer, } // update item separator with a borrowed reference current_item_separator = separator_indent; - if (_PyUnicodeWriter_WriteStr(writer, new_newline_indent) < 0) { + if (PyUnicodeWriter_WriteStr(writer, new_newline_indent) < 0) { goto bail; } } @@ -1635,13 +1643,14 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer, Py_CLEAR(new_newline_indent); Py_CLEAR(separator_indent); - if (_PyUnicodeWriter_WriteStr(writer, newline_indent) < 0) { + if (PyUnicodeWriter_WriteStr(writer, newline_indent) < 0) { goto bail; } } - if (_PyUnicodeWriter_WriteChar(writer, '}')) + if (PyUnicodeWriter_WriteChar(writer, '}')) { goto bail; + } return 0; bail: @@ -1653,7 +1662,7 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer, } static int -encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer, +encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *seq, PyObject *newline_indent) { PyObject *ident = NULL; @@ -1668,7 +1677,7 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer, return -1; if (PySequence_Fast_GET_SIZE(s_fast) == 0) { Py_DECREF(s_fast); - return _PyUnicodeWriter_WriteASCIIString(writer, "[]", 2); + return PyUnicodeWriter_WriteUTF8(writer, "[]", 2); } if (s->markers != Py_None) { @@ -1687,8 +1696,9 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer, } } - if (_PyUnicodeWriter_WriteChar(writer, '[')) + if (PyUnicodeWriter_WriteChar(writer, '[')) { goto bail; + } PyObject *separator = s->item_separator; // borrowed reference if (s->indent != Py_None) { @@ -1697,7 +1707,7 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer, goto bail; } - if (_PyUnicodeWriter_WriteStr(writer, new_newline_indent) < 0) { + if (PyUnicodeWriter_WriteStr(writer, new_newline_indent) < 0) { goto bail; } @@ -1710,7 +1720,7 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer, for (i = 0; i < PySequence_Fast_GET_SIZE(s_fast); i++) { PyObject *obj = PySequence_Fast_GET_ITEM(s_fast, i); if (i) { - if (_PyUnicodeWriter_WriteStr(writer, separator) < 0) + if (PyUnicodeWriter_WriteStr(writer, separator) < 0) goto bail; } if (encoder_listencode_obj(s, writer, obj, new_newline_indent)) { @@ -1727,13 +1737,14 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer, if (s->indent != Py_None) { Py_CLEAR(new_newline_indent); Py_CLEAR(separator_indent); - if (_PyUnicodeWriter_WriteStr(writer, newline_indent) < 0) { + if (PyUnicodeWriter_WriteStr(writer, newline_indent) < 0) { goto bail; } } - if (_PyUnicodeWriter_WriteChar(writer, ']')) + if (PyUnicodeWriter_WriteChar(writer, ']')) { goto bail; + } Py_DECREF(s_fast); return 0; From 01fc3b34cc6994bc83b6540da3a8573e79dfbb56 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 10 Oct 2024 16:27:52 +0200 Subject: [PATCH 105/247] gh-124570: ctypes: Run some Structure tests on Union as well (GH-124976) - Move some Structure tests to test_structunion; use a common base test class + two subclasses to run them on Union too - Remove test_union for now as it's redundant Note: `test_simple_structs` & `test_simple_unions` are in the common file because they share `formats`. --- Lib/test/test_ctypes/test_structunion.py | 353 +++++++++++++++++++++++ Lib/test/test_ctypes/test_structures.py | 337 +--------------------- Lib/test/test_ctypes/test_unions.py | 35 --- 3 files changed, 368 insertions(+), 357 deletions(-) create mode 100644 Lib/test/test_ctypes/test_structunion.py delete mode 100644 Lib/test/test_ctypes/test_unions.py diff --git a/Lib/test/test_ctypes/test_structunion.py b/Lib/test/test_ctypes/test_structunion.py new file mode 100644 index 00000000000000..973ac3b2f1919d --- /dev/null +++ b/Lib/test/test_ctypes/test_structunion.py @@ -0,0 +1,353 @@ +"""Common tests for ctypes.Structure and ctypes.Union""" + +import unittest +from ctypes import (Structure, Union, POINTER, sizeof, alignment, + c_char, c_byte, c_ubyte, + c_short, c_ushort, c_int, c_uint, + c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double) +from ._support import (_CData, PyCStructType, UnionType, + Py_TPFLAGS_DISALLOW_INSTANTIATION, + Py_TPFLAGS_IMMUTABLETYPE) +from struct import calcsize + + +class StructUnionTestBase: + formats = {"c": c_char, + "b": c_byte, + "B": c_ubyte, + "h": c_short, + "H": c_ushort, + "i": c_int, + "I": c_uint, + "l": c_long, + "L": c_ulong, + "q": c_longlong, + "Q": c_ulonglong, + "f": c_float, + "d": c_double, + } + + def test_subclass(self): + class X(self.cls): + _fields_ = [("a", c_int)] + + class Y(X): + _fields_ = [("b", c_int)] + + class Z(X): + pass + + self.assertEqual(sizeof(X), sizeof(c_int)) + self.check_sizeof(Y, + struct_size=sizeof(c_int)*2, + union_size=sizeof(c_int)) + self.assertEqual(sizeof(Z), sizeof(c_int)) + self.assertEqual(X._fields_, [("a", c_int)]) + self.assertEqual(Y._fields_, [("b", c_int)]) + self.assertEqual(Z._fields_, [("a", c_int)]) + + def test_subclass_delayed(self): + class X(self.cls): + pass + self.assertEqual(sizeof(X), 0) + X._fields_ = [("a", c_int)] + + class Y(X): + pass + self.assertEqual(sizeof(Y), sizeof(X)) + Y._fields_ = [("b", c_int)] + + class Z(X): + pass + + self.assertEqual(sizeof(X), sizeof(c_int)) + self.check_sizeof(Y, + struct_size=sizeof(c_int)*2, + union_size=sizeof(c_int)) + self.assertEqual(sizeof(Z), sizeof(c_int)) + self.assertEqual(X._fields_, [("a", c_int)]) + self.assertEqual(Y._fields_, [("b", c_int)]) + self.assertEqual(Z._fields_, [("a", c_int)]) + + def test_inheritance_hierarchy(self): + self.assertEqual(self.cls.mro(), [self.cls, _CData, object]) + self.assertEqual(type(self.metacls), type) + + def test_type_flags(self): + for cls in self.cls, self.metacls: + with self.subTest(cls=cls): + self.assertTrue(cls.__flags__ & Py_TPFLAGS_IMMUTABLETYPE) + self.assertFalse(cls.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION) + + def test_metaclass_details(self): + # Abstract classes (whose metaclass __init__ was not called) can't be + # instantiated directly + NewClass = self.metacls.__new__(self.metacls, 'NewClass', + (self.cls,), {}) + for cls in self.cls, NewClass: + with self.subTest(cls=cls): + with self.assertRaisesRegex(TypeError, "abstract class"): + obj = cls() + + # Cannot call the metaclass __init__ more than once + class T(self.cls): + _fields_ = [("x", c_char), + ("y", c_char)] + with self.assertRaisesRegex(SystemError, "already initialized"): + self.metacls.__init__(T, 'ptr', (), {}) + + def test_alignment(self): + class X(self.cls): + _fields_ = [("x", c_char * 3)] + self.assertEqual(alignment(X), calcsize("s")) + self.assertEqual(sizeof(X), calcsize("3s")) + + class Y(self.cls): + _fields_ = [("x", c_char * 3), + ("y", c_int)] + self.assertEqual(alignment(Y), alignment(c_int)) + self.check_sizeof(Y, + struct_size=calcsize("3s i"), + union_size=max(calcsize("3s"), calcsize("i"))) + + class SI(self.cls): + _fields_ = [("a", X), + ("b", Y)] + self.assertEqual(alignment(SI), max(alignment(Y), alignment(X))) + self.check_sizeof(SI, + struct_size=calcsize("3s0i 3si 0i"), + union_size=max(calcsize("3s"), calcsize("i"))) + + class IS(self.cls): + _fields_ = [("b", Y), + ("a", X)] + + self.assertEqual(alignment(SI), max(alignment(X), alignment(Y))) + self.check_sizeof(IS, + struct_size=calcsize("3si 3s 0i"), + union_size=max(calcsize("3s"), calcsize("i"))) + + class XX(self.cls): + _fields_ = [("a", X), + ("b", X)] + self.assertEqual(alignment(XX), alignment(X)) + self.check_sizeof(XX, + struct_size=calcsize("3s 3s 0s"), + union_size=calcsize("3s")) + + def test_empty(self): + # I had problems with these + # + # Although these are pathological cases: Empty Structures! + class X(self.cls): + _fields_ = [] + + # Is this really the correct alignment, or should it be 0? + self.assertTrue(alignment(X) == 1) + self.assertTrue(sizeof(X) == 0) + + class XX(self.cls): + _fields_ = [("a", X), + ("b", X)] + + self.assertEqual(alignment(XX), 1) + self.assertEqual(sizeof(XX), 0) + + def test_fields(self): + # test the offset and size attributes of Structure/Union fields. + class X(self.cls): + _fields_ = [("x", c_int), + ("y", c_char)] + + self.assertEqual(X.x.offset, 0) + self.assertEqual(X.x.size, sizeof(c_int)) + + if self.cls == Structure: + self.assertEqual(X.y.offset, sizeof(c_int)) + else: + self.assertEqual(X.y.offset, 0) + self.assertEqual(X.y.size, sizeof(c_char)) + + # readonly + self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92) + self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92) + + # XXX Should we check nested data types also? + # offset is always relative to the class... + + def test_invalid_field_types(self): + class POINT(self.cls): + pass + self.assertRaises(TypeError, setattr, POINT, "_fields_", [("x", 1), ("y", 2)]) + + def test_invalid_name(self): + # field name must be string + def declare_with_name(name): + class S(self.cls): + _fields_ = [(name, c_int)] + + self.assertRaises(TypeError, declare_with_name, b"x") + + def test_intarray_fields(self): + class SomeInts(self.cls): + _fields_ = [("a", c_int * 4)] + + # can use tuple to initialize array (but not list!) + self.assertEqual(SomeInts((1, 2)).a[:], [1, 2, 0, 0]) + self.assertEqual(SomeInts((1, 2)).a[::], [1, 2, 0, 0]) + self.assertEqual(SomeInts((1, 2)).a[::-1], [0, 0, 2, 1]) + self.assertEqual(SomeInts((1, 2)).a[::2], [1, 0]) + self.assertEqual(SomeInts((1, 2)).a[1:5:6], [2]) + self.assertEqual(SomeInts((1, 2)).a[6:4:-1], []) + self.assertEqual(SomeInts((1, 2, 3, 4)).a[:], [1, 2, 3, 4]) + self.assertEqual(SomeInts((1, 2, 3, 4)).a[::], [1, 2, 3, 4]) + # too long + # XXX Should raise ValueError?, not RuntimeError + self.assertRaises(RuntimeError, SomeInts, (1, 2, 3, 4, 5)) + + def test_huge_field_name(self): + # issue12881: segfault with large structure field names + def create_class(length): + class S(self.cls): + _fields_ = [('x' * length, c_int)] + + for length in [10 ** i for i in range(0, 8)]: + try: + create_class(length) + except MemoryError: + # MemoryErrors are OK, we just don't want to segfault + pass + + def test_abstract_class(self): + class X(self.cls): + _abstract_ = "something" + with self.assertRaisesRegex(TypeError, r"^abstract class$"): + X() + + def test_methods(self): + self.assertIn("in_dll", dir(type(self.cls))) + self.assertIn("from_address", dir(type(self.cls))) + self.assertIn("in_dll", dir(type(self.cls))) + + +class StructureTestCase(unittest.TestCase, StructUnionTestBase): + cls = Structure + metacls = PyCStructType + + def test_metaclass_name(self): + self.assertEqual(self.metacls.__name__, "PyCStructType") + + def check_sizeof(self, cls, *, struct_size, union_size): + self.assertEqual(sizeof(cls), struct_size) + + def test_simple_structs(self): + for code, tp in self.formats.items(): + class X(Structure): + _fields_ = [("x", c_char), + ("y", tp)] + self.assertEqual((sizeof(X), code), + (calcsize("c%c0%c" % (code, code)), code)) + + +class UnionTestCase(unittest.TestCase, StructUnionTestBase): + cls = Union + metacls = UnionType + + def test_metaclass_name(self): + self.assertEqual(self.metacls.__name__, "UnionType") + + def check_sizeof(self, cls, *, struct_size, union_size): + self.assertEqual(sizeof(cls), union_size) + + def test_simple_unions(self): + for code, tp in self.formats.items(): + class X(Union): + _fields_ = [("x", c_char), + ("y", tp)] + self.assertEqual((sizeof(X), code), + (calcsize("%c" % (code)), code)) + + +class PointerMemberTestBase: + def test(self): + # a Structure/Union with a POINTER field + class S(self.cls): + _fields_ = [("array", POINTER(c_int))] + + s = S() + # We can assign arrays of the correct type + s.array = (c_int * 3)(1, 2, 3) + items = [s.array[i] for i in range(3)] + self.assertEqual(items, [1, 2, 3]) + + s.array[0] = 42 + + items = [s.array[i] for i in range(3)] + self.assertEqual(items, [42, 2, 3]) + + s.array[0] = 1 + + items = [s.array[i] for i in range(3)] + self.assertEqual(items, [1, 2, 3]) + +class PointerMemberTestCase_Struct(unittest.TestCase, PointerMemberTestBase): + cls = Structure + + def test_none_to_pointer_fields(self): + class S(self.cls): + _fields_ = [("x", c_int), + ("p", POINTER(c_int))] + + s = S() + s.x = 12345678 + s.p = None + self.assertEqual(s.x, 12345678) + +class PointerMemberTestCase_Union(unittest.TestCase, PointerMemberTestBase): + cls = Union + + def test_none_to_pointer_fields(self): + class S(self.cls): + _fields_ = [("x", c_int), + ("p", POINTER(c_int))] + + s = S() + s.x = 12345678 + s.p = None + self.assertFalse(s.p) # NULL pointers are falsy + + +class TestRecursiveBase: + def test_contains_itself(self): + class Recursive(self.cls): + pass + + try: + Recursive._fields_ = [("next", Recursive)] + except AttributeError as details: + self.assertIn("Structure or union cannot contain itself", + str(details)) + else: + self.fail("Structure or union cannot contain itself") + + + def test_vice_versa(self): + class First(self.cls): + pass + class Second(self.cls): + pass + + First._fields_ = [("second", Second)] + + try: + Second._fields_ = [("first", First)] + except AttributeError as details: + self.assertIn("_fields_ is final", str(details)) + else: + self.fail("AttributeError not raised") + +class TestRecursiveStructure(unittest.TestCase, TestRecursiveBase): + cls = Structure + +class TestRecursiveUnion(unittest.TestCase, TestRecursiveBase): + cls = Union diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 6cc09c8f2b5b59..0ec238e04b74cd 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -1,209 +1,24 @@ +"""Tests for ctypes.Structure + +Features common with Union should go in test_structunion.py instead. +""" + from platform import architecture as _architecture import struct import sys import unittest -from ctypes import (CDLL, Structure, Union, POINTER, sizeof, byref, alignment, +from ctypes import (CDLL, Structure, Union, POINTER, sizeof, byref, c_void_p, c_char, c_wchar, c_byte, c_ubyte, - c_uint8, c_uint16, c_uint32, - c_short, c_ushort, c_int, c_uint, - c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double) + c_uint8, c_uint16, c_uint32, c_int, c_uint, + c_long, c_ulong, c_longlong, c_float, c_double) from ctypes.util import find_library -from struct import calcsize from collections import namedtuple from test import support from test.support import import_helper _ctypes_test = import_helper.import_module("_ctypes_test") -from ._support import (_CData, PyCStructType, Py_TPFLAGS_DISALLOW_INSTANTIATION, - Py_TPFLAGS_IMMUTABLETYPE) - - -class SubclassesTest(unittest.TestCase): - def test_subclass(self): - class X(Structure): - _fields_ = [("a", c_int)] - - class Y(X): - _fields_ = [("b", c_int)] - - class Z(X): - pass - - self.assertEqual(sizeof(X), sizeof(c_int)) - self.assertEqual(sizeof(Y), sizeof(c_int)*2) - self.assertEqual(sizeof(Z), sizeof(c_int)) - self.assertEqual(X._fields_, [("a", c_int)]) - self.assertEqual(Y._fields_, [("b", c_int)]) - self.assertEqual(Z._fields_, [("a", c_int)]) - - def test_subclass_delayed(self): - class X(Structure): - pass - self.assertEqual(sizeof(X), 0) - X._fields_ = [("a", c_int)] - - class Y(X): - pass - self.assertEqual(sizeof(Y), sizeof(X)) - Y._fields_ = [("b", c_int)] - - class Z(X): - pass - - self.assertEqual(sizeof(X), sizeof(c_int)) - self.assertEqual(sizeof(Y), sizeof(c_int)*2) - self.assertEqual(sizeof(Z), sizeof(c_int)) - self.assertEqual(X._fields_, [("a", c_int)]) - self.assertEqual(Y._fields_, [("b", c_int)]) - self.assertEqual(Z._fields_, [("a", c_int)]) class StructureTestCase(unittest.TestCase): - formats = {"c": c_char, - "b": c_byte, - "B": c_ubyte, - "h": c_short, - "H": c_ushort, - "i": c_int, - "I": c_uint, - "l": c_long, - "L": c_ulong, - "q": c_longlong, - "Q": c_ulonglong, - "f": c_float, - "d": c_double, - } - - def test_inheritance_hierarchy(self): - self.assertEqual(Structure.mro(), [Structure, _CData, object]) - - self.assertEqual(PyCStructType.__name__, "PyCStructType") - self.assertEqual(type(PyCStructType), type) - - - def test_type_flags(self): - for cls in Structure, PyCStructType: - with self.subTest(cls=cls): - self.assertTrue(Structure.__flags__ & Py_TPFLAGS_IMMUTABLETYPE) - self.assertFalse(Structure.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION) - - def test_metaclass_details(self): - # Abstract classes (whose metaclass __init__ was not called) can't be - # instantiated directly - NewStructure = PyCStructType.__new__(PyCStructType, 'NewStructure', - (Structure,), {}) - for cls in Structure, NewStructure: - with self.subTest(cls=cls): - with self.assertRaisesRegex(TypeError, "abstract class"): - obj = cls() - - # Cannot call the metaclass __init__ more than once - class T(Structure): - _fields_ = [("x", c_char), - ("y", c_char)] - with self.assertRaisesRegex(SystemError, "already initialized"): - PyCStructType.__init__(T, 'ptr', (), {}) - - def test_simple_structs(self): - for code, tp in self.formats.items(): - class X(Structure): - _fields_ = [("x", c_char), - ("y", tp)] - self.assertEqual((sizeof(X), code), - (calcsize("c%c0%c" % (code, code)), code)) - - def test_unions(self): - for code, tp in self.formats.items(): - class X(Union): - _fields_ = [("x", c_char), - ("y", tp)] - self.assertEqual((sizeof(X), code), - (calcsize("%c" % (code)), code)) - - def test_struct_alignment(self): - class X(Structure): - _fields_ = [("x", c_char * 3)] - self.assertEqual(alignment(X), calcsize("s")) - self.assertEqual(sizeof(X), calcsize("3s")) - - class Y(Structure): - _fields_ = [("x", c_char * 3), - ("y", c_int)] - self.assertEqual(alignment(Y), alignment(c_int)) - self.assertEqual(sizeof(Y), calcsize("3si")) - - class SI(Structure): - _fields_ = [("a", X), - ("b", Y)] - self.assertEqual(alignment(SI), max(alignment(Y), alignment(X))) - self.assertEqual(sizeof(SI), calcsize("3s0i 3si 0i")) - - class IS(Structure): - _fields_ = [("b", Y), - ("a", X)] - - self.assertEqual(alignment(SI), max(alignment(X), alignment(Y))) - self.assertEqual(sizeof(IS), calcsize("3si 3s 0i")) - - class XX(Structure): - _fields_ = [("a", X), - ("b", X)] - self.assertEqual(alignment(XX), alignment(X)) - self.assertEqual(sizeof(XX), calcsize("3s 3s 0s")) - - def test_empty(self): - # I had problems with these - # - # Although these are pathological cases: Empty Structures! - class X(Structure): - _fields_ = [] - - class Y(Union): - _fields_ = [] - - # Is this really the correct alignment, or should it be 0? - self.assertTrue(alignment(X) == alignment(Y) == 1) - self.assertTrue(sizeof(X) == sizeof(Y) == 0) - - class XX(Structure): - _fields_ = [("a", X), - ("b", X)] - - self.assertEqual(alignment(XX), 1) - self.assertEqual(sizeof(XX), 0) - - def test_fields(self): - # test the offset and size attributes of Structure/Union fields. - class X(Structure): - _fields_ = [("x", c_int), - ("y", c_char)] - - self.assertEqual(X.x.offset, 0) - self.assertEqual(X.x.size, sizeof(c_int)) - - self.assertEqual(X.y.offset, sizeof(c_int)) - self.assertEqual(X.y.size, sizeof(c_char)) - - # readonly - self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92) - self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92) - - class X(Union): - _fields_ = [("x", c_int), - ("y", c_char)] - - self.assertEqual(X.x.offset, 0) - self.assertEqual(X.x.size, sizeof(c_int)) - - self.assertEqual(X.y.offset, 0) - self.assertEqual(X.y.size, sizeof(c_char)) - - # readonly - self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92) - self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92) - - # XXX Should we check nested data types also? - # offset is always relative to the class... - def test_packed(self): class X(Structure): _fields_ = [("a", c_byte), @@ -290,36 +105,6 @@ class POINT(Structure): pt = POINT(y=2, x=1) self.assertEqual((pt.x, pt.y), (1, 2)) - def test_invalid_field_types(self): - class POINT(Structure): - pass - self.assertRaises(TypeError, setattr, POINT, "_fields_", [("x", 1), ("y", 2)]) - - def test_invalid_name(self): - # field name must be string - def declare_with_name(name): - class S(Structure): - _fields_ = [(name, c_int)] - - self.assertRaises(TypeError, declare_with_name, b"x") - - def test_intarray_fields(self): - class SomeInts(Structure): - _fields_ = [("a", c_int * 4)] - - # can use tuple to initialize array (but not list!) - self.assertEqual(SomeInts((1, 2)).a[:], [1, 2, 0, 0]) - self.assertEqual(SomeInts((1, 2)).a[::], [1, 2, 0, 0]) - self.assertEqual(SomeInts((1, 2)).a[::-1], [0, 0, 2, 1]) - self.assertEqual(SomeInts((1, 2)).a[::2], [1, 0]) - self.assertEqual(SomeInts((1, 2)).a[1:5:6], [2]) - self.assertEqual(SomeInts((1, 2)).a[6:4:-1], []) - self.assertEqual(SomeInts((1, 2, 3, 4)).a[:], [1, 2, 3, 4]) - self.assertEqual(SomeInts((1, 2, 3, 4)).a[::], [1, 2, 3, 4]) - # too long - # XXX Should raise ValueError?, not RuntimeError - self.assertRaises(RuntimeError, SomeInts, (1, 2, 3, 4, 5)) - def test_nested_initializers(self): # test initializing nested structures class Phone(Structure): @@ -374,37 +159,12 @@ class Person(Structure): self.assertEqual(msg, "(Phone) TypeError: too many initializers") - def test_huge_field_name(self): - # issue12881: segfault with large structure field names - def create_class(length): - class S(Structure): - _fields_ = [('x' * length, c_int)] - - for length in [10 ** i for i in range(0, 8)]: - try: - create_class(length) - except MemoryError: - # MemoryErrors are OK, we just don't want to segfault - pass - def get_except(self, func, *args): try: func(*args) except Exception as detail: return detail.__class__, str(detail) - def test_abstract_class(self): - class X(Structure): - _abstract_ = "something" - # try 'X()' - cls, msg = self.get_except(eval, "X()", locals()) - self.assertEqual((cls, msg), (TypeError, "abstract class")) - - def test_methods(self): - self.assertIn("in_dll", dir(type(Structure))) - self.assertIn("from_address", dir(type(Structure))) - self.assertIn("in_dll", dir(type(Structure))) - def test_positional_args(self): # see also http://bugs.python.org/issue5042 class W(Structure): @@ -507,6 +267,8 @@ class X(Structure): self.assertEqual(s.second, got.second) def _test_issue18060(self, Vector): + # Regression tests for gh-62260 + # The call to atan2() should succeed if the # class fields were correctly cloned in the # subclasses. Otherwise, it will segfault. @@ -698,6 +460,7 @@ class Test3E(Structure): self.assertEqual(result.data[i], float(i+1)) def test_38368(self): + # Regression test for gh-82549 class U(Union): _fields_ = [ ('f1', c_uint8 * 16), @@ -719,9 +482,9 @@ class U(Union): self.assertEqual(f2, [0x4567, 0x0123, 0xcdef, 0x89ab, 0x3210, 0x7654, 0xba98, 0xfedc]) - @unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576') + @unittest.skipIf(True, 'Test disabled for now - see gh-60779/gh-60780') def test_union_by_value(self): - # See bpo-16575 + # See gh-60779 # These should mirror the structures in Modules/_ctypes/_ctypes_test.c @@ -800,9 +563,9 @@ class Test5(Structure): self.assertEqual(test5.nested.an_int, 0) self.assertEqual(test5.another_int, 0) - @unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576') + @unittest.skipIf(True, 'Test disabled for now - see gh-60779/gh-60780') def test_bitfield_by_value(self): - # See bpo-16576 + # See gh-60780 # These should mirror the structures in Modules/_ctypes/_ctypes_test.c @@ -882,75 +645,5 @@ class Test8(Union): 'a union by value, which is unsupported.') -class PointerMemberTestCase(unittest.TestCase): - - def test(self): - # a Structure with a POINTER field - class S(Structure): - _fields_ = [("array", POINTER(c_int))] - - s = S() - # We can assign arrays of the correct type - s.array = (c_int * 3)(1, 2, 3) - items = [s.array[i] for i in range(3)] - self.assertEqual(items, [1, 2, 3]) - - # The following are bugs, but are included here because the unittests - # also describe the current behaviour. - # - # This fails with SystemError: bad arg to internal function - # or with IndexError (with a patch I have) - - s.array[0] = 42 - - items = [s.array[i] for i in range(3)] - self.assertEqual(items, [42, 2, 3]) - - s.array[0] = 1 - - items = [s.array[i] for i in range(3)] - self.assertEqual(items, [1, 2, 3]) - - def test_none_to_pointer_fields(self): - class S(Structure): - _fields_ = [("x", c_int), - ("p", POINTER(c_int))] - - s = S() - s.x = 12345678 - s.p = None - self.assertEqual(s.x, 12345678) - - -class TestRecursiveStructure(unittest.TestCase): - def test_contains_itself(self): - class Recursive(Structure): - pass - - try: - Recursive._fields_ = [("next", Recursive)] - except AttributeError as details: - self.assertIn("Structure or union cannot contain itself", - str(details)) - else: - self.fail("Structure or union cannot contain itself") - - - def test_vice_versa(self): - class First(Structure): - pass - class Second(Structure): - pass - - First._fields_ = [("second", Second)] - - try: - Second._fields_ = [("first", First)] - except AttributeError as details: - self.assertIn("_fields_ is final", str(details)) - else: - self.fail("AttributeError not raised") - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_unions.py b/Lib/test/test_ctypes/test_unions.py deleted file mode 100644 index e2dff0f22a9213..00000000000000 --- a/Lib/test/test_ctypes/test_unions.py +++ /dev/null @@ -1,35 +0,0 @@ -import unittest -from ctypes import Union, c_char -from ._support import (_CData, UnionType, Py_TPFLAGS_DISALLOW_INSTANTIATION, - Py_TPFLAGS_IMMUTABLETYPE) - - -class ArrayTestCase(unittest.TestCase): - def test_inheritance_hierarchy(self): - self.assertEqual(Union.mro(), [Union, _CData, object]) - - self.assertEqual(UnionType.__name__, "UnionType") - self.assertEqual(type(UnionType), type) - - def test_type_flags(self): - for cls in Union, UnionType: - with self.subTest(cls=Union): - self.assertTrue(Union.__flags__ & Py_TPFLAGS_IMMUTABLETYPE) - self.assertFalse(Union.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION) - - def test_metaclass_details(self): - # Abstract classes (whose metaclass __init__ was not called) can't be - # instantiated directly - NewUnion = UnionType.__new__(UnionType, 'NewUnion', - (Union,), {}) - for cls in Union, NewUnion: - with self.subTest(cls=cls): - with self.assertRaisesRegex(TypeError, "abstract class"): - obj = cls() - - # Cannot call the metaclass __init__ more than once - class T(Union): - _fields_ = [("x", c_char), - ("y", c_char)] - with self.assertRaisesRegex(SystemError, "already initialized"): - UnionType.__init__(T, 'ptr', (), {}) From c9014374c50d6ef64786d3e7d9c7e99053d5c9e2 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 10 Oct 2024 18:19:08 +0100 Subject: [PATCH 106/247] GH-125174: Make immortal objects more robust, following design from PEP 683 (GH-125251) --- .../pycore_global_objects_fini_generated.h | 2 +- Include/internal/pycore_object.h | 34 ++++----------- Include/object.h | 2 +- Include/refcount.h | 42 ++++++++++--------- Lib/test/test_builtin.py | 4 +- ...-10-10-12-04-56.gh-issue-125174._8h6T7.rst | 4 ++ Modules/_asynciomodule.c | 2 +- Objects/bytesobject.c | 6 +-- Objects/dictobject.c | 10 +++-- Objects/object.c | 2 +- Objects/structseq.c | 2 +- Objects/typeobject.c | 8 ++-- Python/bytecodes.c | 4 +- Python/executor_cases.c.h | 4 +- Python/generated_cases.c.h | 4 +- Python/import.c | 2 +- Tools/cases_generator/analyzer.py | 1 - 17 files changed, 61 insertions(+), 72 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 3140a75a47c5ee..de68ef93257234 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -11,7 +11,7 @@ extern "C" { #ifdef Py_DEBUG static inline void _PyStaticObject_CheckRefcnt(PyObject *obj) { - if (Py_REFCNT(obj) < _Py_IMMORTAL_REFCNT) { + if (!_Py_IsImmortal(obj)) { fprintf(stderr, "Immortal Object has less refcnt than expected.\n"); _PyObject_Dump(obj); } diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 0af13b1bcda20b..8832692d03c29e 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -16,9 +16,6 @@ extern "C" { #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_uniqueid.h" // _PyType_IncrefSlow - -#define _Py_IMMORTAL_REFCNT_LOOSE ((_Py_IMMORTAL_REFCNT >> 1) + 1) - // This value is added to `ob_ref_shared` for objects that use deferred // reference counting so that they are not immediately deallocated when the // non-deferred reference count drops to zero. @@ -27,25 +24,8 @@ extern "C" { // `ob_ref_shared` are used for flags. #define _Py_REF_DEFERRED (PY_SSIZE_T_MAX / 8) -// gh-121528, gh-118997: Similar to _Py_IsImmortal() but be more loose when -// comparing the reference count to stay compatible with C extensions built -// with the stable ABI 3.11 or older. Such extensions implement INCREF/DECREF -// as refcnt++ and refcnt-- without taking in account immortal objects. For -// example, the reference count of an immortal object can change from -// _Py_IMMORTAL_REFCNT to _Py_IMMORTAL_REFCNT+1 (INCREF) or -// _Py_IMMORTAL_REFCNT-1 (DECREF). -// -// This function should only be used in assertions. Otherwise, _Py_IsImmortal() -// must be used instead. -static inline int _Py_IsImmortalLoose(PyObject *op) -{ -#if defined(Py_GIL_DISABLED) - return _Py_IsImmortal(op); -#else - return (op->ob_refcnt >= _Py_IMMORTAL_REFCNT_LOOSE); -#endif -} -#define _Py_IsImmortalLoose(op) _Py_IsImmortalLoose(_PyObject_CAST(op)) +/* For backwards compatibility -- Do not use this */ +#define _Py_IsImmortalLoose(op) _Py_IsImmortal /* Check if an object is consistent. For example, ensure that the reference @@ -97,7 +77,7 @@ PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *); #else #define _PyObject_HEAD_INIT(type) \ { \ - .ob_refcnt = _Py_IMMORTAL_REFCNT, \ + .ob_refcnt = _Py_IMMORTAL_INITIAL_REFCNT, \ .ob_type = (type) \ } #endif @@ -184,7 +164,7 @@ PyAPI_FUNC(void) _Py_SetImmortalUntracked(PyObject *op); static inline void _Py_SetMortal(PyObject *op, Py_ssize_t refcnt) { if (op) { - assert(_Py_IsImmortalLoose(op)); + assert(_Py_IsImmortal(op)); #ifdef Py_GIL_DISABLED op->ob_tid = _Py_UNOWNED_TID; op->ob_ref_local = 0; @@ -316,7 +296,7 @@ static inline void _Py_INCREF_TYPE(PyTypeObject *type) { if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { - assert(_Py_IsImmortalLoose(type)); + assert(_Py_IsImmortal(type)); _Py_INCREF_IMMORTAL_STAT_INC(); return; } @@ -357,7 +337,7 @@ static inline void _Py_DECREF_TYPE(PyTypeObject *type) { if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { - assert(_Py_IsImmortalLoose(type)); + assert(_Py_IsImmortal(type)); _Py_DECREF_IMMORTAL_STAT_INC(); return; } @@ -393,7 +373,7 @@ _PyObject_Init(PyObject *op, PyTypeObject *typeobj) { assert(op != NULL); Py_SET_TYPE(op, typeobj); - assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || _Py_IsImmortalLoose(typeobj)); + assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || _Py_IsImmortal(typeobj)); _Py_INCREF_TYPE(typeobj); _Py_NewReference(op); } diff --git a/Include/object.h b/Include/object.h index 418f2196062df7..5be4dedadc20eb 100644 --- a/Include/object.h +++ b/Include/object.h @@ -81,7 +81,7 @@ whose size is determined when the object is allocated. #else #define PyObject_HEAD_INIT(type) \ { \ - { _Py_IMMORTAL_REFCNT }, \ + { _Py_IMMORTAL_INITIAL_REFCNT }, \ (type) \ }, #endif diff --git a/Include/refcount.h b/Include/refcount.h index 9a4e15065ecab8..141cbd34dd72e6 100644 --- a/Include/refcount.h +++ b/Include/refcount.h @@ -21,25 +21,30 @@ cleanup during runtime finalization. #if SIZEOF_VOID_P > 4 /* -In 64+ bit systems, an object will be marked as immortal by setting all of the -lower 32 bits of the reference count field, which is equal to: 0xFFFFFFFF +In 64+ bit systems, any object whose 32 bit reference count is >= 2**31 +will be treated as immortal. Using the lower 32 bits makes the value backwards compatible by allowing C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely -increase and decrease the objects reference count. The object would lose its -immortality, but the execution would still be correct. +increase and decrease the objects reference count. + +In order to offer sufficient resilience to C extensions using the stable ABI +compiled against 3.11 or earlier, we set the initial value near the +middle of the range (2**31, 2**32). That way the the refcount can be +off by ~1 billion without affecting immortality. Reference count increases will use saturated arithmetic, taking advantage of having all the lower 32 bits set, which will avoid the reference count to go beyond the refcount limit. Immortality checks for reference count decreases will be done by checking the bit sign flag in the lower 32 bits. + */ -#define _Py_IMMORTAL_REFCNT _Py_CAST(Py_ssize_t, UINT_MAX) +#define _Py_IMMORTAL_INITIAL_REFCNT ((Py_ssize_t)(3UL << 30)) #else /* -In 32 bit systems, an object will be marked as immortal by setting all of the -lower 30 bits of the reference count field, which is equal to: 0x3FFFFFFF +In 32 bit systems, an object will be treated as immortal if its reference +count equals or exceeds _Py_IMMORTAL_MINIMUM_REFCNT (2**30). Using the lower 30 bits makes the value backwards compatible by allowing C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely @@ -47,9 +52,10 @@ increase and decrease the objects reference count. The object would lose its immortality, but the execution would still be correct. Reference count increases and decreases will first go through an immortality -check by comparing the reference count field to the immortality reference count. +check by comparing the reference count field to the minimum immortality refcount. */ -#define _Py_IMMORTAL_REFCNT _Py_CAST(Py_ssize_t, UINT_MAX >> 2) +#define _Py_IMMORTAL_INITIAL_REFCNT ((Py_ssize_t)(3L << 29)) +#define _Py_IMMORTAL_MINIMUM_REFCNT ((Py_ssize_t)(1L << 30)) #endif // Py_GIL_DISABLED builds indicate immortal objects using `ob_ref_local`, which is @@ -90,7 +96,7 @@ PyAPI_FUNC(Py_ssize_t) Py_REFCNT(PyObject *ob); #else uint32_t local = _Py_atomic_load_uint32_relaxed(&ob->ob_ref_local); if (local == _Py_IMMORTAL_REFCNT_LOCAL) { - return _Py_IMMORTAL_REFCNT; + return _Py_IMMORTAL_INITIAL_REFCNT; } Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&ob->ob_ref_shared); return _Py_STATIC_CAST(Py_ssize_t, local) + @@ -109,9 +115,9 @@ static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op) return (_Py_atomic_load_uint32_relaxed(&op->ob_ref_local) == _Py_IMMORTAL_REFCNT_LOCAL); #elif SIZEOF_VOID_P > 4 - return (_Py_CAST(PY_INT32_T, op->ob_refcnt) < 0); + return _Py_CAST(PY_INT32_T, op->ob_refcnt) < 0; #else - return (op->ob_refcnt == _Py_IMMORTAL_REFCNT); + return op->ob_refcnt >= _Py_IMMORTAL_MINIMUM_REFCNT; #endif } #define _Py_IsImmortal(op) _Py_IsImmortal(_PyObject_CAST(op)) @@ -236,7 +242,7 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) uint32_t new_local = local + 1; if (new_local == 0) { _Py_INCREF_IMMORTAL_STAT_INC(); - // local is equal to _Py_IMMORTAL_REFCNT: do nothing + // local is equal to _Py_IMMORTAL_REFCNT_LOCAL: do nothing return; } if (_Py_IsOwnedByCurrentThread(op)) { @@ -246,18 +252,14 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) _Py_atomic_add_ssize(&op->ob_ref_shared, (1 << _Py_REF_SHARED_SHIFT)); } #elif SIZEOF_VOID_P > 4 - // Portable saturated add, branching on the carry flag and set low bits PY_UINT32_T cur_refcnt = op->ob_refcnt_split[PY_BIG_ENDIAN]; - PY_UINT32_T new_refcnt = cur_refcnt + 1; - if (new_refcnt == 0) { + if (((int32_t)cur_refcnt) < 0) { + // the object is immortal _Py_INCREF_IMMORTAL_STAT_INC(); - // cur_refcnt is equal to _Py_IMMORTAL_REFCNT: the object is immortal, - // do nothing return; } - op->ob_refcnt_split[PY_BIG_ENDIAN] = new_refcnt; + op->ob_refcnt_split[PY_BIG_ENDIAN] = cur_refcnt + 1; #else - // Explicitly check immortality against the immortal value if (_Py_IsImmortal(op)) { _Py_INCREF_IMMORTAL_STAT_INC(); return; diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index d884f54940b471..eb5906f8944c8e 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -2574,9 +2574,9 @@ def __del__(self): class ImmortalTests(unittest.TestCase): if sys.maxsize < (1 << 32): - IMMORTAL_REFCOUNT = (1 << 30) - 1 + IMMORTAL_REFCOUNT = 3 << 29 else: - IMMORTAL_REFCOUNT = (1 << 32) - 1 + IMMORTAL_REFCOUNT = 3 << 30 IMMORTALS = (None, True, False, Ellipsis, NotImplemented, *range(-5, 257)) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst new file mode 100644 index 00000000000000..c7eaac32601bb3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst @@ -0,0 +1,4 @@ +Make the handling of reference counts of immortal objects more robust. +Immortal objects with reference counts that deviate from their original +reference count by up to a billion (half a billion on 32 bit builds) are +still counted as immortal. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 870084100a1b85..0a769c46b87ac8 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1387,7 +1387,7 @@ FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored)) default: assert (0); } - assert(_Py_IsImmortalLoose(ret)); + assert(_Py_IsImmortal(ret)); return ret; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index bf58e55e100b3a..dcc1aba76abbed 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -46,7 +46,7 @@ Py_LOCAL_INLINE(Py_ssize_t) _PyBytesWriter_GetSize(_PyBytesWriter *writer, static inline PyObject* bytes_get_empty(void) { PyObject *empty = &EMPTY->ob_base.ob_base; - assert(_Py_IsImmortalLoose(empty)); + assert(_Py_IsImmortal(empty)); return empty; } @@ -119,7 +119,7 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size) } if (size == 1 && str != NULL) { op = CHARACTER(*str & 255); - assert(_Py_IsImmortalLoose(op)); + assert(_Py_IsImmortal(op)); return (PyObject *)op; } if (size == 0) { @@ -155,7 +155,7 @@ PyBytes_FromString(const char *str) } else if (size == 1) { op = CHARACTER(*str & 255); - assert(_Py_IsImmortalLoose(op)); + assert(_Py_IsImmortal(op)); return (PyObject *)op; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c index adfd91d1e4d63b..12722eca6be5e5 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -416,6 +416,8 @@ _PyDict_DebugMallocStats(FILE *out) #define DK_MASK(dk) (DK_SIZE(dk)-1) +#define _Py_DICT_IMMORTAL_INITIAL_REFCNT PY_SSIZE_T_MIN + static void free_keys_object(PyDictKeysObject *keys, bool use_qsbr); /* PyDictKeysObject has refcounts like PyObject does, so we have the @@ -428,7 +430,8 @@ static void free_keys_object(PyDictKeysObject *keys, bool use_qsbr); static inline void dictkeys_incref(PyDictKeysObject *dk) { - if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_IMMORTAL_REFCNT) { + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) < 0) { + assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_DICT_IMMORTAL_INITIAL_REFCNT); return; } #ifdef Py_REF_DEBUG @@ -440,7 +443,8 @@ dictkeys_incref(PyDictKeysObject *dk) static inline void dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk, bool use_qsbr) { - if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_IMMORTAL_REFCNT) { + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) < 0) { + assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_DICT_IMMORTAL_INITIAL_REFCNT); return; } assert(FT_ATOMIC_LOAD_SSIZE(dk->dk_refcnt) > 0); @@ -586,7 +590,7 @@ estimate_log2_keysize(Py_ssize_t n) * (which cannot fail and thus can do no allocation). */ static PyDictKeysObject empty_keys_struct = { - _Py_IMMORTAL_REFCNT, /* dk_refcnt */ + _Py_DICT_IMMORTAL_INITIAL_REFCNT, /* dk_refcnt */ 0, /* dk_log2_size */ 0, /* dk_log2_index_bytes */ DICT_KEYS_UNICODE, /* dk_kind */ diff --git a/Objects/object.c b/Objects/object.c index a97a900890320d..27d06cc081259d 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2453,7 +2453,7 @@ _Py_SetImmortalUntracked(PyObject *op) op->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL; op->ob_ref_shared = 0; #else - op->ob_refcnt = _Py_IMMORTAL_REFCNT; + op->ob_refcnt = _Py_IMMORTAL_INITIAL_REFCNT; #endif } diff --git a/Objects/structseq.c b/Objects/structseq.c index 6092742835400b..56a7851b98788d 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -708,7 +708,7 @@ _PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type) assert(type->tp_name != NULL); assert(type->tp_base == &PyTuple_Type); assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); - assert(_Py_IsImmortalLoose(type)); + assert(_Py_IsImmortal(type)); // Cannot delete a type if it still has subclasses if (_PyType_HasSubclasses(type)) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5380633fa1149e..d90bb5825fd437 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -476,7 +476,7 @@ set_tp_bases(PyTypeObject *self, PyObject *bases, int initial) assert(PyTuple_GET_SIZE(bases) == 1); assert(PyTuple_GET_ITEM(bases, 0) == (PyObject *)self->tp_base); assert(self->tp_base->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); - assert(_Py_IsImmortalLoose(self->tp_base)); + assert(_Py_IsImmortal(self->tp_base)); } _Py_SetImmortal(bases); } @@ -493,7 +493,7 @@ clear_tp_bases(PyTypeObject *self, int final) Py_CLEAR(self->tp_bases); } else { - assert(_Py_IsImmortalLoose(self->tp_bases)); + assert(_Py_IsImmortal(self->tp_bases)); _Py_ClearImmortal(self->tp_bases); } } @@ -558,7 +558,7 @@ clear_tp_mro(PyTypeObject *self, int final) Py_CLEAR(self->tp_mro); } else { - assert(_Py_IsImmortalLoose(self->tp_mro)); + assert(_Py_IsImmortal(self->tp_mro)); _Py_ClearImmortal(self->tp_mro); } } @@ -5966,7 +5966,7 @@ fini_static_type(PyInterpreterState *interp, PyTypeObject *type, int isbuiltin, int final) { assert(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); - assert(_Py_IsImmortalLoose((PyObject *)type)); + assert(_Py_IsImmortal((PyObject *)type)); type_dealloc_common(type); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 87cca3fc1d373c..34fdfcb05e3c18 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -381,7 +381,7 @@ dummy_func( EXIT_IF(!PyLong_CheckExact(value_o)); STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value_o)) { - assert(_Py_IsImmortalLoose(value_o)); + assert(_Py_IsImmortal(value_o)); DEAD(value); res = PyStackRef_False; } @@ -412,7 +412,7 @@ dummy_func( EXIT_IF(!PyUnicode_CheckExact(value_o)); STAT_INC(TO_BOOL, hit); if (value_o == &_Py_STR(empty)) { - assert(_Py_IsImmortalLoose(value_o)); + assert(_Py_IsImmortal(value_o)); DEAD(value); res = PyStackRef_False; } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 57e15f33ca7703..ef110e2e2a794a 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -402,7 +402,7 @@ } STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value_o)) { - assert(_Py_IsImmortalLoose(value_o)); + assert(_Py_IsImmortal(value_o)); res = PyStackRef_False; } else { @@ -455,7 +455,7 @@ } STAT_INC(TO_BOOL, hit); if (value_o == &_Py_STR(empty)) { - assert(_Py_IsImmortalLoose(value_o)); + assert(_Py_IsImmortal(value_o)); res = PyStackRef_False; } else { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7656ce6bb7e313..7023aea369db49 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -7840,7 +7840,7 @@ DEOPT_IF(!PyLong_CheckExact(value_o), TO_BOOL); STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value_o)) { - assert(_Py_IsImmortalLoose(value_o)); + assert(_Py_IsImmortal(value_o)); res = PyStackRef_False; } else { @@ -7902,7 +7902,7 @@ DEOPT_IF(!PyUnicode_CheckExact(value_o), TO_BOOL); STAT_INC(TO_BOOL, hit); if (value_o == &_Py_STR(empty)) { - assert(_Py_IsImmortalLoose(value_o)); + assert(_Py_IsImmortal(value_o)); res = PyStackRef_False; } else { diff --git a/Python/import.c b/Python/import.c index 460b1fe225c72e..acf849f14562b9 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1051,7 +1051,7 @@ del_cached_def(struct extensions_cache_value *value) However, this decref would be problematic if the module def were dynamically allocated, it were the last ref, and this function were called with an interpreter other than the def's owner. */ - assert(value->def == NULL || _Py_IsImmortalLoose(value->def)); + assert(value->def == NULL || _Py_IsImmortal(value->def)); Py_XDECREF(value->def->m_base.m_copy); value->def->m_base.m_copy = NULL; diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 9c2981a68ac909..60f5d010a7a083 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -614,7 +614,6 @@ def has_error_without_pop(op: parser.InstDef) -> bool: "_Py_EnterRecursiveCallTstateUnchecked", "_Py_ID", "_Py_IsImmortal", - "_Py_IsImmortalLoose", "_Py_LeaveRecursiveCallPy", "_Py_LeaveRecursiveCallTstate", "_Py_NewRef", From 3b87fb74c907510402678bf1b7c4a94df0e5e65a Mon Sep 17 00:00:00 2001 From: Justin Kunimune Date: Thu, 10 Oct 2024 13:56:05 -0400 Subject: [PATCH 107/247] Note argparse exit code in documentation (GH-119568) Co-authored-by: Savannah Ostrowski --- Doc/library/argparse.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index e9a08984f77c3a..4eb6fad41f11ef 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -541,7 +541,8 @@ exit_on_error ^^^^^^^^^^^^^ Normally, when you pass an invalid argument list to the :meth:`~ArgumentParser.parse_args` -method of an :class:`ArgumentParser`, it will exit with error info. +method of an :class:`ArgumentParser`, it will print a *message* to :data:`sys.stderr` and exit with a status +code of 2. If the user would like to catch errors manually, the feature can be enabled by setting ``exit_on_error`` to ``False``:: From bb594e801b6a84823badbb85b88f0fc8b221d7bf Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Oct 2024 20:41:14 +0200 Subject: [PATCH 108/247] gh-125196: Use PyUnicodeWriter for repr(dict) (#125270) --- Objects/dictobject.c | 72 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 12722eca6be5e5..b27599d2815c82 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3200,16 +3200,12 @@ static PyObject * dict_repr_lock_held(PyObject *self) { PyDictObject *mp = (PyDictObject *)self; - Py_ssize_t i; PyObject *key = NULL, *value = NULL; - _PyUnicodeWriter writer; - int first; - ASSERT_DICT_LOCKED(mp); - i = Py_ReprEnter((PyObject *)mp); - if (i != 0) { - return i > 0 ? PyUnicode_FromString("{...}") : NULL; + int res = Py_ReprEnter((PyObject *)mp); + if (res != 0) { + return (res > 0 ? PyUnicode_FromString("{...}") : NULL); } if (mp->ma_used == 0) { @@ -3217,66 +3213,70 @@ dict_repr_lock_held(PyObject *self) return PyUnicode_FromString("{}"); } - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; - /* "{" + "1: 2" + ", 3: 4" * (len - 1) + "}" */ - writer.min_length = 1 + 4 + (2 + 4) * (mp->ma_used - 1) + 1; + // "{" + "1: 2" + ", 3: 4" * (len - 1) + "}" + Py_ssize_t prealloc = 1 + 4 + 6 * (mp->ma_used - 1) + 1; + PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc); + if (writer == NULL) { + goto error; + } - if (_PyUnicodeWriter_WriteChar(&writer, '{') < 0) + if (PyUnicodeWriter_WriteChar(writer, '{') < 0) { goto error; + } /* Do repr() on each key+value pair, and insert ": " between them. Note that repr may mutate the dict. */ - i = 0; - first = 1; + Py_ssize_t i = 0; + int first = 1; while (_PyDict_Next((PyObject *)mp, &i, &key, &value, NULL)) { - PyObject *s; - int res; - - /* Prevent repr from deleting key or value during key format. */ + // Prevent repr from deleting key or value during key format. Py_INCREF(key); Py_INCREF(value); if (!first) { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) + // Write ", " + if (PyUnicodeWriter_WriteChar(writer, ',') < 0) { + goto error; + } + if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) { goto error; + } } first = 0; - s = PyObject_Repr(key); - if (s == NULL) - goto error; - res = _PyUnicodeWriter_WriteStr(&writer, s); - Py_DECREF(s); - if (res < 0) + // Write repr(key) + if (PyUnicodeWriter_WriteRepr(writer, key) < 0) { goto error; + } - if (_PyUnicodeWriter_WriteASCIIString(&writer, ": ", 2) < 0) + // Write ": " + if (PyUnicodeWriter_WriteChar(writer, ':') < 0) { goto error; - - s = PyObject_Repr(value); - if (s == NULL) + } + if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) { goto error; - res = _PyUnicodeWriter_WriteStr(&writer, s); - Py_DECREF(s); - if (res < 0) + } + + // Write repr(value) + if (PyUnicodeWriter_WriteRepr(writer, value) < 0) { goto error; + } Py_CLEAR(key); Py_CLEAR(value); } - writer.overallocate = 0; - if (_PyUnicodeWriter_WriteChar(&writer, '}') < 0) + if (PyUnicodeWriter_WriteChar(writer, '}') < 0) { goto error; + } Py_ReprLeave((PyObject *)mp); - return _PyUnicodeWriter_Finish(&writer); + return PyUnicodeWriter_Finish(writer); error: Py_ReprLeave((PyObject *)mp); - _PyUnicodeWriter_Dealloc(&writer); + PyUnicodeWriter_Discard(writer); Py_XDECREF(key); Py_XDECREF(value); return NULL; From 427dcf24de4e06d239745d74d08c4b2e541dca5a Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 10 Oct 2024 16:21:29 -0400 Subject: [PATCH 109/247] gh-125268: Use static string for "1e309" in AST (#125272) When formatting the AST as a string, infinite values are replaced by 1e309, which evaluates to infinity. The initialization of this string replacement was not thread-safe in the free threading build. --- Include/internal/pycore_global_objects.h | 3 -- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 +++ Parser/asdl_c.py | 2 -- Python/Python-ast.c | 2 -- Python/ast_unparse.c | 29 +++---------------- 8 files changed, 11 insertions(+), 32 deletions(-) diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 913dce6f1ec0fe..e3f7ac707f0c37 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -66,9 +66,6 @@ struct _Py_static_objects { struct _Py_interp_cached_objects { PyObject *interned_strings; - /* AST */ - PyObject *str_replace_inf; - /* object.__reduce__ */ PyObject *objreduce; PyObject *type_slots_pname; diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index de68ef93257234..2fd7d5d13a98b2 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -562,6 +562,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(json_decoder)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(kwdefaults)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(list_err)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(str_replace_inf)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CANCELLED)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 1591cb0a3f114f..fc3871570cc49d 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -48,6 +48,7 @@ struct _Py_global_strings { STRUCT_FOR_STR(json_decoder, "json.decoder") STRUCT_FOR_STR(kwdefaults, ".kwdefaults") STRUCT_FOR_STR(list_err, "list index out of range") + STRUCT_FOR_STR(str_replace_inf, "1e309") STRUCT_FOR_STR(type_params, ".type_params") STRUCT_FOR_STR(utf_8, "utf-8") } literals; diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index c9d20d0b5aacdb..3b80e265b0ca50 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -557,6 +557,7 @@ extern "C" { INIT_STR(json_decoder, "json.decoder"), \ INIT_STR(kwdefaults, ".kwdefaults"), \ INIT_STR(list_err, "list index out of range"), \ + INIT_STR(str_replace_inf, "1e309"), \ INIT_STR(type_params, ".type_params"), \ INIT_STR(utf_8, "utf-8"), \ } diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index d335373e88ee74..eb2eca06ec4d4f 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2936,6 +2936,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(str_replace_inf); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_STR(anon_null); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index f50c28afcfe205..32eac3afafa5d5 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -2242,8 +2242,6 @@ def generate_ast_fini(module_state, f): for s in module_state: f.write(" Py_CLEAR(state->" + s + ');\n') f.write(textwrap.dedent(""" - Py_CLEAR(_Py_INTERP_CACHED_OBJECT(interp, str_replace_inf)); - state->finalized = 1; state->once = (_PyOnceFlag){0}; } diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 89c52b9dc73cac..38d74b48d232f8 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -281,8 +281,6 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->vararg); Py_CLEAR(state->withitem_type); - Py_CLEAR(_Py_INTERP_CACHED_OBJECT(interp, str_replace_inf)); - state->finalized = 1; state->once = (_PyOnceFlag){0}; } diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c index 86f7a582b981a3..8017cfc7fcf268 100644 --- a/Python/ast_unparse.c +++ b/Python/ast_unparse.c @@ -2,7 +2,6 @@ #include "pycore_ast.h" // expr_ty #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_runtime.h" // _Py_ID() -#include // DBL_MAX_10_EXP #include /* This limited unparser is used to convert annotations back to strings @@ -13,10 +12,6 @@ _Py_DECLARE_STR(dbl_open_br, "{{"); _Py_DECLARE_STR(dbl_close_br, "}}"); -/* We would statically initialize this if doing so were simple enough. */ -#define _str_replace_inf(interp) \ - _Py_INTERP_CACHED_OBJECT(interp, str_replace_inf) - /* Forward declarations for recursion via helper functions. */ static PyObject * expr_as_unicode(expr_ty e, int level); @@ -78,13 +73,13 @@ append_repr(_PyUnicodeWriter *writer, PyObject *obj) } if ((PyFloat_CheckExact(obj) && isinf(PyFloat_AS_DOUBLE(obj))) || - PyComplex_CheckExact(obj)) + PyComplex_CheckExact(obj)) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + _Py_DECLARE_STR(str_replace_inf, "1e309"); // evaluates to inf PyObject *new_repr = PyUnicode_Replace( repr, &_Py_ID(inf), - _str_replace_inf(interp), + &_Py_STR(str_replace_inf), -1 ); Py_DECREF(repr); @@ -918,20 +913,6 @@ append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level) return -1; } -static int -maybe_init_static_strings(void) -{ - PyInterpreterState *interp = _PyInterpreterState_GET(); - if (_str_replace_inf(interp) == NULL) { - PyObject *tmp = PyUnicode_FromFormat("1e%d", 1 + DBL_MAX_10_EXP); - if (tmp == NULL) { - return -1; - } - _str_replace_inf(interp) = tmp; - } - return 0; -} - static PyObject * expr_as_unicode(expr_ty e, int level) { @@ -939,9 +920,7 @@ expr_as_unicode(expr_ty e, int level) _PyUnicodeWriter_Init(&writer); writer.min_length = 256; writer.overallocate = 1; - if (-1 == maybe_init_static_strings() || - -1 == append_ast_expr(&writer, e, level)) - { + if (-1 == append_ast_expr(&writer, e, level)) { _PyUnicodeWriter_Dealloc(&writer); return NULL; } From dd0ee201da34d1d4a631d77b420728f9233f53f9 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 10 Oct 2024 21:26:01 +0100 Subject: [PATCH 110/247] Doc: Upgrade Sphinx to 8.1 (#125276) --- Doc/conf.py | 31 ++++++++++++++++++++++++------- Doc/requirements.txt | 2 +- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index 287e0da46eb11c..d7197b17865854 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -11,6 +11,8 @@ import sys import time +import sphinx + sys.path.append(os.path.abspath('tools/extensions')) sys.path.append(os.path.abspath('includes')) @@ -62,7 +64,10 @@ # General substitutions. project = 'Python' -copyright = f"2001-{time.strftime('%Y')}, Python Software Foundation" +if sphinx.version_info[:2] >= (8, 1): + copyright = "2001-%Y, Python Software Foundation" +else: + copyright = f"2001-{time.strftime('%Y')}, Python Software Foundation" # We look for the Include/patchlevel.h file in the current Python source tree # and replace the values accordingly. @@ -361,10 +366,14 @@ } # This 'Last updated on:' timestamp is inserted at the bottom of every page. -html_time = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) -html_last_updated_fmt = time.strftime( - '%b %d, %Y (%H:%M UTC)', time.gmtime(html_time) -) +html_last_updated_fmt = '%b %d, %Y (%H:%M UTC)' +if sphinx.version_info[:2] >= (8, 1): + html_last_updated_use_utc = True +else: + html_time = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + html_last_updated_fmt = time.strftime( + html_last_updated_fmt, time.gmtime(html_time) + ) # Path to find HTML templates. templates_path = ['tools/templates'] @@ -596,13 +605,21 @@ # mapping unique short aliases to a base URL and a prefix. # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html extlinks = { - "cve": ("https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-%s", "CVE-%s"), - "cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"), "pypi": ("https://pypi.org/project/%s/", "%s"), "source": (SOURCE_URI, "%s"), } extlinks_detect_hardcoded_links = True +if sphinx.version_info[:2] < (8, 1): + # Sphinx 8.1 has in-built CVE and CWE roles. + extlinks |= { + "cve": ( + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-%s", + "CVE-%s", + ), + "cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"), + } + # Options for c_annotations # ------------------------- diff --git a/Doc/requirements.txt b/Doc/requirements.txt index bf1028020b7af7..5105786ccf283c 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -6,7 +6,7 @@ # Sphinx version is pinned so that new versions that introduce new warnings # won't suddenly cause build failures. Updating the version is fine as long # as no warnings are raised by doing so. -sphinx~=8.0.0 +sphinx~=8.1.0 blurb From a726ce73ca69b3a5ccc2cbe23061070e686b1150 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 11 Oct 2024 00:53:45 +0100 Subject: [PATCH 111/247] Add some doctest cleanups for `turtle` and `configparser` (#125288) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/configparser.rst | 1 + Doc/library/turtle.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index b5c18bbccffb78..3aad6f7b5d2d20 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -54,6 +54,7 @@ can be customized by end users easily. import os os.remove("example.ini") + os.remove("override.ini") Quick Start diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index da801d4dc1f5b3..efa4b6f8f1d3f9 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -14,6 +14,11 @@ from turtle import * turtle = Turtle() +.. testcleanup:: + + import os + os.remove("my_drawing.ps") + -------------- Introduction From 2f8301cbfbdd2976d254a4a772b4879069dd4298 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 10 Oct 2024 22:39:17 -0400 Subject: [PATCH 112/247] gh-124872: Rename blurb file to reference the correct issue (#125285) --- ....7tinr0.rst => 2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Misc/NEWS.d/next/Documentation/{2024-09-29-18-14-52.gh-issue-119333.7tinr0.rst => 2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst} (100%) diff --git a/Misc/NEWS.d/next/Documentation/2024-09-29-18-14-52.gh-issue-119333.7tinr0.rst b/Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst similarity index 100% rename from Misc/NEWS.d/next/Documentation/2024-09-29-18-14-52.gh-issue-119333.7tinr0.rst rename to Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst From c1913effeed4e4da4d5310a40ab518945001ffba Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 10 Oct 2024 23:30:27 -0700 Subject: [PATCH 113/247] gh-125296: Fix strange fragment identifier for `name or flags` in argparse docs (#125297) --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 4eb6fad41f11ef..d337de87ca8f39 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -602,7 +602,7 @@ The add_argument() method The following sections describe how each of these are used. -.. _name_or_flags: +.. _`name or flags`: name or flags ^^^^^^^^^^^^^ From b12e99261e656585ffbaa395af7c5dbaee5ad1ad Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Fri, 11 Oct 2024 03:56:01 -0400 Subject: [PATCH 114/247] gh-125221: Fix free-threading data race in `object.__reduce_ex__` (#125267) --- ...-10-10-14-47-13.gh-issue-125221.nfSQzT.rst | 2 ++ Objects/object.c | 8 ++++++++ Objects/typeobject.c | 20 +++++-------------- 3 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst new file mode 100644 index 00000000000000..c79650c3a64feb --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst @@ -0,0 +1,2 @@ +Fix possible race condition when calling :meth:`~object.__reduce_ex__` for the +first time in the free threading build. diff --git a/Objects/object.c b/Objects/object.c index 27d06cc081259d..4a4c5bf7d7f08a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2372,6 +2372,14 @@ _PyTypes_InitTypes(PyInterpreterState *interp) } } + // Cache __reduce__ from PyBaseObject_Type object + PyObject *baseobj_dict = _PyType_GetDict(&PyBaseObject_Type); + PyObject *baseobj_reduce = PyDict_GetItemWithError(baseobj_dict, &_Py_ID(__reduce__)); + if (baseobj_reduce == NULL && PyErr_Occurred()) { + return _PyStatus_ERR("Can't get __reduce__ from base object"); + } + _Py_INTERP_CACHED_OBJECT(interp, objreduce) = baseobj_reduce; + // Must be after static types are initialized if (_Py_initialize_generic(interp) < 0) { return _PyStatus_ERR("Can't initialize generic types"); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d90bb5825fd437..6ca4406ec0ea2d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7359,18 +7359,7 @@ static PyObject * object___reduce_ex___impl(PyObject *self, int protocol) /*[clinic end generated code: output=2e157766f6b50094 input=f326b43fb8a4c5ff]*/ { -#define objreduce \ - (_Py_INTERP_CACHED_OBJECT(_PyInterpreterState_GET(), objreduce)) - PyObject *reduce, *res; - - if (objreduce == NULL) { - PyObject *dict = lookup_tp_dict(&PyBaseObject_Type); - objreduce = PyDict_GetItemWithError(dict, &_Py_ID(__reduce__)); - if (objreduce == NULL && PyErr_Occurred()) { - return NULL; - } - } - + PyObject *reduce; if (PyObject_GetOptionalAttr(self, &_Py_ID(__reduce__), &reduce) < 0) { return NULL; } @@ -7384,10 +7373,12 @@ object___reduce_ex___impl(PyObject *self, int protocol) Py_DECREF(reduce); return NULL; } - override = (clsreduce != objreduce); + + PyInterpreterState *interp = _PyInterpreterState_GET(); + override = (clsreduce != _Py_INTERP_CACHED_OBJECT(interp, objreduce)); Py_DECREF(clsreduce); if (override) { - res = _PyObject_CallNoArgs(reduce); + PyObject *res = _PyObject_CallNoArgs(reduce); Py_DECREF(reduce); return res; } @@ -7396,7 +7387,6 @@ object___reduce_ex___impl(PyObject *self, int protocol) } return _common_reduce(self, protocol); -#undef objreduce } static PyObject * From 0135848059162ad81478a7776fec622d68a36524 Mon Sep 17 00:00:00 2001 From: Jan Kaliszewski Date: Fri, 11 Oct 2024 10:15:46 +0200 Subject: [PATCH 115/247] gh-125058: update `_thread` docs regarding interruptibility of `lock.acquire()` (#125141) --- Doc/library/_thread.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 5fd604c05380ac..6a66fc4c64bc45 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -219,9 +219,11 @@ In addition to these methods, lock objects can also be used via the * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is equivalent to calling :func:`_thread.exit`. -* It is not possible to interrupt the :meth:`~threading.Lock.acquire` method on - a lock --- the :exc:`KeyboardInterrupt` exception will happen after the lock - has been acquired. +* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method + on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception + will happen immediately, rather than only after the lock has been acquired or + the operation has timed out). It can be interrupted on POSIX, but not on + Windows. * When the main thread exits, it is system defined whether the other threads survive. On most systems, they are killed without executing From 18c74497681e0107d7cde53e63ea42feb38f2176 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 11 Oct 2024 11:43:29 +0300 Subject: [PATCH 116/247] gh-61011: Fix inheritance of nested mutually exclusive groups in argparse (GH-125210) Previously, all nested mutually exclusive groups lost their connection to the group containing them and were displayed as belonging directly to the parser. Co-authored-by: Danica J. Sutherland --- Lib/argparse.py | 6 +++- Lib/test/test_argparse.py | 29 +++++++++++++++++++ Misc/ACKS | 1 + ...4-10-09-21-42-43.gh-issue-61011.pQXZb1.rst | 4 +++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index d1f8fa2ace8611..2d8a7ef343a4ef 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1521,7 +1521,11 @@ def _add_container_actions(self, container): # NOTE: if add_mutually_exclusive_group ever gains title= and # description= then this code will need to be expanded as above for group in container._mutually_exclusive_groups: - mutex_group = self.add_mutually_exclusive_group( + if group._container is container: + cont = self + else: + cont = title_group_map[group._container.title] + mutex_group = cont.add_mutually_exclusive_group( required=group.required) # map the actions to their new mutex group diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index c9e79eb18a08fb..1ebbc21bc1755b 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2942,6 +2942,35 @@ def test_groups_parents(self): def test_wrong_type_parents(self): self.assertRaises(TypeError, ErrorRaisingArgumentParser, parents=[1]) + def test_mutex_groups_parents(self): + parent = ErrorRaisingArgumentParser(add_help=False) + g = parent.add_argument_group(title='g', description='gd') + g.add_argument('-w') + g.add_argument('-x') + m = g.add_mutually_exclusive_group() + m.add_argument('-y') + m.add_argument('-z') + parser = ErrorRaisingArgumentParser(prog='PROG', parents=[parent]) + + self.assertRaises(ArgumentParserError, parser.parse_args, + ['-y', 'Y', '-z', 'Z']) + + parser_help = parser.format_help() + self.assertEqual(parser_help, textwrap.dedent('''\ + usage: PROG [-h] [-w W] [-x X] [-y Y | -z Z] + + options: + -h, --help show this help message and exit + + g: + gd + + -w W + -x X + -y Y + -z Z + ''')) + # ============================== # Mutually exclusive group tests # ============================== diff --git a/Misc/ACKS b/Misc/ACKS index d94cbacf888468..a1769d9601a2ea 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1814,6 +1814,7 @@ Reuben Sumner Eryk Sun Sanjay Sundaresan Marek Šuppa +Danica J. Sutherland Hisao Suzuki Kalle Svensson Andrew Svetlov diff --git a/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst new file mode 100644 index 00000000000000..20f9c0b9c78b12 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst @@ -0,0 +1,4 @@ +Fix inheritance of nested mutually exclusive groups from parent parser in +:class:`argparse.ArgumentParser`. Previously, all nested mutually exclusive +groups lost their connection to the group containing them and were displayed +as belonging directly to the parser. From b3aa1b5fe260382788a2df416599325ad680a5ee Mon Sep 17 00:00:00 2001 From: Y5 <124019959+y5c4l3@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:08:03 +0000 Subject: [PATCH 117/247] gh-125235: Keep `_tkinter` TCL paths pointing to base installation on Windows (#125250) Signed-off-by: y5c4l3 --- .../next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst | 2 ++ Modules/_tkinter.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst diff --git a/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst b/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst new file mode 100644 index 00000000000000..f64d15917da1fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst @@ -0,0 +1,2 @@ +Keep :mod:`tkinter` TCL paths in venv pointing to base installation on +Windows. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 4f05cab375ed6b..b0b70ccb8cc3d3 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -143,7 +143,7 @@ _get_tcl_lib_path(void) struct stat stat_buf; int stat_return_value; - PyObject *prefix = PySys_GetObject("prefix"); // borrowed reference + PyObject *prefix = PySys_GetObject("base_prefix"); // borrowed reference if (prefix == NULL) { return NULL; } From 2115d76acc14effb3dbb9fedcf21048b2ad62c5e Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 11 Oct 2024 17:39:18 +0300 Subject: [PATCH 118/247] gh-124787: Fix `TypeAliasType` and incorrect `type_params` (#124795) Co-authored-by: Jelle Zijlstra --- Lib/test/test_type_aliases.py | 44 ++++++++- ...-09-30-20-46-32.gh-issue-124787.3FnJnP.rst | 4 + Objects/typevarobject.c | 97 ++++++++++++++++--- 3 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index ebb65d8c6cf81b..230bbe646baf28 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -4,7 +4,9 @@ from test.support import check_syntax_error, run_code from test.typinganndata import mod_generics_cache -from typing import Callable, TypeAliasType, TypeVar, get_args +from typing import ( + Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, get_args, +) class TypeParamsInvalidTest(unittest.TestCase): @@ -225,6 +227,46 @@ def test_not_generic(self): ): TA[int] + def test_type_params_order_with_defaults(self): + HasNoDefaultT = TypeVar("HasNoDefaultT") + WithDefaultT = TypeVar("WithDefaultT", default=int) + + HasNoDefaultP = ParamSpec("HasNoDefaultP") + WithDefaultP = ParamSpec("WithDefaultP", default=HasNoDefaultP) + + HasNoDefaultTT = TypeVarTuple("HasNoDefaultTT") + WithDefaultTT = TypeVarTuple("WithDefaultTT", default=HasNoDefaultTT) + + for type_params in [ + (HasNoDefaultT, WithDefaultT), + (HasNoDefaultP, WithDefaultP), + (HasNoDefaultTT, WithDefaultTT), + ]: + with self.subTest(type_params=type_params): + TypeAliasType("A", int, type_params=type_params) # ok + + msg = "follows default type parameter" + for type_params in [ + (WithDefaultT, HasNoDefaultT), + (WithDefaultP, HasNoDefaultP), + (WithDefaultTT, HasNoDefaultTT), + (WithDefaultT, HasNoDefaultP), # different types + ]: + with self.subTest(type_params=type_params): + with self.assertRaisesRegex(TypeError, msg): + TypeAliasType("A", int, type_params=type_params) + + def test_expects_type_like(self): + T = TypeVar("T") + + msg = "Expected a type param" + with self.assertRaisesRegex(TypeError, msg): + TypeAliasType("A", int, type_params=(1,)) + with self.assertRaisesRegex(TypeError, msg): + TypeAliasType("A", int, type_params=(1, 2)) + with self.assertRaisesRegex(TypeError, msg): + TypeAliasType("A", int, type_params=(T, 2)) + def test_keywords(self): TA = TypeAliasType(name="TA", value=int) self.assertEqual(TA.__name__, "TA") diff --git a/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst b/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst new file mode 100644 index 00000000000000..d9d1bbcf5a2fe4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst @@ -0,0 +1,4 @@ +Fix :class:`typing.TypeAliasType` with incorrect ``type_params`` argument. +Now it raises a :exc:`TypeError` when a type parameter without a default +follows one with a default, and when an entry in the ``type_params`` tuple +is not a type parameter object. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 51d93ed8b5ba8c..91cc37c9a72636 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1799,6 +1799,24 @@ _Py_make_typevartuple(PyThreadState *Py_UNUSED(ignored), PyObject *v) return (PyObject *)typevartuple_alloc(v, NULL, NULL); } +static PyObject * +get_type_param_default(PyThreadState *ts, PyObject *typeparam) { + // Does not modify refcount of existing objects. + if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevar_type)) { + return typevar_default((typevarobject *)typeparam, NULL); + } + else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.paramspec_type)) { + return paramspec_default((paramspecobject *)typeparam, NULL); + } + else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevartuple_type)) { + return typevartuple_default((typevartupleobject *)typeparam, NULL); + } + else { + PyErr_Format(PyExc_TypeError, "Expected a type param, got %R", typeparam); + return NULL; + } +} + static void typealias_dealloc(PyObject *self) { @@ -1906,25 +1924,75 @@ static PyGetSetDef typealias_getset[] = { {0} }; -static typealiasobject * -typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, - PyObject *value, PyObject *module) -{ - typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type); - if (ta == NULL) { +static PyObject * +typealias_check_type_params(PyObject *type_params, int *err) { + // Can return type_params or NULL without exception set. + // Does not change the reference count of type_params, + // sets `*err` to 1 when error happens and sets an exception, + // otherwise `*err` is set to 0. + *err = 0; + if (type_params == NULL) { return NULL; } - ta->name = Py_NewRef(name); + + assert(PyTuple_Check(type_params)); + Py_ssize_t length = PyTuple_GET_SIZE(type_params); + if (!length) { // 0-length tuples are the same as `NULL`. + return NULL; + } + + PyThreadState *ts = _PyThreadState_GET(); + int default_seen = 0; + for (Py_ssize_t index = 0; index < length; index++) { + PyObject *type_param = PyTuple_GET_ITEM(type_params, index); + PyObject *dflt = get_type_param_default(ts, type_param); + if (dflt == NULL) { + *err = 1; + return NULL; + } + if (dflt == &_Py_NoDefaultStruct) { + if (default_seen) { + *err = 1; + PyErr_Format(PyExc_TypeError, + "non-default type parameter '%R' " + "follows default type parameter", + type_param); + return NULL; + } + } else { + default_seen = 1; + Py_DECREF(dflt); + } + } + + return type_params; +} + +static PyObject * +typelias_convert_type_params(PyObject *type_params) +{ if ( type_params == NULL || Py_IsNone(type_params) || (PyTuple_Check(type_params) && PyTuple_GET_SIZE(type_params) == 0) ) { - ta->type_params = NULL; + return NULL; } else { - ta->type_params = Py_NewRef(type_params); + return type_params; } +} + +static typealiasobject * +typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, + PyObject *value, PyObject *module) +{ + typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type); + if (ta == NULL) { + return NULL; + } + ta->name = Py_NewRef(name); + ta->type_params = Py_XNewRef(type_params); ta->compute_value = Py_XNewRef(compute_value); ta->value = Py_XNewRef(value); ta->module = Py_XNewRef(module); @@ -2002,11 +2070,18 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, PyErr_SetString(PyExc_TypeError, "type_params must be a tuple"); return NULL; } + + int err = 0; + PyObject *checked_params = typealias_check_type_params(type_params, &err); + if (err) { + return NULL; + } + PyObject *module = caller(); if (module == NULL) { return NULL; } - PyObject *ta = (PyObject *)typealias_alloc(name, type_params, NULL, value, + PyObject *ta = (PyObject *)typealias_alloc(name, checked_params, NULL, value, module); Py_DECREF(module); return ta; @@ -2072,7 +2147,7 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args) assert(PyTuple_GET_SIZE(args) == 3); PyObject *name = PyTuple_GET_ITEM(args, 0); assert(PyUnicode_Check(name)); - PyObject *type_params = PyTuple_GET_ITEM(args, 1); + PyObject *type_params = typelias_convert_type_params(PyTuple_GET_ITEM(args, 1)); PyObject *compute_value = PyTuple_GET_ITEM(args, 2); assert(PyFunction_Check(compute_value)); return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL, NULL); From 08f6bf717118963815d9a3e60578104470fdf3e1 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 12 Oct 2024 00:27:26 +0900 Subject: [PATCH 119/247] gh-124612: Update autoconf container image (#125320) --- Tools/build/regen-configure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh index efc80c8527885c..1a24b07c3ff707 100755 --- a/Tools/build/regen-configure.sh +++ b/Tools/build/regen-configure.sh @@ -5,7 +5,7 @@ set -e -x # The check_generated_files job of .github/workflows/build.yml must kept in # sync with this script. Use the same container image than the job so the job # doesn't need to run autoreconf in a container. -IMAGE="ghcr.io/python/autoconf:2024.10.06.11200919239" +IMAGE="ghcr.io/python/autoconf:2024.10.11.11293396815" AUTORECONF="autoreconf -ivf -Werror" WORK_DIR="/src" From a00221e5a70e54a281ba0e2cff8d85cd37ae305f Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 12 Oct 2024 01:55:36 +0800 Subject: [PATCH 120/247] gh-116738: Make `_csv` module thread-safe (#118344) --- Modules/_csv.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 913560ce4a0ee3..1a4dc3f1f55ace 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -14,6 +14,7 @@ module instead. #endif #include "Python.h" +#include "pycore_pyatomic_ft_wrappers.h" #include // offsetof() #include @@ -34,7 +35,7 @@ typedef struct { PyTypeObject *dialect_type; PyTypeObject *reader_type; PyTypeObject *writer_type; - long field_limit; /* max parsed field size */ + Py_ssize_t field_limit; /* max parsed field size */ PyObject *str_write; } _csvstate; @@ -706,10 +707,11 @@ parse_grow_buff(ReaderObj *self) static int parse_add_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) { - if (self->field_len >= module_state->field_limit) { + Py_ssize_t field_limit = FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit); + if (self->field_len >= field_limit) { PyErr_Format(module_state->error_obj, - "field larger than field limit (%ld)", - module_state->field_limit); + "field larger than field limit (%zd)", + field_limit); return -1; } if (self->field_len == self->field_size && !parse_grow_buff(self)) @@ -1659,20 +1661,20 @@ _csv_field_size_limit_impl(PyObject *module, PyObject *new_limit) /*[clinic end generated code: output=f2799ecd908e250b input=cec70e9226406435]*/ { _csvstate *module_state = get_csv_state(module); - long old_limit = module_state->field_limit; + Py_ssize_t old_limit = FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit); if (new_limit != NULL) { if (!PyLong_CheckExact(new_limit)) { PyErr_Format(PyExc_TypeError, "limit must be an integer"); return NULL; } - module_state->field_limit = PyLong_AsLong(new_limit); - if (module_state->field_limit == -1 && PyErr_Occurred()) { - module_state->field_limit = old_limit; + Py_ssize_t new_limit_value = PyLong_AsSsize_t(new_limit); + if (new_limit_value == -1 && PyErr_Occurred()) { return NULL; } + FT_ATOMIC_STORE_SSIZE_RELAXED(module_state->field_limit, new_limit_value); } - return PyLong_FromLong(old_limit); + return PyLong_FromSsize_t(old_limit); } static PyType_Slot error_slots[] = { From cc2938a18967c9d462ebb18bc09f73e4364aa7d2 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 11 Oct 2024 12:41:59 -0700 Subject: [PATCH 121/247] gh-124917: Allow keyword args to os.path.exists/lexists on Windows (#124918) --- Lib/test/test_genericpath.py | 4 + ...-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst | 2 + Modules/clinic/posixmodule.c.h | 78 ++++++++++++++++--- Modules/posixmodule.c | 6 +- 4 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index bf04b3fecf7057..6d2593cb4cf228 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -156,6 +156,10 @@ def test_exists(self): self.assertIs(self.pathmodule.lexists(filename + '\x00'), False) self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False) + # Keyword arguments are accepted + self.assertIs(self.pathmodule.exists(path=filename), True) + self.assertIs(self.pathmodule.lexists(path=filename), True) + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat") def test_exists_fd(self): diff --git a/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst new file mode 100644 index 00000000000000..f208793859bbf8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst @@ -0,0 +1,2 @@ +Allow calling :func:`os.path.exists` and :func:`os.path.lexists` with +keyword arguments on Windows. Fixes a regression in 3.13.0. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 749fe54598cc39..d9d919ea75d853 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -2015,25 +2015,55 @@ os__path_splitroot(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #if defined(MS_WINDOWS) PyDoc_STRVAR(os__path_exists__doc__, -"_path_exists($module, path, /)\n" +"_path_exists($module, /, path)\n" "--\n" "\n" "Test whether a path exists. Returns False for broken symbolic links."); #define OS__PATH_EXISTS_METHODDEF \ - {"_path_exists", (PyCFunction)os__path_exists, METH_O, os__path_exists__doc__}, + {"_path_exists", _PyCFunction_CAST(os__path_exists), METH_FASTCALL|METH_KEYWORDS, os__path_exists__doc__}, static int os__path_exists_impl(PyObject *module, path_t *path); static PyObject * -os__path_exists(PyObject *module, PyObject *arg) +os__path_exists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_path_exists", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; path_t path = PATH_T_INITIALIZE_P("_path_exists", "path", 0, 0, 1, 1); int _return_value; - if (!path_converter(arg, &path)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &path)) { goto exit; } _return_value = os__path_exists_impl(module, &path); @@ -2054,25 +2084,55 @@ os__path_exists(PyObject *module, PyObject *arg) #if defined(MS_WINDOWS) PyDoc_STRVAR(os__path_lexists__doc__, -"_path_lexists($module, path, /)\n" +"_path_lexists($module, /, path)\n" "--\n" "\n" "Test whether a path exists. Returns True for broken symbolic links."); #define OS__PATH_LEXISTS_METHODDEF \ - {"_path_lexists", (PyCFunction)os__path_lexists, METH_O, os__path_lexists__doc__}, + {"_path_lexists", _PyCFunction_CAST(os__path_lexists), METH_FASTCALL|METH_KEYWORDS, os__path_lexists__doc__}, static int os__path_lexists_impl(PyObject *module, path_t *path); static PyObject * -os__path_lexists(PyObject *module, PyObject *arg) +os__path_lexists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_path_lexists", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; path_t path = PATH_T_INITIALIZE_P("_path_lexists", "path", 0, 0, 1, 1); int _return_value; - if (!path_converter(arg, &path)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &path)) { goto exit; } _return_value = os__path_lexists_impl(module, &path); @@ -12837,4 +12897,4 @@ os__create_environ(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF #define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF #endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */ -/*[clinic end generated code: output=b93bbaaa8eb5b0ce input=a9049054013a1b77]*/ +/*[clinic end generated code: output=18d75b737513dae6 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 334350285f3b6f..c0af78ba075e85 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5391,7 +5391,6 @@ _testFileType(path_t *path, int testedType) os._path_exists -> bool path: path_t(allow_fd=True, suppress_value_error=True) - / Test whether a path exists. Returns False for broken symbolic links. @@ -5399,7 +5398,7 @@ Test whether a path exists. Returns False for broken symbolic links. static int os__path_exists_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=8da13acf666e16ba input=29198507a6082a57]*/ +/*[clinic end generated code: output=8da13acf666e16ba input=142beabfc66783eb]*/ { return _testFileExists(path, TRUE); } @@ -5409,7 +5408,6 @@ os__path_exists_impl(PyObject *module, path_t *path) os._path_lexists -> bool path: path_t(allow_fd=True, suppress_value_error=True) - / Test whether a path exists. Returns True for broken symbolic links. @@ -5417,7 +5415,7 @@ Test whether a path exists. Returns True for broken symbolic links. static int os__path_lexists_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=e7240ed5fc45bff3 input=03d9fed8bc6ce96f]*/ +/*[clinic end generated code: output=e7240ed5fc45bff3 input=208205112a3cc1ed]*/ { return _testFileExists(path, FALSE); } From 76b29d271b3132bf8e13bc724f10be8c630057ba Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Fri, 11 Oct 2024 17:00:31 -0300 Subject: [PATCH 122/247] Fix typo in ``Doclibrary/functions.rst`` (#125327) --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 7f8df704a33327..0638df04c6ff40 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -686,7 +686,7 @@ are always available. They are listed here in alphabetical order. The *closure* argument specifies a closure--a tuple of cellvars. It's only valid when the *object* is a code object containing :term:`free (closure) variables `. - The length of the tuple must exactly match the length of the code object'S + The length of the tuple must exactly match the length of the code object's :attr:`~codeobject.co_freevars` attribute. .. audit-event:: exec code_object exec From 89515be596a0ca05fd9ab4ddf76c8013dd093545 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 11 Oct 2024 21:18:37 +0100 Subject: [PATCH 123/247] gh-119786: Move garbage collection doc from devguide to InternalDocs (#125282) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Carol Willing carolcode@willingconsulting.com Co-Authored-By: Ezio Melotti ezio.melotti@gmail.com Co-Authored-By: Hugo van Kemenade hugovk@users.noreply.github.com Co-Authored-By: Itamar Ostricher itamarost@gmail.com Co-Authored-By: Jesús Cea jcea@jcea.es Co-Authored-By: Joannah Nanjekye 33177550+nanjekyejoannah@users.noreply.github.com Co-Authored-By: Ned Batchelder ned@nedbatchelder.com Co-Authored-By: Pablo Galindo Salgado Pablogsal@gmail.com Co-Authored-By: Pamela Fox pamela.fox@gmail.com Co-Authored-By: Sam Gross colesbury@gmail.com Co-Authored-By: Stefan Pochmann 609905+pochmann@users.noreply.github.com Co-Authored-By: T. Wouters thomas@python.org Co-Authored-By: q-ata 24601033+q-ata@users.noreply.github.com Co-Authored-By: slateny 46876382+slateny@users.noreply.github.com Co-Authored-By: Борис Верховский boris.verk@gmail.com Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Jacob Coffee --- InternalDocs/README.md | 2 + InternalDocs/garbage_collector.md | 596 ++++++++++++++++++ .../images/python-cyclic-gc-1-new-page.png | Bin 0 -> 4415 bytes .../images/python-cyclic-gc-2-new-page.png | Bin 0 -> 4337 bytes .../images/python-cyclic-gc-3-new-page.png | Bin 0 -> 4876 bytes .../images/python-cyclic-gc-4-new-page.png | Bin 0 -> 4863 bytes .../images/python-cyclic-gc-5-new-page.png | Bin 0 -> 5712 bytes 7 files changed, 598 insertions(+) create mode 100644 InternalDocs/garbage_collector.md create mode 100644 InternalDocs/images/python-cyclic-gc-1-new-page.png create mode 100644 InternalDocs/images/python-cyclic-gc-2-new-page.png create mode 100644 InternalDocs/images/python-cyclic-gc-3-new-page.png create mode 100644 InternalDocs/images/python-cyclic-gc-4-new-page.png create mode 100644 InternalDocs/images/python-cyclic-gc-5-new-page.png diff --git a/InternalDocs/README.md b/InternalDocs/README.md index 8956ecafed2039..805e2f97937e1e 100644 --- a/InternalDocs/README.md +++ b/InternalDocs/README.md @@ -22,4 +22,6 @@ it is not, please report that through the [The Source Code Locations Table](locations.md) +[Garbage collector design](garbage_collector.md) + [Exception Handling](exception_handling.md) diff --git a/InternalDocs/garbage_collector.md b/InternalDocs/garbage_collector.md new file mode 100644 index 00000000000000..fd0246fa1a60e2 --- /dev/null +++ b/InternalDocs/garbage_collector.md @@ -0,0 +1,596 @@ + +Garbage collector design +======================== + +Abstract +======== + +The main garbage collection algorithm used by CPython is reference counting. The basic idea is +that CPython counts how many different places there are that have a reference to an +object. Such a place could be another object, or a global (or static) C variable, or +a local variable in some C function. When an object’s reference count becomes zero, +the object is deallocated. If it contains references to other objects, their +reference counts are decremented. Those other objects may be deallocated in turn, if +this decrement makes their reference count become zero, and so on. The reference +count field can be examined using the ``sys.getrefcount()`` function (notice that the +value returned by this function is always 1 more as the function also has a reference +to the object when called): + +```pycon + >>> x = object() + >>> sys.getrefcount(x) + 2 + >>> y = x + >>> sys.getrefcount(x) + 3 + >>> del y + >>> sys.getrefcount(x) + 2 +``` + +The main problem with the reference counting scheme is that it does not handle reference +cycles. For instance, consider this code: + +```pycon + >>> container = [] + >>> container.append(container) + >>> sys.getrefcount(container) + 3 + >>> del container +``` + +In this example, ``container`` holds a reference to itself, so even when we remove +our reference to it (the variable "container") the reference count never falls to 0 +because it still has its own internal reference. Therefore it would never be +cleaned just by simple reference counting. For this reason some additional machinery +is needed to clean these reference cycles between objects once they become +unreachable. This is the cyclic garbage collector, usually called just Garbage +Collector (GC), even though reference counting is also a form of garbage collection. + +Starting in version 3.13, CPython contains two GC implementations: + +- The default build implementation relies on the + [global interpreter lock](https://docs.python.org/3/glossary.html#term-global-interpreter-lock) + for thread safety. +- The free-threaded build implementation pauses other executing threads when + performing a collection for thread safety. + +Both implementations use the same basic algorithms, but operate on different +data structures. The the section on +[Differences between GC implementations](#Differences-between-GC-implementations) +for the details. + + +Memory layout and object structure +================================== + +The garbage collector requires additional fields in Python objects to support +garbage collection. These extra fields are different in the default and the +free-threaded builds. + + +GC for the default build +------------------------ + +Normally the C structure supporting a regular Python object looks as follows: + +``` + object -----> +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ \ + | ob_refcnt | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | PyObject_HEAD + | *ob_type | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / + | ... | +``` + +In order to support the garbage collector, the memory layout of objects is altered +to accommodate extra information **before** the normal layout: + +``` + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ \ + | *_gc_next | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | PyGC_Head + | *_gc_prev | | + object -----> +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / + | ob_refcnt | \ + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | PyObject_HEAD + | *ob_type | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / + | ... | +``` + + +In this way the object can be treated as a normal python object and when the extra +information associated to the GC is needed the previous fields can be accessed by a +simple type cast from the original object: `((PyGC_Head *)(the_object)-1)`. + +As is explained later in the +[Optimization: reusing fields to save memory](#optimization-reusing-fields-to-save-memory) +section, these two extra fields are normally used to keep doubly linked lists of all the +objects tracked by the garbage collector (these lists are the GC generations, more on +that in the [Optimization: generations](#Optimization-generations) section), but +they are also reused to fulfill other purposes when the full doubly linked list +structure is not needed as a memory optimization. + +Doubly linked lists are used because they efficiently support the most frequently required operations. In +general, the collection of all objects tracked by GC is partitioned into disjoint sets, each in its own +doubly linked list. Between collections, objects are partitioned into "generations", reflecting how +often they've survived collection attempts. During collections, the generation(s) being collected +are further partitioned into, for example, sets of reachable and unreachable objects. Doubly linked lists +support moving an object from one partition to another, adding a new object, removing an object +entirely (objects tracked by GC are most often reclaimed by the refcounting system when GC +isn't running at all!), and merging partitions, all with a small constant number of pointer updates. +With care, they also support iterating over a partition while objects are being added to - and +removed from - it, which is frequently required while GC is running. + +GC for the free-threaded build +------------------------------ + +In the free-threaded build, Python objects contain a 1-byte field +``ob_gc_bits`` that is used to track garbage collection related state. The +field exists in all objects, including ones that do not support cyclic +garbage collection. The field is used to identify objects that are tracked +by the collector, ensure that finalizers are called only once per object, +and, during garbage collection, differentiate reachable vs. unreachable objects. + +``` + object -----> +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ \ + | ob_tid | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | + | pad | ob_mutex | ob_gc_bits | ob_ref_local | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | PyObject_HEAD + | ob_ref_shared | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | + | *ob_type | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / + | ... | +``` + +Note that not all fields are to scale. ``pad`` is two bytes, ``ob_mutex`` and +``ob_gc_bits`` are each one byte, and ``ob_ref_local`` is four bytes. The +other fields, ``ob_tid``, ``ob_ref_shared``, and ``ob_type``, are all +pointer-sized (that is, eight bytes on a 64-bit platform). + + +The garbage collector also temporarily repurposes the ``ob_tid`` (thread ID) +and ``ob_ref_local`` (local reference count) fields for other purposes during +collections. + + +C APIs +------ + +Specific APIs are offered to allocate, deallocate, initialize, track, and untrack +objects with GC support. These APIs can be found in the +[Garbage Collector C API documentation](https://docs.python.org/3/c-api/gcsupport.html). + +Apart from this object structure, the type object for objects supporting garbage +collection must include the ``Py_TPFLAGS_HAVE_GC`` in its ``tp_flags`` slot and +provide an implementation of the ``tp_traverse`` handler. Unless it can be proven +that the objects cannot form reference cycles with only objects of its type or unless +the type is immutable, a ``tp_clear`` implementation must also be provided. + + +Identifying reference cycles +============================ + +The algorithm that CPython uses to detect those reference cycles is +implemented in the ``gc`` module. The garbage collector **only focuses** +on cleaning container objects (that is, objects that can contain a reference +to one or more objects). These can be arrays, dictionaries, lists, custom +class instances, classes in extension modules, etc. One could think that +cycles are uncommon but the truth is that many internal references needed by +the interpreter create cycles everywhere. Some notable examples: + +- Exceptions contain traceback objects that contain a list of frames that + contain the exception itself. +- Module-level functions reference the module's dict (which is needed to resolve globals), + which in turn contains entries for the module-level functions. +- Instances have references to their class which itself references its module, and the module + contains references to everything that is inside (and maybe other modules) + and this can lead back to the original instance. +- When representing data structures like graphs, it is very typical for them to + have internal links to themselves. + +To correctly dispose of these objects once they become unreachable, they need +to be identified first. To understand how the algorithm works, let’s take +the case of a circular linked list which has one link referenced by a +variable ``A``, and one self-referencing object which is completely +unreachable: + +```pycon + >>> import gc + + >>> class Link: + ... def __init__(self, next_link=None): + ... self.next_link = next_link + + >>> link_3 = Link() + >>> link_2 = Link(link_3) + >>> link_1 = Link(link_2) + >>> link_3.next_link = link_1 + >>> A = link_1 + >>> del link_1, link_2, link_3 + + >>> link_4 = Link() + >>> link_4.next_link = link_4 + >>> del link_4 + + # Collect the unreachable Link object (and its .__dict__ dict). + >>> gc.collect() + 2 +``` + +The GC starts with a set of candidate objects it wants to scan. In the +default build, these "objects to scan" might be all container objects or a +smaller subset (or "generation"). In the free-threaded build, the collector +always scans all container objects. + +The objective is to identify all the unreachable objects. The collector does +this by identifying reachable objects; the remaining objects must be +unreachable. The first step is to identify all of the "to scan" objects that +are **directly** reachable from outside the set of candidate objects. These +objects have a refcount larger than the number of incoming references from +within the candidate set. + +Every object that supports garbage collection will have an extra reference +count field initialized to the reference count (``gc_ref`` in the figures) +of that object when the algorithm starts. This is because the algorithm needs +to modify the reference count to do the computations and in this way the +interpreter will not modify the real reference count field. + +![gc-image1](images/python-cyclic-gc-1-new-page.png) + +The GC then iterates over all containers in the first list and decrements by one the +`gc_ref` field of any other object that container is referencing. Doing +this makes use of the ``tp_traverse`` slot in the container class (implemented +using the C API or inherited by a superclass) to know what objects are referenced by +each container. After all the objects have been scanned, only the objects that have +references from outside the “objects to scan” list will have ``gc_ref > 0``. + +![gc-image2](images/python-cyclic-gc-2-new-page.png) + +Notice that having ``gc_ref == 0`` does not imply that the object is unreachable. +This is because another object that is reachable from the outside (``gc_ref > 0``) +can still have references to it. For instance, the ``link_2`` object in our example +ended having ``gc_ref == 0`` but is referenced still by the ``link_1`` object that +is reachable from the outside. To obtain the set of objects that are really +unreachable, the garbage collector re-scans the container objects using the +``tp_traverse`` slot; this time with a different traverse function that marks objects with +``gc_ref == 0`` as "tentatively unreachable" and then moves them to the +tentatively unreachable list. The following image depicts the state of the lists in a +moment when the GC processed the ``link_3`` and ``link_4`` objects but has not +processed ``link_1`` and ``link_2`` yet. + +![gc-image3](images/python-cyclic-gc-3-new-page.png) + +Then the GC scans the next ``link_1`` object. Because it has ``gc_ref == 1``, +the gc does not do anything special because it knows it has to be reachable (and is +already in what will become the reachable list): + +![gc-image4](images/python-cyclic-gc-4-new-page.png) + +When the GC encounters an object which is reachable (``gc_ref > 0``), it traverses +its references using the ``tp_traverse`` slot to find all the objects that are +reachable from it, moving them to the end of the list of reachable objects (where +they started originally) and setting its ``gc_ref`` field to 1. This is what happens +to ``link_2`` and ``link_3`` below as they are reachable from ``link_1``. From the +state in the previous image and after examining the objects referred to by ``link_1`` +the GC knows that ``link_3`` is reachable after all, so it is moved back to the +original list and its ``gc_ref`` field is set to 1 so that if the GC visits it again, +it will know that it's reachable. To avoid visiting an object twice, the GC marks all +objects that have already been visited once (by unsetting the ``PREV_MASK_COLLECTING`` +flag) so that if an object that has already been processed is referenced by some other +object, the GC does not process it twice. + +![gc-image5](images/python-cyclic-gc-5-new-page.png) + +Notice that an object that was marked as "tentatively unreachable" and was later +moved back to the reachable list will be visited again by the garbage collector +as now all the references that that object has need to be processed as well. This +process is really a breadth first search over the object graph. Once all the objects +are scanned, the GC knows that all container objects in the tentatively unreachable +list are really unreachable and can thus be garbage collected. + +Pragmatically, it's important to note that no recursion is required by any of this, +and neither does it in any other way require additional memory proportional to the +number of objects, number of pointers, or the lengths of pointer chains. Apart from +``O(1)`` storage for internal C needs, the objects themselves contain all the storage +the GC algorithms require. + +Why moving unreachable objects is better +---------------------------------------- + +It sounds logical to move the unreachable objects under the premise that most objects +are usually reachable, until you think about it: the reason it pays isn't actually +obvious. + +Suppose we create objects A, B, C in that order. They appear in the young generation +in the same order. If B points to A, and C to B, and C is reachable from outside, +then the adjusted refcounts after the first step of the algorithm runs will be 0, 0, +and 1 respectively because the only reachable object from the outside is C. + +When the next step of the algorithm finds A, A is moved to the unreachable list. The +same for B when it's first encountered. Then C is traversed, B is moved *back* to +the reachable list. B is eventually traversed, and then A is moved back to the reachable +list. + +So instead of not moving at all, the reachable objects B and A are each moved twice. +Why is this a win? A straightforward algorithm to move the reachable objects instead +would move A, B, and C once each. The key is that this dance leaves the objects in +order C, B, A - it's reversed from the original order. On all *subsequent* scans, +none of them will move. Since most objects aren't in cycles, this can save an +unbounded number of moves across an unbounded number of later collections. The only +time the cost can be higher is the first time the chain is scanned. + +Destroying unreachable objects +============================== + +Once the GC knows the list of unreachable objects, a very delicate process starts +with the objective of completely destroying these objects. Roughly, the process +follows these steps in order: + +1. Handle and clear weak references (if any). Weak references to unreachable objects + are set to ``None``. If the weak reference has an associated callback, the callback + is enqueued to be called once the clearing of weak references is finished. We only + invoke callbacks for weak references that are themselves reachable. If both the weak + reference and the pointed-to object are unreachable we do not execute the callback. + This is partly for historical reasons: the callback could resurrect an unreachable + object and support for weak references predates support for object resurrection. + Ignoring the weak reference's callback is fine because both the object and the weakref + are going away, so it's legitimate to say the weak reference is going away first. +2. If an object has legacy finalizers (``tp_del`` slot) move it to the + ``gc.garbage`` list. +3. Call the finalizers (``tp_finalize`` slot) and mark the objects as already + finalized to avoid calling finalizers twice if the objects are resurrected or + if other finalizers have removed the object first. +4. Deal with resurrected objects. If some objects have been resurrected, the GC + finds the new subset of objects that are still unreachable by running the cycle + detection algorithm again and continues with them. +5. Call the ``tp_clear`` slot of every object so all internal links are broken and + the reference counts fall to 0, triggering the destruction of all unreachable + objects. + +Optimization: generations +========================= + +In order to limit the time each garbage collection takes, the GC +implementation for the default build uses a popular optimization: +generations. The main idea behind this concept is the assumption that most +objects have a very short lifespan and can thus be collected soon after their +creation. This has proven to be very close to the reality of many Python +programs as many temporary objects are created and destroyed very quickly. + +To take advantage of this fact, all container objects are segregated into +three spaces/generations. Every new +object starts in the first generation (generation 0). The previous algorithm is +executed only over the objects of a particular generation and if an object +survives a collection of its generation it will be moved to the next one +(generation 1), where it will be surveyed for collection less often. If +the same object survives another GC round in this new generation (generation 1) +it will be moved to the last generation (generation 2) where it will be +surveyed the least often. + +The GC implementation for the free-threaded build does not use multiple +generations. Every collection operates on the entire heap. + +In order to decide when to run, the collector keeps track of the number of object +allocations and deallocations since the last collection. When the number of +allocations minus the number of deallocations exceeds ``threshold_0``, +collection starts. Initially only generation 0 is examined. If generation 0 has +been examined more than ``threshold_1`` times since generation 1 has been +examined, then generation 1 is examined as well. With generation 2, +things are a bit more complicated; see +[Collecting the oldest generation](#Collecting-the-oldest-generation) for +more information. These thresholds can be examined using the +[`gc.get_threshold()`](https://docs.python.org/3/library/gc.html#gc.get_threshold) +function: + +```pycon + >>> import gc + >>> gc.get_threshold() + (700, 10, 10) +``` + +The content of these generations can be examined using the +``gc.get_objects(generation=NUM)`` function and collections can be triggered +specifically in a generation by calling ``gc.collect(generation=NUM)``. + +```pycon + >>> import gc + >>> class MyObj: + ... pass + ... + + # Move everything to the last generation so it's easier to inspect + # the younger generations. + + >>> gc.collect() + 0 + + # Create a reference cycle. + + >>> x = MyObj() + >>> x.self = x + + # Initially the object is in the youngest generation. + + >>> gc.get_objects(generation=0) + [..., <__main__.MyObj object at 0x7fbcc12a3400>, ...] + + # After a collection of the youngest generation the object + # moves to the next generation. + + >>> gc.collect(generation=0) + 0 + >>> gc.get_objects(generation=0) + [] + >>> gc.get_objects(generation=1) + [..., <__main__.MyObj object at 0x7fbcc12a3400>, ...] +``` + +Collecting the oldest generation +-------------------------------- + +In addition to the various configurable thresholds, the GC only triggers a full +collection of the oldest generation if the ratio ``long_lived_pending / long_lived_total`` +is above a given value (hardwired to 25%). The reason is that, while "non-full" +collections (that is, collections of the young and middle generations) will always +examine roughly the same number of objects (determined by the aforementioned +thresholds) the cost of a full collection is proportional to the total +number of long-lived objects, which is virtually unbounded. Indeed, it has +been remarked that doing a full collection every of object +creations entails a dramatic performance degradation in workloads which consist +of creating and storing lots of long-lived objects (for example, building a large list +of GC-tracked objects would show quadratic performance, instead of linear as +expected). Using the above ratio, instead, yields amortized linear performance +in the total number of objects (the effect of which can be summarized thusly: +"each full garbage collection is more and more costly as the number of objects +grows, but we do fewer and fewer of them"). + +Optimization: reusing fields to save memory +=========================================== + +In order to save memory, the two linked list pointers in every object with GC +support are reused for several purposes. This is a common optimization known +as "fat pointers" or "tagged pointers": pointers that carry additional data, +"folded" into the pointer, meaning stored inline in the data representing the +address, taking advantage of certain properties of memory addressing. This is +possible as most architectures align certain types of data +to the size of the data, often a word or multiple thereof. This discrepancy +leaves a few of the least significant bits of the pointer unused, which can be +used for tags or to keep other information – most often as a bit field (each +bit a separate tag) – as long as code that uses the pointer masks out these +bits before accessing memory. For example, on a 32-bit architecture (for both +addresses and word size), a word is 32 bits = 4 bytes, so word-aligned +addresses are always a multiple of 4, hence end in ``00``, leaving the last 2 bits +available; while on a 64-bit architecture, a word is 64 bits = 8 bytes, so +word-aligned addresses end in ``000``, leaving the last 3 bits available. + +The CPython GC makes use of two fat pointers that correspond to the extra fields +of ``PyGC_Head`` discussed in the `Memory layout and object structure`_ section: + +> [!WARNING] +> Because the presence of extra information, "tagged" or "fat" pointers cannot be +> dereferenced directly and the extra information must be stripped off before +> obtaining the real memory address. Special care needs to be taken with +> functions that directly manipulate the linked lists, as these functions +> normally assume the pointers inside the lists are in a consistent state. + + +- The ``_gc_prev`` field is normally used as the "previous" pointer to maintain the + doubly linked list but its lowest two bits are used to keep the flags + ``PREV_MASK_COLLECTING`` and ``_PyGC_PREV_MASK_FINALIZED``. Between collections, + the only flag that can be present is ``_PyGC_PREV_MASK_FINALIZED`` that indicates + if an object has been already finalized. During collections ``_gc_prev`` is + temporarily used for storing a copy of the reference count (``gc_ref``), in + addition to two flags, and the GC linked list becomes a singly linked list until + ``_gc_prev`` is restored. + +- The ``_gc_next`` field is used as the "next" pointer to maintain the doubly linked + list but during collection its lowest bit is used to keep the + ``NEXT_MASK_UNREACHABLE`` flag that indicates if an object is tentatively + unreachable during the cycle detection algorithm. This is a drawback to using only + doubly linked lists to implement partitions: while most needed operations are + constant-time, there is no efficient way to determine which partition an object is + currently in. Instead, when that's needed, ad hoc tricks (like the + ``NEXT_MASK_UNREACHABLE`` flag) are employed. + +Optimization: delay tracking containers +======================================= + +Certain types of containers cannot participate in a reference cycle, and so do +not need to be tracked by the garbage collector. Untracking these objects +reduces the cost of garbage collection. However, determining which objects may +be untracked is not free, and the costs must be weighed against the benefits +for garbage collection. There are two possible strategies for when to untrack +a container: + +1. When the container is created. +2. When the container is examined by the garbage collector. + +As a general rule, instances of atomic types aren't tracked and instances of +non-atomic types (containers, user-defined objects...) are. However, some +type-specific optimizations can be present in order to suppress the garbage +collector footprint of simple instances. Some examples of native types that +benefit from delayed tracking: + +- Tuples containing only immutable objects (integers, strings etc, + and recursively, tuples of immutable objects) do not need to be tracked. The + interpreter creates a large number of tuples, many of which will not survive + until garbage collection. It is therefore not worthwhile to untrack eligible + tuples at creation time. Instead, all tuples except the empty tuple are tracked + when created. During garbage collection it is determined whether any surviving + tuples can be untracked. A tuple can be untracked if all of its contents are + already not tracked. Tuples are examined for untracking in all garbage collection + cycles. It may take more than one cycle to untrack a tuple. + +- Dictionaries containing only immutable objects also do not need to be tracked. + Dictionaries are untracked when created. If a tracked item is inserted into a + dictionary (either as a key or value), the dictionary becomes tracked. During a + full garbage collection (all generations), the collector will untrack any dictionaries + whose contents are not tracked. + +The garbage collector module provides the Python function ``is_tracked(obj)``, which returns +the current tracking status of the object. Subsequent garbage collections may change the +tracking status of the object. + +```pycon + >>> gc.is_tracked(0) + False + >>> gc.is_tracked("a") + False + >>> gc.is_tracked([]) + True + >>> gc.is_tracked({}) + False + >>> gc.is_tracked({"a": 1}) + False + >>> gc.is_tracked({"a": []}) + True +``` + +Differences between GC implementations +====================================== + +This section summarizes the differences between the GC implementation in the +default build and the implementation in the free-threaded build. + +The default build implementation makes extensive use of the ``PyGC_Head`` data +structure, while the free-threaded build implementation does not use that +data structure. + +- The default build implementation stores all tracked objects in a doubly + linked list using ``PyGC_Head``. The free-threaded build implementation + instead relies on the embedded mimalloc memory allocator to scan the heap + for tracked objects. +- The default build implementation uses ``PyGC_Head`` for the unreachable + object list. The free-threaded build implementation repurposes the + ``ob_tid`` field to store a unreachable objects linked list. +- The default build implementation stores flags in the ``_gc_prev`` field of + ``PyGC_Head``. The free-threaded build implementation stores these flags + in ``ob_gc_bits``. + + +The default build implementation relies on the +[global interpreter lock](https://docs.python.org/3/glossary.html#term-global-interpreter-lock) +for thread safety. The free-threaded build implementation has two "stop the +world" pauses, in which all other executing threads are temporarily paused so +that the GC can safely access reference counts and object attributes. + +The default build implementation is a generational collector. The +free-threaded build is non-generational; each collection scans the entire +heap. + +- Keeping track of object generations is simple and inexpensive in the default + build. The free-threaded build relies on mimalloc for finding tracked + objects; identifying "young" objects without scanning the entire heap would + be more difficult. + + +> [!NOTE] +> **Document history** +> +> Pablo Galindo Salgado - Original author +> +> Irit Katriel - Convert to Markdown diff --git a/InternalDocs/images/python-cyclic-gc-1-new-page.png b/InternalDocs/images/python-cyclic-gc-1-new-page.png new file mode 100644 index 0000000000000000000000000000000000000000..2ddac50f4b5575888d8d19cd9b6f2e3863132776 GIT binary patch literal 4415 zcmZ`-cUV)~vfn9?Pz*(Sks?SF4DHY{v_R-ZsUjdq5iyj2R83TRQ>ubMBya=-k*@S2 z3Mdj0L~1}mA_z$D@Zve|-FwgdzW2whS$p=LHM3{dH*0Xq9R2J5_h(<=`5s@q#(=Bn-Jf z-S2tM!qOTyM=GQ_F{MtvGeD=0kzPv=j*Bz!5MIOG|JTF)DzhYW(esjJ z8f05Ovk=8t?*$Q51LL3qw;pW~)XD##-`3zt|49Z~^5l;x(40MO)Z%!tAv7mko!A0n zmG#6YS#c$AIH392w1k_$~Q!)rSP0RDWQ!sH=4h`Nb>*26BS5k7PBYnJF~ zbT4h4YeC+M?a%Iny|4wBj~)hRJUqkjTZ&4xuGN!2BhK(*%O4{t+91coptKo@;$BTd z8tby(2ExM#R#22;W_ASN3no4_?B;Et>+u|1uR`eH#BUM!{+2a9O!2SDGaL z+x{Le<&h{En)7esAe?j22{GF+P z8UCG4tAF_PcUmjyag17G>?K%Ygo#Mdu;kiXRH~!owO1KUka-VjL$^T~iu-|^u@FXV z*t)x+@Ra1!*_1hMv}rjUt#m~jP)}G?nl@feRtmFl^L;= z$w$i9gtOE2uM7y16@5beh=!|xal#WO^1>CK3c3wRQPDQmnCt>Q7sNH$b#l;) zb)+(&o){N*nz=H6uIKq_vQ?(XgJ1~pri#cb=ka%tsO0yaD6c9ES|SKSB*m4xoHb>m z$_9BqP2~1b(B(d}1jpSZTH$@p%HrR&7YP!UPvAn@1#CgiS#>w|7F~|cuC?9XU99#x z$Ghr;dli0#a>^~k9QBm<6${xGj~lH05#tcZbhGmK?PS*qcRgf-H#pL+UL?|%V(#{G z2t*ZTug-}8@;so^DG_%kkv4?~h09NmYa(`53@k#7>4#RGi|03&*kkMp#~^v#%ugi8 zVN|f|WyD79+FkpDyJhG7UTz1r=5@BeD6gcRA-165an3iQxUae=c-m{u@q88<9TY1d zVULl6)!4o>M8jSY;fHcTREPMUfU3z8isR+49X@S`b$x;2*nBH&sw~D3yFabBtx!&T z+E|`(IYttvd@BxUOacm%qfsZRSw2l^cFZ~a`1)#@SN?VQEc|w^)J*8LlYu5Lv^VlP zD=zu+Q#4av36X_j0`^}w(C@vtH|w!vEkl%u@A=ABGz3vElJN@3$n|>t$FF`S#v{ia z(KvSA2ym1#Gm*+KapVLNWJVh6T%OAQw)M!2x74+-Nzuug{(c4)v7ziD;r_=Ur9o2p zZ93zl?Pq4T;F-FG znp{`A*bDVz|?V`}Lei!y3+2TSH}ph&!A zqox-2Aik@nulVg@6stEGr=~R$?}brw=3a8WNqbPFO#abgyQu-3IQMDXl5LMrx2?>w z)?K8J3+ExnBJ%-ipr2LO2uOYI@cit($04`Xa2K(v*0-i}Pt7t3V{@BE7$I|S@&<2& zd3&{qlKEddrbr;%za?J$9saHoq;8Wr-4UulLT9nhTbY z9SN)Jx0p)gW9q~zR1dP;uG321FcX!EgNsl#2wYVGTmi;w*G;8S@_jPOULQ%ByN90T zt9Rem1pENF0O;*+?-P1v^bW21RVGh8NssFpsG8X7E>Aj{EEzI%ZF}l-r}W7r-L!yw z%9fH7%f{C(EZ-YX;q zyHp$UHq+e_sIbgZM)L_y^y8AW%r(cWs&mP= zVDI9!p>wm5%dMV>s5WdZ`n@cLWuBbf>QJh4_KdtaFUl7?q=9jqn8{tN$VwNCSn8Ln zltHvz0N@b_Ua7XLt zzuuy7V$k}qZN^HneP)UTI&xm_ht zoVnB^x#18saQk(B+R-HN+#ek^h&34t(t)<>88N$x}nsZE#MGvQXeL9`VO$Vv~|fgxZUxG(+O(b+i^Jc6irFph_OD& zd5tV7qf*%xa&Q@f(S5)cdK_qf5sA_H*fm-&^kEp}TZ~mE+U?bY8x46b;`4`*QnFEw zgo?@Lqp?+|#0Ke!Pi@Ot(`BCypCHD?uhaYHVYUA6^WbU$H4*;p$GIae8b=*K&ArG* zzuLN{vNw|*EfNDmmePc}z6MdUOq3I7@^q51Pg9KnWuP|fuI`fmx^2fv>X|_XHTKLlue~_{KBZ$4PXp$#_#s+x*UPa zwMM%4Ar|Wf!v}}16|3E($eVS;^&qlVXGwajZC^~edaw{D+i3G!azPsw71~7cTNguU-QSiIGhDAhI#41P8wN=Z;8Jr4N3QG@%5e zw&Ao_myO|hIm%$EP}6Zdnq#vbKKmlFw;r|_9Vx^~+XpqF^JuLQ&{(2<$>%zO6NMT{P!G%_z@~aqz z3x2?YHLXaGd`21UD+LSO~EC;)9T#smRQaXX?+8EXbl_n_`chHawo* zh`N#(Wmj6bLNPy8zn9OV?$`Otm}3mGgnKGwXcTtr>t8!<{yDh&!1A~;V(01A0b6ZS z%8L5%dPPL@JPl8E6>p&odBe@s0;PdMm+Q7y>9pQ#l!xNmCyxQ$zj_0}aj;22_vQ!)t#z_Gs7bqTm{2b&`T*6Y zNj@A55xJ+s;$|r~0#kRv9SD;v;Tw^yLI!$7$|sdlZE_QTej6*58y4Ocn~ZSoGh93r zxI~>_MtOq!+0=_w1qQU8o=a`$(Hi2Z%9yCq*MfwjS@FiVqN7E$2FY>(vb2pl79&H$ zRp^$04WfI8rg1q-ZEN*_5aE^^G0%quH=3@ggc+|Z|0+&)VWzSdcZrU^T+!6V+<@Y4 ziRaf)y;OshyGpX>?w`s_cZ6uQ+R7Tf9P4S>FMY;~rXy}EUzBnDu7vDU$vR2C;%eK literal 0 HcmV?d00001 diff --git a/InternalDocs/images/python-cyclic-gc-2-new-page.png b/InternalDocs/images/python-cyclic-gc-2-new-page.png new file mode 100644 index 0000000000000000000000000000000000000000..159aeeb05024a3247381e1c3aec2b986035b5e44 GIT binary patch literal 4337 zcmai2c|26z|GzV1UlU^N*_SX`LzplkQPwOGiO9~_w~?}rl$3;wY$aRPjEpP|m2?rJ zmR-!@|}8q%k%v4d;R`+pL1U4-uLI6d*1h+^LgL&^H!%h*@V~t0N^w?GqC{x zC`fM)v(O8`)bGhCG@A?yWf?=9IGv3e#VmmljFh{G#RiPKn)u5jej&5;;o z8)=E~t&T2Aeq=+&9f}n5;8Aw~cqzZYcC67;rB*^zaJuDiizk4>< zkypd{HI5{l{iu!+E4ww&`yu@rH~L6v^a0C;#QkF4Q8Ax;&#ka-P(%4D9neZqraj+Q zW0Mc($GG5_SwfG4WBmty56JNFpLpyhNPcn$X?uy;M@}@U!ax)}3Z!MI`Sv4OtRaBY zOKGTOycVtl^4GCKM=8d^Gzh@KG{)<**a#`QVs!s_I|OBVLg&h$_bYccI@^USK;QI@ zd{wgimy)Z7W=4co$(u;qI_4%JwEkb%D*3{KgJxcywn!H<+|zNG?mKzNDcLe!&^$%3 zbh=Gh8vM8f$r==tNaG%SfCeTlAm_1i;K!>l-8AMisw(HkL@@@pmpSR<2!nOo1qx70 z+&{qM^LrWpi3}vK&;R20O0#ItLBWci>v~K$1fHzCy<>yikak+MfMlIAIU;)cV0?G3 zGt+ILk?>Rwl2sis&_T?*$^N%$e`5WP_upD2$%1@;@LN!8 zhKD=e$kgd(u-nvjv3b;Ra-v<;yJVMx>~rI>Lw_%G@U(d2njA8A!S?RSB!#}b^UJRd zf3|QVVi~X-D9gN{&PI`YNZWBW@4cPOY(y*vc0X#E$`9_Wh1x+aUHzim88=Qp&}Sl2 zsHhN5G=1r+%8V%x+}yN#n$&;ILl*qE)_-*8CC@|kpH^L?Gx7j@@#hD*bnzkNP^t5D zrKjPOR`iJ*Ay4PAXxQ_Ut*4u9$6?M@-@vJmd`QUlH1gbR(e^NlHgt+iK;Qd}fq z9}=u|!6ri)!vvINzVwvCZEWfy7Gt4Pk&OLTA3l^+Go!@{!%P(iz`jB$p43%N^n>FA z0p31Wb)V-AtuRsw!*(S&Ng`x_Ql6gTSc&IhlM67i&OF(?C$cV7;%f>r`!>`?>f3`b zE-`KkT+nSNPeVD1J{?tNo-}`|-Vmup+Y2PrbjxRUe|lgn>{p|& zdgvus6?CDdb7E-AtLGC7dU%jaxk}`<9G_<3Bq#X+4=JZXq#$YYTihij><63F6`3xJ z$Tq`YvN%)-K0-hC2ieB5KHLA+_WO=OL*#H1yA+gUvcE|XQvEl7bHk2Wz#AGf$lz~X(ebpht!FA-G%PP zXCf`aP1-Z;K-S5tVb&c{S?^!z?r^DH3@9BTY72*W&Of>rD$?Vqb~mnE7Y)PlTw%bi zYKc7K80#80cq7o(N}R8R#B*s{t`>R>~q{WFM91BD}6(_0CSe9 zQY!U@qJi_r==;?s#;T%t05$IUI=AQ6aY}5Nh}UrV=LFXuK^yXp+}rmnx81a-S7GP^ zgqDL&sL4v)-3HgiExZE9?8+_wlW>7ZSBVJAxI4AK6qI({mfPW2I{^UCn0ytq6HI#AuHG>9V2f&L`;r@dQn?sE zpXpv^A)kEDU{Gp7q)<4^IxS7F0U_gRF`V(P4o>vO$t`@Yc03h4TiEXWv7X6ih_9Tz zNcx2_Z*qZde$IB;;dAb7=3durk>_Yxo#eXRr95HM+4cDuvH3cO}C9oW9>YXC# zlHO`24BX0H2FbT_+41q4NYjWFUs~9}tGafYN`A@wh(-!}Tp$?|dMwaQZp}0&KVGF; z3=%W*?E9dEd9opOC^T^YgH!u}UOn+yO>zQTQ`)Z1ewa4t zH8Qh5D5h^~+n5hSUT9A+#N}N~7)8{##WyVpm5XqHNg}`|#ShO!oArG8xT1_1{Gj@R z^S<`TX3)N)9&H+kNnTw`tYOZ$Avry@O!p@?O64_ie#YxpdJV)(Thh8M9!N{R zV_33YhC8ZART#JVcFW?#DN`Jja#h*%^1CNLVI^cNkU8o(DWTW)oln~w2zkV{G)zU{ zGI^CMUdn`Be*O5wLN7nZuu~+|;@oJ;zH8+=vqE3z9;L1*ExpI9}&va*iwfp#1wAGRCS@cn6sruI%E+egyACipOqeFPO&jPVT)Wk{Our zU-~AT_fmgT~-chP>VgCCMMsy~E3Yp9#qXJ&cnyM4) z{yYkENC_`0h-jr^dW6WBX!boNI_7+{L%2Y_1I<|{(OQpmAjne|-gqqm^6U zN8qP3HeHJOOy?Wr-}?Lr*5R4&a=e5Kb*4si>|Zvf`DdwKUr>Mamy2DX!O(n_59y}a1%DtW@5GEg!`_iv3d{*&|RO_WoiAM3A(Rjn~R#&T3 zed;2t2z3-A%Bqo6%hdERe9PCxn>>9);S?MF+!)1J5zifewCZ~?M9-Cn2TnhJ&>e96 z!l3!x6s#t4UKdu-JG=$MDc!td$mLlqqB~f{g+6n_v8dR7`}xH7t8(Q+1!#OC8@d@` zN8GW$1sfhsidbpt@@fUE)3({}qCz9RGgiOHGNQ{74FU?INh&SYZ$q?>Tvu|<;(?4EBJIyTKq;GWM4jJ}#1Lo-yg*&Xha^Jsk} zfsRiqQ4;lF4=ibuB)zj+%?0wke>0yp1?z@-=j{YB|EVMiN3Y*Bg^;*{#~M zkQBDPRjUD;q{3O09OCPSf&|_LvQQ!!V;Y8a=AAXYx&-IKfH|-mX}qZyd0^_T7)r7z8UaBAyYKJ-@ss0Wt`kSe~+jlY17oB%%{>_Vx!- z2O~jt-yO#?+W6k?vUw~6=#1mU6U`?)Wki`RiF-+pI=u+?qk&FJ-kT+#)vlvO?V^e}-zAd-rILnC+_S|gFq8e+tJ&n|HZU>X)^NSG6c*b}kTvC~@ zxOxV%6AHHH(_PfR%<8}W?B?wXx`o+gAnO&SGd#rK@4Wc2$xPgXD(E>AAhq$V=vbBl z!$W6vO@sO?e@P99c~-}|P=Yt9r)(WWo1%pV$T7c literal 0 HcmV?d00001 diff --git a/InternalDocs/images/python-cyclic-gc-3-new-page.png b/InternalDocs/images/python-cyclic-gc-3-new-page.png new file mode 100644 index 0000000000000000000000000000000000000000..29fab0498e5b106f813e08aa2799602269cd74d1 GIT binary patch literal 4876 zcma)AcT`i$w?1hgARUw{9f{J5KxmO50qIqw$(14qh(JsbDTxXJq)U?;L_n&b6afQr z0YPa&q)JgiiPEkRq)6li@9)05)_d!%_5L{Lo3-cLduH~WS!ebaZ*7TYXBA=v0D#@p z#K;x^z!XON?GeTcF!q0ZnE@=I1^lB3#Xj=55SyDZAlKN{sm-} zJ!`}HQU+LYVz}2x);DtOQ-JVC`l|Pn?_Z53u?fOgU7U=cA}lNEgk!9c(^U93WCfNv zx5BQ@1(V>Y2c^0vdAZ%QVT=KDCOE<=jBo@;lEdFo`Ft5eAy5C)cWR6mQXmbdR6c>I z-?t+no<$G6!9ftS7>WN=Nm21(6Aj*m6v zG2hDuqamMe-%5tDQD8b8dg`&H6ie9asgw+x+5!_BlEW}_gTQl;hm;}s%kGopIO?=# zF@vj5VuK~bsY{3vhSbY47T^5G_%RVAx!d<@5$0>fkJNDgJ$jn1HS;Ici|%-LlOM*v zEyFvn|JUOFULzy9Bz|8;a*bH>u~!>IB84v;#f9V zNQ%3rHTl<*-On9WbJe)WsuNK4gh_|ykptC^{lKxjz{d#lN+Lk+sa14+%!tlN>;K5^ z;nw{-kAJpx{wVd-3!z6;5{PvYSHck}5l`TR43srigzkDc_A5_*TL^<{I$?Oy`Zcr&|kzYj#A( zNYIw8U}&K&?%gcy@XecV)vS0>1ox_js6DRptTcsb*YtCYN%1pw{{I8*!c-w9pD#8H zZU>Z-R?SFdv?z&q7R3SEV*}~cgJ(h1l|Fvh9te3{#}ZyTGq=8WUF4$}kqR zh=Ll1VI$~A(QqJyoiUcrzmk6tg{p#$F+T=e;)eff_YqI;$IA7vaTK85e-adGoA);q^dHQ|Y~0^jk8QZk|`$x&Eo zg;gSU-CnNQsgP?f5(*4XyO^(+IBw&Xcy7A_MJ7DIdKyk?0|t-Q%|5NSb#zpu(|q_f?BK_{umQ}r1r-xiD$by9ao*7+s?1p9L5{XI8wJk zOP(zk%r;AGf==55*XTzT$mwePpJkTOQ{)@5P5DQ5y|{`->u+f+*v5}!q3h&TMwvR) z#`HxMv#+ExIQ+g6XmjBv53%vig52PWZr^_5pYpnQpZ2V$+m6n zVCrIA-#H9c9(XxjfJ(N?m5|j3Q5;kKz};tlv_Y8IiUW3%?&;xw`Qm+gzfr9qDh>CaRVzuCj?JGXjg)+ zQE?gCedj;DHk)Rr-kD7^PHS7ypFq%v9LG>1A_k`xwbVTaGqyDF#*gqQg6tG0wWpT+ zel1cbrUHwVf8&v)#0lA>Br37dME9IqL>|Ls{4`P9%O7~vQG}={QV$pR)I;PtJBA~j zpZW!vC-MAxE3_854r-8*yxQFQ2&ps*&GfRa29wn&ycWo(X9?GIQKP{5&oGgnJ@^y4 zfKe4vlPQ-aqLp6E@S^4Sd=w6doG@+5q*qq3P&6lNZdHdEAzfcWL~a#^%`;I82YoME zX3xmYT)qM4xwLv6F}vjzGAK86+o;QH(wGcze#ZR*&VYTW=WT*Wm z*`k=Y-13EYW$S>D{f(Xbmts4jb{EmPzg#2eKRaBe^qBW}+bptH$M1^7Q;9|67%twV z5o>ni4J10fubgm7uK300>Hwy2a?wxq5<$w>RFv8r0tG37sK%6b@p`|r?*^0?xT}w* z;;kl4%3QyW%{(_ifuaI^a7BXQai3Hu7&+#ha}&*Jomd6uAW0LzX0b@ag32gf+Aam`T{eZkZZ zK_R7gh{t&V>E8K0Eb__s&?27(*UwH{{b4M=9ne2RtrqhA*A#%ICCvzqEX~o~lb0N& z+KK?Wbn9eiS9A^YsU9PixDNma6xU-ec^`^z&VVz1^x1-{li%RKU4eP8-H z?~rbODeZoA-Qx3U<%mA}cCL{9eyf83uM6Xofn2BymRjV*ueN>PyL$aatIe}?pK4?o zzf4=e*-43IAK!@}r#^AioBgn)I2a~GT4J7-w1a)(;hs<)jFtydQ5LtQH}m|@6USm( zILul(Xelj*Gf$FM$~3Spx_q|AD)tuudikP;sL_K_$x+ueY(gBj%8;8PTrBJOr<*at z?ao`6dqua@OZ@6zZCoq^gth$5}!nij!AJ@`(Hq0S#r z$Ic#l9XD9Vm}D7hpWdi_ZEAr}*5XqOgZH*agrrwoPWOhjs!-+81RK(eso{s4_GS;#ngx?sTjvB1d}_M zpnJf?>gBqgi&55BzMTCQg&ba9X?C;}LVGB(_DAhT`}myjEa>M`**rqpuob*2G}YT` zFRr7I62VF7?@j6x$vQy$_&fj-LvgZY(m2M*JG@{9mVjMx4PznqWshGgr&~jnDNv6``*I|Iul@n~?MxN9aV^=i(&%0_wtzmuYk@qT`;WTj;JF}j&zcd? zy{d`QNi~<9VW)Y;N>SqY=0F90Je5FRPopTok}nzAC8qWW1kJ5FrqtXsP8_5l&wFd@ zg)&nN`3ca)w3PTjbHNxxi_n_w&5^4B?O2=PPO9Q4udl?Bz&2nblw?PO4x8}VvKoEn z3h{dB!p9mU4ifJl2tWWyo%T)y>+`SgN3v-HPAMjWU)>6HdI$Ca(o+BOZaeW$0>Lod zikCVGA{ceIS|Wq$PctDWIeq!WlbUN$9n3-jRez=TF7kYlb9_X~cOa9FJM=`Q#+KZ3J$p-~2#B_2$*`y`1PX&zkmIi}m3f*%3A`Fr@6Ot?Hy51)D z#)zl_X72l|$P}g=6A$pW?|mQgZF2~Thm*~N7tH$29jAK5WvS|GYMrs})ctM?z8fnO zYuRs;e{sAtBmH|Qy$X>Y#7^@7c_o-Y@iq5RD_O}4PJQJWlIIf3fSBy=gI<8VwXruG zfc``^QO@~5g~|&gN5y+DH9EvOoqh|YT3{8((RK$nd>69SlA5)e(gl00a|yLs9Go$Q z8y}a@S+4q4{8_GbUU^FIExhiWw7Wu5BkS=wyKqXNGj>fo5niY}0zxOWP#64j*k@Z% zd6UO^-g&HsA-J!AmoLG z>sl(Gvt8hF!0Y?MW}B&y`<92S&obG&NeIW8G(aJXOjezuXW`(E(Olo_b(d zF$;pZjt-W#q&!IADK;bCeHX~!nMWD64y0`uVwCzK=P|OmuvqxgiwfkE2sshViRpSJxM!2BN33vB1Ghrxmfy7kFsq{_ZVu*~ z*}I?DtL6eOtPrak+Ds=_=W_c0Xc~vltxR?_e*J*X`4MEi?8;$^RIH-6O9VWOyD(8B zK@4DSoq99iE;d#vXn|v8e>TPSEpQ~r=vNz9FZJS(DV%Z(yc*bZ@lB*!#}&!F?`{P5 z%V=2m6_R(m&`s*c?X)<#XgiXDFbvjeKpC?vm30ZQ_h~QbUubCoLb^=80+QJ#Mt5DJsz~qyZn7m+C#ZWkHH&RY`Hg2ikKXapFy2~KYn6zhDBSgSmsi22X& zG1HeqSiPTROyGM{Y`T2Z6N^Ke1@``O^)hY5y;)ZDd{-x!bU|BW%lY7dHT;chvQpWX zWy(2vEi#&gG!j&9&8R)azzutD|JJKxd548NL%2AEs0;sAvkv~Gg1yMbPsd0lh#$wM zbO>MWjj6s{zcO^*e?E7seEpSJ=SO|gLJy~PN5=$4@U30Ty}znFqaPB=e&S;#)XIwD z=^lbK1_hOXduZ1m6yPup(-*PFjO9{;S{?(mC5IWarm}j=>y)|Xr zBRmxB_gC4T?QcQhw_5X$ymF`tRQxRt90EgZAV2>l*7sDPT7U=so}n|zV9q&Vy#By= zBRoUA833p%tEej|YbvNJ+p8)gG?Wo4XHF|CBb1ei4-yVltA8B=gS`BFZvNj6Ke|;L Q7!H8xIZLBjLyz141yIB0(EtDd literal 0 HcmV?d00001 diff --git a/InternalDocs/images/python-cyclic-gc-4-new-page.png b/InternalDocs/images/python-cyclic-gc-4-new-page.png new file mode 100644 index 0000000000000000000000000000000000000000..51a2b1065ea64eaf009a96ce6fecd3132424ea0f GIT binary patch literal 4863 zcma)AXIN8Nw?0WE)W8S|NY{Xl^r8ZRK$LC)DN+R-YA{j_C}1ENg@{5B5k^!X6k+HJ z0Y+jdA{`}y6oCY000}}2NNACA<9Fw4KkoC~ALqRL+2^di)_T|8d+oJTF526`MC3#O z0D#%qS~>v$n9gqx3h`fnHRg9eJ_twHdR*tD?LQvt9*h~k0rop*V+rgL)B9ThK=QPm z82#6q+FnvrGKR}ilyOU0y zY+V+9bjatnv44;l36k}t$h^E*-KqRb^RdToT1q``4)%zjQR5@b*weiPHH>@Y2F`{^8;(ZxEGL1ZeRPC@)!%C-*AK#zFskKZ|H-ou3>c?44}EH&+LWMIAxb5(i}$3dChM z?u`r63*AJGT^zoUyxq_U-b}OlaGjeKUYaILw>LQa;PyuE-~eVFB5Cj|pcSV_hC9{R zrZX|;%nd_<=}yW;yfjjo{*e~b&$5dKBMQ>>c#A`4_{#5~Hbhbm1z|;gfsPkE(Cp=_ zk%1sAGMBPQpRPc8s9I+*h1G#i=+wBs56x%t-%kFgum5!NKYc~<1%B}QzjWli$aH>T z=_`abF1^Toj?c~vu<{jUk%78dBc8c~a^hud4DDfEv(XjQ_CW@946;K;FMHEb+L=q}txm9*+-at9*R-lvs|Z zDHpH4%Qk@THrX_p3Q|K`Wiyuc^EP;cUcKBv zYl`&7?`qmp-_L}Sch=%nQNFutI?RL5YVxx*P>D)qbAkjCm>VU(6tzwRaOtku0sHy! z{xKK+KY#%gOV>#JS+b*s*S`1zqw(V9w%vzOi3R&TMd>iSwxY`c@&?e^fknEfqf{;LTXW)tP| zTBuxr1;d+}9+pp~U+>quWkWXE_t46k#U`xF0WJ`-gq{tLgi05AI5#H1N_{_WKPOGv z695vnvpvMKRZtu-_M(EO#nhV>Bwi=Nv~sq(#DvU|YoY^v+Kr~?mI{`z%PvF3x} zV^$V9tY3NK>V`e}l7l6Js(>bHv;C%}6PkVeDC+c#;?esytg)++)_>&HGAkJIgqU&_ zr=$+l{K@F}3b{Yh@@ukWs}5P1$X2{COfY{af$)mG3r?l;$jSzYV zn2x(ZHa|)CcJTiwVQj{-e!D4#k{>kEABM^$L89KGNhuW<@VjL1!Bi7~ou%BB&>>nu zg;88#@?CTe)e+lu3_!GbrQTY-SPf9r;C^@7j)C0ZWOH<*d!0?TMf}61%YkHbUApHV zRfL4mG@svsfhUU7BJtcbyjgr;-En$pOy;RT2{H|Crzj7?t!Q8SV^_cUF#WorB!Ux( zeE0H#5+eBFF9C4!fKt;_Fz%XR#n(2ko8j4z+>OpzYm_pK(xB@*y>+_ioihqSeETWDiZgv{QiSDCMe+=L>a_6u_$7ps2}+1dF<>5_VTb)u6hXuVi{iu^ z@$wKH+Rc3YtADtNa~PD{);cJU&7gvE?bBOzgt-u&AI4bLUtuwg4ueg$$b-475Tw1p zEo)F5hJ1aw2=G>9y-yYLrpai4xo60wB3ORcA@sq!mbn6~P=a=EaLIcidKRIf$=$cf z9?z6!k?r)|yq>9|@~gk-_$CU`y@1>YTkFMHCInK#bB(i=V6GxN8&<2Jcl`ve48UR_ z8yxF*vg7D^lQ|^`WBq@yo(k#WQXX`KYokM;nWqpQzol1LxDrL5Ae*1}@ zqY5$OEo>=k_I%yWnM}GLr?Nj{QfE%{vcp|0~DGD^%qpU zm(TGTya+dzeXL7Eek0p_WT8R*_&WrJchMD-A>YI5V}@iKf$`&w0bTcu!}7=Z3u5PT zoiPH-kU#zA2=Bn%n}>t2 zb{fGm9K1NuZ$a>!#2)rZapaw2j4r6j$>vwzqKB_;(2DXc*iLaBx9{v16g6KPz~i+8CD(>WRG04|)W1HoEBY9_yaJ=C<~f~q4z|GK6d zk48(2LcGS>(ee6Y`9W=riL73?GbCl|a(?~zn&@~{1~CS*0G3HsV9*C!2f}Y8%k{b@ zBqWe6RC@I9obQ}zW49Y2d-d%~3M|cc9F#r$o&~pYL|)#4QWPbp&bumw7;2*%JBxpU zgy?Dmy!nJ{*RH&dG9j|JUklUKYQ_GvCs%x_*<1eFyFSI+3U1k5-Mcm#CP1!I^Y~ch zJ;nNL$*tMjY_x{@Py?j{HO#~JQ5sI*abR-G*i~xC=tdpK{pHQ%Fc;)VXsRr4ZvKD> zy$>%Q!Sp%+it{2D6<+EeRzD_8uZx3W`wZ=c=+Sul7ZFR2`&hlG%p`?EfEFo+RL{K` zTb&GeLs&~R&S5?72+AOHoAZYx8dDW*rhNAESQ)gT(OESQIswZO%T~?2pgO}9FKZn6 zo)KUks!ZEllSXX>Kd*6~?+ZdXloox$9;0U_{+b*78_s;ITq4O-L3J!sb6r%!QuVq1KM1U=m5FS>Wb9}noiWkq~c-baijNv(*p@K z7=5{Gq1vJpJE__C;o$5qvFof0hD$5WS9%Y4SsQU+2Noh#k1H^jjDKgo=|3o?V}t`( zX-$q2Xw0Mfk@8_w{6i39YwsH&3d}+uA7mO~0vNT&v6Qh^Ky8fizv(71LMD{S@OO@jO$IB3FA`v@1IO znTTKbi8B?~sOY9Hg3_fMM^gTzoX81y!*aB(_#A>Z_%ZYsQdSmmR2d(mM-pjQFt`&^ zQ2DaBeW7B+6Z4ZDTlRr%MdhXJa0^m|GJQW>O0(*CumHpq>O{Rf+_<8JWB*JO9}bzOTiQ}Y7t=6%Ev4DBm(@i&h!DtSmhr3Owd;4 z%_iao)5Ov`wK$3&g&Qw|QTeCTs|4c!yU;RTU$}HhJ0|V^UG#2RXsyC?-HjXb1p{`4 z!yR7M06wM89~b1fGrKvY5#!FGjl%F@V`)#|6#W2K%#F&{Oyry9>n%PpM+6zKD(%L|6(d26|LCG|-`)5adrs-6C+dNE&?gAwXDFrvLfw!J?xy+E7}mlV~c zk`%TDKFfCBiga>3^Gy8FCn&3sVDvcN7bnsE>~e~29F{nJQmNstLW$PVPT8!PyBV5D ze(p5<(wRpb&A%XGvl;s{*W<>}960{>W=N+LJ;77G5LUI`ET~^)mP#i2wurLC6f0{L z=+q%&xRR;~a??UgQ5~qm7#cQr0{_V{hbH(7{_#~qYmlI2RdpVzjY3Z59;z@Er zbb9?zjC^#_`k!mz_K&?pPMFNzbeG$m03Bpxe8R9h>okcC#Q0~LS1Qk~4(`Yf#Mn({ z%yqv%>fduEt4{{?+vy5zy}YXP!56)mOC9&tEoXP?*-kZC^07vdI!bm=z7-H@_0DY- zcL=HCB?I*qB>u{XMp8J}d^xFEf)pjzU+ojQ4Z{<(7I*mmvV2+tL*~}ng=WUF?+A>s z0yo6WB;R^l0VQZ;1n;vk6pW+1II(h)@Oj!l&Yrvgd!(t%P(nleLq6UIGn#*#_i_T? zWjf%iv*v7>uBNYj@OgF~uEuuwYBBEJ4-*!rJn_{+6gOO|UJxj5=7EKLFcdDjU6D@D zl3*Sn%YYS60GY0U;`o@?iEmO3@jCS5o%L|;i`xWcfYCkhdN8digsRYY&s|5Wr3JHx zSImFGAc`|DL$IA|5YmL~rZ_7ofy5e9Kr634Taxip*QFOxlxd59fNbzuO z+f#zHRHdas%p)1B2%{38=M)X||NouRD08~fs7FgmDk5z2UoYP`HR`qa3;?wz!G=EmDUuNZx%pi$CZIprNv1WZM zCJrK@$M^$aB^X5e!=r+6k7v5MIKuk}6h;GTad*3@eCGDXuFmH0_iY#aFe4>U%`A{$0@ko)B3wL z`e#ayX0qka>ACrcM#OG}z3vxcpx@0mym2_!vc=gPt&llWuU50>WOKW@(d!`95t-~- zyC8I+rUK`*P2O#)ju=CxP=0qxM|x%Z$lPOR5FjL6g*{N)SNp0ANMvs zUV9RccxLc;?>f@1$~0rl&0%X|UA&dT1h`plJI{|Ce<0u%rM literal 0 HcmV?d00001 diff --git a/InternalDocs/images/python-cyclic-gc-5-new-page.png b/InternalDocs/images/python-cyclic-gc-5-new-page.png new file mode 100644 index 0000000000000000000000000000000000000000..fe67a6896fe4b07c03291ca8b21781fde8785757 GIT binary patch literal 5712 zcmZ{oc|25W{Ksd(U>H&MeTi&kD-6RRYgw`{4T`ZO6oaB+CgB#@ibBH?ne3G1rjSZx zJ@y(GNf>)HBujpC@9*CG+g`sv&iOp&`99z0oaghL=e(ZtzHMh?&dn*p34uVkEiF#l zLm)7aSsr9(o*-sHPcJfsUr3MiX71YkS z46$;&&OfOq;KkV&VAeD?n6jEu#b}*Z-deqM^y;-f+eey7Npi>dh~_sRV&$;Or(ty# ze+x-XsESiz@uTdi-t6t>$w z?tqJflHqqz=fsXi>wp3X)|aM<0RvPBaoE)TL;G*cej%#ZWR?J^yBrn?$}oiwFoo4I zy9ZeRiDl4llWn9qz{hKd0HiE7*%L(=Sj$wrCK|Z07epI#mLCA%?Z=F3hX(xC6KHE1K*+6MMs3EA3G_fVf7p{ zopk@Yk-5&Z$QnEt$r3I1N%5~5!x`=WJ}!~~(=Vv|pTcyOB=FBD|Ic8VvHxrm^6`VB z>*F={09~pb0|!-A_;9C18CZZ;pi_TQx8`}uCsq83$p#z&*?isjtt#SQ%+;dOS2DFwE<5o-+B=AxsXVWaCp= z>uK#VnD~V+CSO=Mbe)xQgOOnL!)eyumioLPa)XO4*Ac+bNI0^4{AAaeT%wP*3ye}- zu%LvEOXTVjINl_9aZWghyCAVQ9Ky+Tg86L7f8;NFnA85JOaBU; z3P&d$GPYng-N!*D8fBhJF*BxE!KQM)Fm`Z?2Rv@YrHYL+$Bs2d)WaA^C{EQ;0PqJ^ zE~qmCol;&$OM%Xa&AH|HYAynoIbQdDM=wRGiIpCOaaFHzy;dTF?JvXqF(rm)X%ciz zgEvW~FY~8$IW&86O?U)tO3w-Tq^i_N2!#o8$t9#;n*$E5wE5IP{+%ZV(AxBoaIc&mHr&Em0-=x)oWFQeB*m-=|q-OvgM*1<0eb6?4 zo|Rro&R?#a!o&L4s&*?Zc0X^bD&|M-^Ohj}i)YTpY4%7q!E^6MNCKLquTHwJ z}eWu5d}US28D?~qLlHJ)ZF6RE|R!%`wp#f%FnG3piiS#QU56_MC1|Hs1uSEH`7QG~=s;SL4?8@2ZHAE9Y(MErPitJDJ_t(^F24pmdi^G*yy>7k1HP;Lg|#G zVmRiSK8T4nqks2UP3j@n9P8yy{;_pR5?NPY7rFXnZ}Mw!r#Y08E)d)+_Ye=^UyG;8;o%muPF(SRyRID8m(z8 z$%=%a6D$|Jc`{WN-=Ab=TF6BYj*Iv5@|h?aoC^P%ZYh6Q5<*BxDNStAkgiQ6%jsn; z43n`B?5w;uN}-rrR$(N6#|amW_a{5G)2(_Kz?|{Ot-H~veS;#3@d$0tIAkJ{~2Vz3@gi9(ZmU^{1ER9l+K3i-@yi%yla|zcZc~=i&FwoAB+n4 zw=6qr%{$K})dX_{S;s&rZ_Jc&!v|9c!fg-B)~5$kLG4x-Lbs0D(3ab}cMjH;3f10B zYMJN8IIQ3!w?hDA&&o(*a!JmKMX5D7t@LE~mf*qaiLPe_!R=ilJQ~L*`S|lu^z%92 z&4)G;UL7-{c%J|D>%;7EDio*hWlQ7%pXlDq%k8U?WNAtl+{DTS5yvlio_D8i@?z(0 zh&M{U;dnf0wV7WpioWyAnTONlGo2;^QLcDl?qzIpgZ$B;r{v}FR|kP_6axu$5P9wQ z`C>iR;W`CV^$90M&WaN%E`-g~O1`Iuz%Y$3>zs{~?BWx<^(jeT$yFM9PtFIP(Lcn# zR+z*hb#`jfC58ob-sM+z?s=86m5mVQKkK(Cg8QP+K~v^ue{ECAqpL3p4k$fex407? zF7=h=F!#pqdryz)32_M@M-=BM>9KItk-5T&$$H)SzZlP>^4{{udc^H@9C);>vKb?i zV%-($3Kx*T!Cv+Zf2PZ%kUv))BI>LEGtjJQ&Ut4(V@72b4u#h871(rK!uSlidkFxLm` zXMOZoW>>!>o^Sd_oMg%K+>Rf;1F4kVHvbL7KC=KPUEtYbh{jT4$y5p$cfA!Ss(cW3 z$`~6CcR;emUYMGkr@mp6K8NE(||!$-fpFm?WiRI|*PvIber#KT}&&dSB8 zNAulb_tW(4rOsBZnT4m|>KgWa&dqEjmi@X|UaX9TZ?_#R34@Vk*X$kgL~}inTBOx} ze=PO(-B?)DzNLk)F&Zi^0V8m>DL2Y|)p45L|9G(2grFL-%kgGMxKu+J9r+o&7XI0j zcY-}6sFosQliv)SRyST*#Dr_UMgkoT^3SV6cT_=_2q@$JVG*y;1GhsTphp2p{gxEq zlAV_QUBYwoGoyf(!CxEkQyD6L?qQQwZjlTqjj~V?dMaM-X@~E2MDkC)i_Ie+|4jw= zsHdrEfd{s77Qfb|m^gY=*?Pzc{r0yvu^a?n-J{Jb3Qty!H;Ohd8lfykfNMCRb4VFY z0qm~3?YP*D2Ur&*x05Zekd{_?0=bf*M(cA-&>aDrguolooRGx)7u3e(HxR60B!Zb6$wJIiCd_@55hyfgfL zdQ4m2RaHyuxwA;VmRh8`@wjgHg{c&ceh7i6iEo6`1zu#SIclVys@w-XRpfGZb72kv zp;e03rHPH>MSH-#X%VxIB`W4i>#Nw9)AqQ$C2qPdiZelwCt>Y+`jeG+8MLaGCcY^twGpkw`gmPh zEp7G%$wmp!+B_be#6zcgy&C%?E%w=K$%BPB)TN*O2kDaydcoBjW331M@wpRINIq1#+HfGkO z<_?VTl5I%ZMRm651X8Ox5j{m`D8nh-J?%%5Ap7pvdkM?;AQ(S38QtZ^=@*dwD?m8= z^kUl$FHXAi_VWm+ZNsSh)L27dYW?UvU+qzZLMX1H_=lXZs^wOslx5J%LmHOjVl{i) zXrQuwG(p2NUR>di4&%u`#;Z;^(ss2+C{*#^skD##>VjSof4q8~;(PpGfzqD0YB`F=+QB)vGaF0-SA9(v2m zD7)v%!zd0)X~7LYu?QzickxFz^{mHK4O-X&%1yp;=HD{l4fM9qP!_7@rE*x@id4Pr zi~S}No$u&z;|BF)LW@*PTqxH>%LjLPsqjbfoYKb##ZC%a7=~koIYM zmop%$v>&!H6j>ts>Fro#j5h2piQNFh+hXu41F>}BO1;FV0y1*BV+8w|&LD6jir zy*q@`a7%17vnRQ1U@I=&Qi)>W?v#xcrA~ZoyOiM%yzP@lu-zQ~IfD(-gHFUg!K=F% z=G4B$4$2xTfDWBTlW@W#^wjFh-*^+2-S65>^U?bpXLYksU(;ZeEF51c&PZ-IGU?cP z*hJAvNswxe(}6Tl-j-=WEfvohUnv}&Wv8gK4D$vIt?K}H%dTk4JC8ysU_W-Kmw)h4 zuTDO{+s_JYsKKjPmL}U$#KsX#-$7+(mM~BM;Sg7m%9PI1^+dhVqsL8BUqJ&N3<997 zy2<4P@O>ugy9e`?kjkLdd!;*#Ds^|K%T}?{itlqZDf)f$HMOl)nkTMwteuvk_!&)A zoi2|S4%^-*tvcO-L<$vtDzy?9O1BRKsp;_wnkDT9QI*yGY=kLPwPXW~8zNuZ?je0Y z5|S}gY@jM$kG^$CrIXZ^@=?Y+z6KIqg>dE2f;`oEzb-BJY^d_$<;ms-Vx`H&H{kK! z#Y5Rv%1V)4VfVY1hfwNT z<%(24Jfird_~p8}*k?aLcISR( zfzGM#J5P2=RWy~~xPcaud|-@NBe2KYrVfhtTwezL=fu_epP{7nBmfqLFxC36^5HbD9{^+0UkD5UyMIH=sPI4l(<6B?wq-}UIHOP zz%^XE3oF_^2M<+yRIVcz-16yE!62_qYSrLwN zA{pp^6;dgKOq`t_{xbXrhFmoz0-hro7$hD~PcqIdzPZ?A3cNfF&X|dNDPR2&$diC( z2jvi4a^)@v2u3{hhc%N8(CaRU#;*y}*Dq&1D|{Wd|0L&FU4NowN}Xq4nq06 zh0RUVXHjD^m8I-Nd4Ss49k~m)mT)cIE`IidI$@YSt2QR^A@(&gNXfW>gTCd41;HmdEn~#_NihACS>I&lmmz4Qi;myqczM4#*1lG3RG~EIHVNI_Y z_;0ig=AO_+DVApk+=!PYw~QeXDwlQ8!DFJ3uGtwTOM`>epL+F3@@EWRrRp*P)Q$jn z0+0Ha_56+h{u6%vONICVFL=NStYO~X7=$JXW!#ln`Zt>VTmFWl{Y3|ef%~pM z3N_a7Ojdi8VCqWny+FXDeZufefoQ0yYpJSft7Ulni@p(`R@Nn d2oCiP^t=B5CtNi{nllq1mZmnRtBk#G{s-d0T~Yu5 literal 0 HcmV?d00001 From 21ac0a7f4cf6d11da728b33ed5e8cfa65a5a8ae7 Mon Sep 17 00:00:00 2001 From: Victorien <65306057+Viicos@users.noreply.github.com> Date: Sat, 12 Oct 2024 01:05:13 +0200 Subject: [PATCH 124/247] gh-116938: Clarify documentation of `dict` and `dict.update` regarding the positional argument they accept (#125213) Co-authored-by: Alex Waygood --- Doc/library/stdtypes.rst | 25 +++++++++++++------------ Lib/_collections_abc.py | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 833c71c4ce4b9a..a6e2e3b8928ebe 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4505,14 +4505,14 @@ can be used interchangeably to index the same dictionary entry. ``dict([('foo', 100), ('bar', 200)])``, ``dict(foo=100, bar=200)`` If no positional argument is given, an empty dictionary is created. - If a positional argument is given and it is a mapping object, a dictionary - is created with the same key-value pairs as the mapping object. Otherwise, - the positional argument must be an :term:`iterable` object. Each item in - the iterable must itself be an iterable with exactly two objects. The - first object of each item becomes a key in the new dictionary, and the - second object the corresponding value. If a key occurs more than once, the - last value for that key becomes the corresponding value in the new - dictionary. + If a positional argument is given and it defines a ``keys()`` method, a + dictionary is created by calling :meth:`~object.__getitem__` on the argument with + each returned key from the method. Otherwise, the positional argument must be an + :term:`iterable` object. Each item in the iterable must itself be an iterable + with exactly two elements. The first element of each item becomes a key in the + new dictionary, and the second element the corresponding value. If a key occurs + more than once, the last value for that key becomes the corresponding value in + the new dictionary. If keyword arguments are given, the keyword arguments and their values are added to the dictionary created from the positional argument. If a key @@ -4669,10 +4669,11 @@ can be used interchangeably to index the same dictionary entry. Update the dictionary with the key/value pairs from *other*, overwriting existing keys. Return ``None``. - :meth:`update` accepts either another dictionary object or an iterable of - key/value pairs (as tuples or other iterables of length two). If keyword - arguments are specified, the dictionary is then updated with those - key/value pairs: ``d.update(red=1, blue=2)``. + :meth:`update` accepts either another object with a ``keys()`` method (in + which case :meth:`~object.__getitem__` is called with every key returned from + the method). or an iterable of key/value pairs (as tuples or other iterables + of length two). If keyword arguments are specified, the dictionary is then + updated with those key/value pairs: ``d.update(red=1, blue=2)``. .. method:: values() diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index c2edf6c8856c21..06667b7434ccef 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -962,7 +962,7 @@ def clear(self): def update(self, other=(), /, **kwds): ''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F. - If E present and has a .keys() method, does: for k in E: D[k] = E[k] + If E present and has a .keys() method, does: for k in E.keys(): D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v ''' From 979c0df7c0adfb744159a5fc184043dc733d8534 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sat, 12 Oct 2024 00:31:06 +0100 Subject: [PATCH 125/247] gh-124309: fix staggered race on eager tasks (#124847) This patch is entirely by Thomas and Peter Co-authored-by: Thomas Grainger Co-authored-by: Peter Bierma --- Lib/asyncio/staggered.py | 17 +++++-- .../test_asyncio/test_eager_task_factory.py | 46 +++++++++++++++++++ Lib/test/test_asyncio/test_staggered.py | 27 +++++++++++ ...-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst | 1 + 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py index 326c6f708944af..0f4df8855a80b9 100644 --- a/Lib/asyncio/staggered.py +++ b/Lib/asyncio/staggered.py @@ -69,7 +69,11 @@ async def staggered_race(coro_fns, delay, *, loop=None): exceptions = [] running_tasks = [] - async def run_one_coro(previous_failed) -> None: + async def run_one_coro(ok_to_start, previous_failed) -> None: + # in eager tasks this waits for the calling task to append this task + # to running_tasks, in regular tasks this wait is a no-op that does + # not yield a future. See gh-124309. + await ok_to_start.wait() # Wait for the previous task to finish, or for delay seconds if previous_failed is not None: with contextlib.suppress(exceptions_mod.TimeoutError): @@ -85,8 +89,12 @@ async def run_one_coro(previous_failed) -> None: return # Start task that will run the next coroutine this_failed = locks.Event() - next_task = loop.create_task(run_one_coro(this_failed)) + next_ok_to_start = locks.Event() + next_task = loop.create_task(run_one_coro(next_ok_to_start, this_failed)) running_tasks.append(next_task) + # next_task has been appended to running_tasks so next_task is ok to + # start. + next_ok_to_start.set() assert len(running_tasks) == this_index + 2 # Prepare place to put this coroutine's exceptions if not won exceptions.append(None) @@ -116,8 +124,11 @@ async def run_one_coro(previous_failed) -> None: if i != this_index: t.cancel() - first_task = loop.create_task(run_one_coro(None)) + ok_to_start = locks.Event() + first_task = loop.create_task(run_one_coro(ok_to_start, None)) running_tasks.append(first_task) + # first_task has been appended to running_tasks so first_task is ok to start. + ok_to_start.set() try: # Wait for a growing list of tasks to all finish: poor man's version of # curio's TaskGroup or trio's nursery diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py index 0777f39b572486..31d2a00dbb8c9c 100644 --- a/Lib/test/test_asyncio/test_eager_task_factory.py +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -213,6 +213,52 @@ async def run(): self.run_coro(run()) + def test_staggered_race_with_eager_tasks(self): + # See https://github.com/python/cpython/issues/124309 + + async def fail(): + await asyncio.sleep(0) + raise ValueError("no good") + + async def run(): + winner, index, excs = await asyncio.staggered.staggered_race( + [ + lambda: asyncio.sleep(2, result="sleep2"), + lambda: asyncio.sleep(1, result="sleep1"), + lambda: fail() + ], + delay=0.25 + ) + self.assertEqual(winner, 'sleep1') + self.assertEqual(index, 1) + self.assertIsNone(excs[index]) + self.assertIsInstance(excs[0], asyncio.CancelledError) + self.assertIsInstance(excs[2], ValueError) + + self.run_coro(run()) + + def test_staggered_race_with_eager_tasks_no_delay(self): + # See https://github.com/python/cpython/issues/124309 + async def fail(): + raise ValueError("no good") + + async def run(): + winner, index, excs = await asyncio.staggered.staggered_race( + [ + lambda: fail(), + lambda: asyncio.sleep(1, result="sleep1"), + lambda: asyncio.sleep(0, result="sleep0"), + ], + delay=None + ) + self.assertEqual(winner, 'sleep1') + self.assertEqual(index, 1) + self.assertIsNone(excs[index]) + self.assertIsInstance(excs[0], ValueError) + self.assertEqual(len(excs), 2) + + self.run_coro(run()) + class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): Task = tasks._PyTask diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py index e6e32f7dbbbcba..74941f704c4890 100644 --- a/Lib/test/test_asyncio/test_staggered.py +++ b/Lib/test/test_asyncio/test_staggered.py @@ -95,3 +95,30 @@ async def coro(index): self.assertEqual(len(excs), 2) self.assertIsInstance(excs[0], ValueError) self.assertIsInstance(excs[1], ValueError) + + + async def test_multiple_winners(self): + event = asyncio.Event() + + async def coro(index): + await event.wait() + return index + + async def do_set(): + event.set() + await asyncio.Event().wait() + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + do_set, + ], + delay=0.1, + ) + self.assertIs(winner, 0) + self.assertIs(index, 0) + self.assertEqual(len(excs), 3) + self.assertIsNone(excs[0], None) + self.assertIsInstance(excs[1], asyncio.CancelledError) + self.assertIsInstance(excs[2], asyncio.CancelledError) diff --git a/Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst b/Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst new file mode 100644 index 00000000000000..89610fa44bf743 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst @@ -0,0 +1 @@ +Fixed :exc:`AssertionError` when using :func:`!asyncio.staggered.staggered_race` with :attr:`asyncio.eager_task_factory`. From 5a074aab845f82f4a150c27b905dae05c337d381 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Fri, 11 Oct 2024 21:40:33 -0300 Subject: [PATCH 126/247] Doc: Fix a typo in "Function Examples" in the control-flow tutorial (#125338) --- Doc/tutorial/controlflow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index fd765e58ff2485..9b73ac475c78d5 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -832,7 +832,7 @@ parameters as there is a ``/`` in the function definition:: File "", line 1, in TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg' -The third function ``kwd_only_args`` only allows keyword arguments as indicated +The third function ``kwd_only_arg`` only allows keyword arguments as indicated by a ``*`` in the function definition:: >>> kwd_only_arg(3) From 5d8739e956cd20d3860133b384518a3c5c74e5ae Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sat, 12 Oct 2024 12:40:34 +0530 Subject: [PATCH 127/247] gh-111924: use atomics for interp id refcounting (#125321) --- Include/internal/pycore_interp.h | 6 ++-- Python/pystate.c | 54 ++++---------------------------- 2 files changed, 8 insertions(+), 52 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index d7e584094f7839..36cd71e5a007d5 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -102,9 +102,8 @@ struct _is { PyInterpreterState *next; int64_t id; - int64_t id_refcount; + Py_ssize_t id_refcount; int requires_idref; - PyThread_type_lock id_mutex; #define _PyInterpreterState_WHENCE_NOTSET -1 #define _PyInterpreterState_WHENCE_UNKNOWN 0 @@ -318,8 +317,7 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst PyAPI_FUNC(int64_t) _PyInterpreterState_ObjectToID(PyObject *); PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(int64_t); PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpIDObject(PyObject *); -PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *); -PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *); +PyAPI_FUNC(void) _PyInterpreterState_IDIncref(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *); PyAPI_FUNC(int) _PyInterpreterState_IsReady(PyInterpreterState *interp); diff --git a/Python/pystate.c b/Python/pystate.c index 45e79ade7b6035..5d94b7714bd607 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -523,12 +523,6 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) _PyTypes_AfterFork(); - /* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does - * not force the default allocator. */ - if (_PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex) < 0) { - return _PyStatus_ERR("Failed to reinitialize runtime locks"); - } - PyStatus status = gilstate_tss_reinit(runtime); if (_PyStatus_EXCEPTION(status)) { return status; @@ -629,6 +623,8 @@ init_interpreter(PyInterpreterState *interp, assert(id > 0 || (id == 0 && interp == runtime->interpreters.main)); interp->id = id; + interp->id_refcount = 0; + assert(runtime->interpreters.head == interp); assert(next != NULL || (interp == runtime->interpreters.main)); interp->next = next; @@ -989,10 +985,6 @@ PyInterpreterState_Delete(PyInterpreterState *interp) } HEAD_UNLOCK(runtime); - if (interp->id_mutex != NULL) { - PyThread_free_lock(interp->id_mutex); - } - _Py_qsbr_fini(interp); _PyObject_FiniState(interp); @@ -1031,9 +1023,6 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) // the "current" tstate to be set? PyInterpreterState_Clear(interp); // XXX must activate? zapthreads(interp); - if (interp->id_mutex != NULL) { - PyThread_free_lock(interp->id_mutex); - } PyInterpreterState *prev_interp = interp; interp = interp->next; free_interpreter(prev_interp); @@ -1247,9 +1236,6 @@ PyInterpreterState_GetID(PyInterpreterState *interp) PyObject * _PyInterpreterState_GetIDObject(PyInterpreterState *interp) { - if (_PyInterpreterState_IDInitref(interp) != 0) { - return NULL; - }; int64_t interpid = interp->id; if (interpid < 0) { return NULL; @@ -1259,50 +1245,22 @@ _PyInterpreterState_GetIDObject(PyInterpreterState *interp) } -int -_PyInterpreterState_IDInitref(PyInterpreterState *interp) -{ - if (interp->id_mutex != NULL) { - return 0; - } - interp->id_mutex = PyThread_allocate_lock(); - if (interp->id_mutex == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "failed to create init interpreter ID mutex"); - return -1; - } - interp->id_refcount = 0; - return 0; -} - -int +void _PyInterpreterState_IDIncref(PyInterpreterState *interp) { - if (_PyInterpreterState_IDInitref(interp) < 0) { - return -1; - } - - PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK); - interp->id_refcount += 1; - PyThread_release_lock(interp->id_mutex); - return 0; + _Py_atomic_add_ssize(&interp->id_refcount, 1); } void _PyInterpreterState_IDDecref(PyInterpreterState *interp) { - assert(interp->id_mutex != NULL); _PyRuntimeState *runtime = interp->runtime; - PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK); - assert(interp->id_refcount != 0); - interp->id_refcount -= 1; - int64_t refcount = interp->id_refcount; - PyThread_release_lock(interp->id_mutex); + Py_ssize_t refcount = _Py_atomic_add_ssize(&interp->id_refcount, -1); - if (refcount == 0 && interp->requires_idref) { + if (refcount == 1 && interp->requires_idref) { PyThreadState *tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI); From 4a943c3251d1b3fdf50cfb9264ae74e5bc845c3c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 12 Oct 2024 09:28:34 +0200 Subject: [PATCH 128/247] gh-125196: Use PyUnicodeWriter in parser (#125271) Replace the private _PyUnicodeWriter API with the public PyUnicodeWriter API in _PyPegen_concatenate_strings(). --- Parser/action_helpers.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 24b817c6f8ff27..cb21777f566189 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1615,7 +1615,6 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, } /* build folded list */ - _PyUnicodeWriter writer; current_pos = 0; for (i = 0; i < n_flattened_elements; i++) { expr_ty elem = asdl_seq_GET(flattened, i); @@ -1635,14 +1634,17 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, "abc" u"abc" -> "abcabc" */ PyObject *kind = elem->v.Constant.kind; - _PyUnicodeWriter_Init(&writer); + PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); + if (writer == NULL) { + return NULL; + } expr_ty last_elem = elem; for (j = i; j < n_flattened_elements; j++) { expr_ty current_elem = asdl_seq_GET(flattened, j); if (current_elem->kind == Constant_kind) { - if (_PyUnicodeWriter_WriteStr( - &writer, current_elem->v.Constant.value)) { - _PyUnicodeWriter_Dealloc(&writer); + if (PyUnicodeWriter_WriteStr(writer, + current_elem->v.Constant.value)) { + PyUnicodeWriter_Discard(writer); return NULL; } last_elem = current_elem; @@ -1652,9 +1654,8 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, } i = j - 1; - PyObject *concat_str = _PyUnicodeWriter_Finish(&writer); + PyObject *concat_str = PyUnicodeWriter_Finish(writer); if (concat_str == NULL) { - _PyUnicodeWriter_Dealloc(&writer); return NULL; } if (_PyArena_AddPyObject(p->arena, concat_str) < 0) { From eb2d268ac7480b5e2b4ffb9a644cad7ac75ae954 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 12 Oct 2024 13:10:50 +0300 Subject: [PATCH 129/247] gh-65865: Raise early errors for invalid help strings in argparse (GH-124899) --- Lib/argparse.py | 31 ++++++++++++++----- Lib/test/test_argparse.py | 31 +++++++++++++++++++ ...4-10-02-16-35-07.gh-issue-65865.S2D4wq.rst | 3 ++ 3 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index 2d8a7ef343a4ef..208c1827f9aca7 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -588,17 +588,20 @@ def _format_args(self, action, default_metavar): return result def _expand_help(self, action): + help_string = self._get_help_string(action) + if '%' not in help_string: + return help_string params = dict(vars(action), prog=self._prog) for name in list(params): - if params[name] is SUPPRESS: + value = params[name] + if value is SUPPRESS: del params[name] - for name in list(params): - if hasattr(params[name], '__name__'): - params[name] = params[name].__name__ + elif hasattr(value, '__name__'): + params[name] = value.__name__ if params.get('choices') is not None: choices_str = ', '.join([str(c) for c in params['choices']]) params['choices'] = choices_str - return self._get_help_string(action) % params + return help_string % params def _iter_indented_subactions(self, action): try: @@ -1180,9 +1183,13 @@ def add_parser(self, name, *, deprecated=False, **kwargs): help = kwargs.pop('help') choice_action = self._ChoicesPseudoAction(name, aliases, help) self._choices_actions.append(choice_action) + else: + choice_action = None # create the parser and add it to the map parser = self._parser_class(**kwargs) + if choice_action is not None: + parser._check_help(choice_action) self._name_parser_map[name] = parser # make parser available under aliases also @@ -1449,11 +1456,12 @@ def add_argument(self, *args, **kwargs): # raise an error if the metavar does not match the type if hasattr(self, "_get_formatter"): + formatter = self._get_formatter() try: - self._get_formatter()._format_args(action, None) + formatter._format_args(action, None) except TypeError: raise ValueError("length of metavar tuple does not match nargs") - + self._check_help(action) return self._add_action(action) def add_argument_group(self, *args, **kwargs): @@ -1635,6 +1643,14 @@ def _handle_conflict_resolve(self, action, conflicting_actions): if not action.option_strings: action.container._remove_action(action) + def _check_help(self, action): + if action.help and hasattr(self, "_get_formatter"): + formatter = self._get_formatter() + try: + formatter._expand_help(action) + except (ValueError, TypeError, KeyError) as exc: + raise ValueError('badly formed help string') from exc + class _ArgumentGroup(_ActionsContainer): @@ -1852,6 +1868,7 @@ def add_subparsers(self, **kwargs): # create the parsers action and add it to the positionals list parsers_class = self._pop_action_class(kwargs, 'parsers') action = parsers_class(option_strings=[], **kwargs) + self._check_help(action) self._subparsers._add_action(action) # return the created parsers action diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 1ebbc21bc1755b..000b810454f584 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2623,6 +2623,29 @@ def test_parser_command_help(self): --foo foo help ''')) + def assert_bad_help(self, context_type, func, *args, **kwargs): + with self.assertRaisesRegex(ValueError, 'badly formed help string') as cm: + func(*args, **kwargs) + self.assertIsInstance(cm.exception.__context__, context_type) + + def test_invalid_subparsers_help(self): + parser = ErrorRaisingArgumentParser(prog='PROG') + self.assert_bad_help(ValueError, parser.add_subparsers, help='%Y-%m-%d') + parser = ErrorRaisingArgumentParser(prog='PROG') + self.assert_bad_help(KeyError, parser.add_subparsers, help='%(spam)s') + parser = ErrorRaisingArgumentParser(prog='PROG') + self.assert_bad_help(TypeError, parser.add_subparsers, help='%(prog)d') + + def test_invalid_subparser_help(self): + parser = ErrorRaisingArgumentParser(prog='PROG') + subparsers = parser.add_subparsers() + self.assert_bad_help(ValueError, subparsers.add_parser, '1', + help='%Y-%m-%d') + self.assert_bad_help(KeyError, subparsers.add_parser, '1', + help='%(spam)s') + self.assert_bad_help(TypeError, subparsers.add_parser, '1', + help='%(prog)d') + def test_subparser_title_help(self): parser = ErrorRaisingArgumentParser(prog='PROG', description='main description') @@ -5375,6 +5398,14 @@ def test_invalid_action(self): self.assertValueError('--foo', action="store-true", errmsg='unknown action') + def test_invalid_help(self): + self.assertValueError('--foo', help='%Y-%m-%d', + errmsg='badly formed help string') + self.assertValueError('--foo', help='%(spam)s', + errmsg='badly formed help string') + self.assertValueError('--foo', help='%(prog)d', + errmsg='badly formed help string') + def test_multiple_dest(self): parser = argparse.ArgumentParser() parser.add_argument(dest='foo') diff --git a/Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst b/Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst new file mode 100644 index 00000000000000..106a8b81140520 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst @@ -0,0 +1,3 @@ +:mod:`argparse` now raises early error for invalid ``help`` arguments to +:meth:`~argparse.ArgumentParser.add_argument`, +:meth:`~argparse.ArgumentParser.add_subparsers` and :meth:`!add_parser`. From a6c0c64de0ade400df7995f1e9480b6fc0f863aa Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 12 Oct 2024 14:46:28 +0300 Subject: [PATCH 130/247] gh-59330: Improve error message for dest= for positionals (GH-125215) Also improve the documentation. Specify how dest and metavar are derived from add_argument() positional arguments. Co-authored-by: Simon Law --- Doc/library/argparse.rst | 19 +++++++++++++++++++ Lib/argparse.py | 3 ++- Lib/test/test_argparse.py | 3 ++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index d337de87ca8f39..19f832051a9ee8 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -636,6 +636,25 @@ be positional:: usage: PROG [-h] [-f FOO] bar PROG: error: the following arguments are required: bar +By default, argparse automatically handles the internal naming and +display names of arguments, simplifying the process without requiring +additional configuration. +As such, you do not need to specify the dest_ and metavar_ parameters. +The dest_ parameter defaults to the argument name with underscores ``_`` +replacing hyphens ``-`` . The metavar_ parameter defaults to the +upper-cased name. For example:: + + >>> parser = argparse.ArgumentParser(prog='PROG') + >>> parser.add_argument('--foo-bar') + >>> parser.parse_args(['--foo-bar', 'FOO-BAR'] + Namespace(foo_bar='FOO-BAR') + >>> parser.print_help() + usage: [-h] [--foo-bar FOO-BAR] + + optional arguments: + -h, --help show this help message and exit + --foo-bar FOO-BAR + .. _action: diff --git a/Lib/argparse.py b/Lib/argparse.py index 208c1827f9aca7..64dbd7149e769c 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1424,7 +1424,8 @@ def add_argument(self, *args, **kwargs): chars = self.prefix_chars if not args or len(args) == 1 and args[0][0] not in chars: if args and 'dest' in kwargs: - raise ValueError('dest supplied twice for positional argument') + raise ValueError('dest supplied twice for positional argument,' + ' did you mean metavar?') kwargs = self._get_positional_kwargs(*args, **kwargs) # otherwise, we're adding an optional argument diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 000b810454f584..61ddb5f16cc44f 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5411,7 +5411,8 @@ def test_multiple_dest(self): parser.add_argument(dest='foo') with self.assertRaises(ValueError) as cm: parser.add_argument('bar', dest='baz') - self.assertIn('dest supplied twice for positional argument', + self.assertIn('dest supplied twice for positional argument,' + ' did you mean metavar?', str(cm.exception)) def test_no_argument_actions(self): From 07c2d15977738165e9dc4248e7edda7c75ecc14b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 12 Oct 2024 14:53:00 +0300 Subject: [PATCH 131/247] gh-85935: Explicitly document the case nargs=0 in argparse (GH-125302) --- Doc/library/argparse.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 19f832051a9ee8..d58c75eef3e739 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -751,6 +751,9 @@ how the command-line arguments should be handled. The supplied actions are: .. versionadded:: 3.8 +Only actions that consume command-line arguments (e.g. ``'store'``, +``'append'`` or ``'extend'``) can be used with positional arguments. + You may also specify an arbitrary action by passing an Action subclass or other object that implements the same interface. The ``BooleanOptionalAction`` is available in ``argparse`` and adds support for boolean actions such as @@ -878,6 +881,8 @@ See also :ref:`specifying-ambiguous-arguments`. The supported values are: If the ``nargs`` keyword argument is not provided, the number of arguments consumed is determined by the action_. Generally this means a single command-line argument will be consumed and a single item (not a list) will be produced. +Actions that do not consume command-line arguments (e.g. +``'store_const'``) set ``nargs=0``. .. _const: From 63cf4e914f879ee28a75c02e867baa7c6047ea2b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 12 Oct 2024 15:15:37 +0300 Subject: [PATCH 132/247] gh-125254: Fix error report about ambiguous option in argparse (GH-125273) This was a regression introduced in gh-58573. It was only tested for the case when the ambiguous option is the last argument in the command line. --- Lib/argparse.py | 2 +- Lib/test/test_argparse.py | 14 ++++++++++++-- .../2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index 64dbd7149e769c..cbecb3b753c2b9 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2019,7 +2019,7 @@ def consume_optional(start_index): if len(option_tuples) > 1: options = ', '.join([option_string for action, option_string, sep, explicit_arg in option_tuples]) - args = {'option': arg_string, 'matches': options} + args = {'option': arg_strings[start_index], 'matches': options} msg = _('ambiguous option: %(option)s could match %(matches)s') raise ArgumentError(None, msg % args) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 61ddb5f16cc44f..1fc97de78f7f89 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -6730,9 +6730,19 @@ def test_conflicting_mutually_exclusive_args_zero_or_more_with_metavar2(self): def test_ambiguous_option(self): self.parser.add_argument('--foobaz') self.parser.add_argument('--fooble', action='store_true') + self.parser.add_argument('--foogle') self.assertRaisesRegex(argparse.ArgumentError, - "ambiguous option: --foob could match --foobaz, --fooble", - self.parser.parse_args, ['--foob']) + "ambiguous option: --foob could match --foobaz, --fooble", + self.parser.parse_args, ['--foob']) + self.assertRaisesRegex(argparse.ArgumentError, + "ambiguous option: --foob=1 could match --foobaz, --fooble$", + self.parser.parse_args, ['--foob=1']) + self.assertRaisesRegex(argparse.ArgumentError, + "ambiguous option: --foob could match --foobaz, --fooble$", + self.parser.parse_args, ['--foob', '1', '--foogle', '2']) + self.assertRaisesRegex(argparse.ArgumentError, + "ambiguous option: --foob=1 could match --foobaz, --fooble$", + self.parser.parse_args, ['--foob=1', '--foogle', '2']) def test_os_error(self): self.parser.add_argument('file') diff --git a/Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst b/Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst new file mode 100644 index 00000000000000..abe37fefedc3be --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst @@ -0,0 +1 @@ +Fix a bug where ArgumentError includes the incorrect ambiguous option in :mod:`argparse`. From 9944ad388c457325456152257b977410c4ec3593 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 12 Oct 2024 16:04:17 +0300 Subject: [PATCH 133/247] gh-85935: Check for nargs=0 for positional arguments in argparse (GH-124839) Raise ValueError in add_argument() if either explicit nargs=0 or action that does not consume arguments (like 'store_const' or 'store_true') is specified for positional argument. --- Lib/argparse.py | 10 +++++++++- Lib/test/test_argparse.py | 7 +++++-- .../2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst | 4 ++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index cbecb3b753c2b9..550415dc93478b 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1441,11 +1441,17 @@ def add_argument(self, *args, **kwargs): kwargs['default'] = self.argument_default # create the action object, and add it to the parser + action_name = kwargs.get('action') action_class = self._pop_action_class(kwargs) if not callable(action_class): raise ValueError('unknown action "%s"' % (action_class,)) action = action_class(**kwargs) + # raise an error if action for positional argument does not + # consume arguments + if not action.option_strings and action.nargs == 0: + raise ValueError(f'action {action_name!r} is not valid for positional arguments') + # raise an error if the action type is not callable type_func = self._registry_get('type', action.type, action.type) if not callable(type_func): @@ -1554,7 +1560,9 @@ def _get_positional_kwargs(self, dest, **kwargs): # mark positional arguments as required if at least one is # always required nargs = kwargs.get('nargs') - if nargs not in [OPTIONAL, ZERO_OR_MORE, REMAINDER, SUPPRESS, 0]: + if nargs == 0: + raise ValueError('nargs for positionals must be != 0') + if nargs not in [OPTIONAL, ZERO_OR_MORE, REMAINDER, SUPPRESS]: kwargs['required'] = True # return the keyword arguments with no option strings diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 1fc97de78f7f89..f52a4b6bdd8aca 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5424,8 +5424,11 @@ def test_no_argument_actions(self): with self.subTest(attrs=attrs): self.assertTypeError('-x', action=action, **attrs) self.assertTypeError('x', action=action, **attrs) + self.assertValueError('x', action=action, + errmsg=f"action '{action}' is not valid for positional arguments") self.assertTypeError('-x', action=action, nargs=0) - self.assertTypeError('x', action=action, nargs=0) + self.assertValueError('x', action=action, nargs=0, + errmsg='nargs for positionals must be != 0') def test_no_argument_no_const_actions(self): # options with zero arguments @@ -5445,7 +5448,7 @@ def test_more_than_one_argument_actions(self): self.assertValueError('-x', nargs=0, action=action, errmsg=f'nargs for {action_name} actions must be != 0') self.assertValueError('spam', nargs=0, action=action, - errmsg=f'nargs for {action_name} actions must be != 0') + errmsg='nargs for positionals must be != 0') # const is disallowed with non-optional arguments for nargs in [1, '*', '+']: diff --git a/Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst b/Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst new file mode 100644 index 00000000000000..553f206bf26337 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst @@ -0,0 +1,4 @@ +:meth:`argparse.ArgumentParser.add_argument` now raises an exception if +an :ref:`action` that does not consume arguments (like 'store_const' or +'store_true') or explicit ``nargs=0`` are specified for positional +arguments. From dcd58c50844dae0d83517e88518a677914ea594b Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Sat, 12 Oct 2024 19:18:48 +0200 Subject: [PATCH 134/247] gh-125260: Change the default ``gzip.compress()`` mtime to 0 (#125261) This follows GNU gzip, which defaults to using 0 as the mtime for compressing stdin, where no file mtime is involved. This makes the output of gzip.compress() deterministic by default, greatly helping reproducible builds. Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/gzip.rst | 9 +++++++-- Lib/gzip.py | 6 +++--- Lib/test/test_gzip.py | 11 +++++++++++ .../2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst | 2 ++ 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 6b6e158f6eba2c..f24e73517e5767 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -184,11 +184,12 @@ The module defines the following items: attribute instead. -.. function:: compress(data, compresslevel=9, *, mtime=None) +.. function:: compress(data, compresslevel=9, *, mtime=0) Compress the *data*, returning a :class:`bytes` object containing the compressed data. *compresslevel* and *mtime* have the same meaning as in - the :class:`GzipFile` constructor above. + the :class:`GzipFile` constructor above, + but *mtime* defaults to 0 for reproducible output. .. versionadded:: 3.2 .. versionchanged:: 3.8 @@ -203,6 +204,10 @@ The module defines the following items: .. versionchanged:: 3.13 The gzip header OS byte is guaranteed to be set to 255 when this function is used as was the case in 3.10 and earlier. + .. versionchanged:: 3.14 + The *mtime* parameter now defaults to 0 for reproducible output. + For the previous behaviour of using the current time, + pass ``None`` to *mtime*. .. function:: decompress(data) diff --git a/Lib/gzip.py b/Lib/gzip.py index ba753ce3050dd8..1a3c82ce7e0711 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -580,12 +580,12 @@ def _rewind(self): self._new_member = True -def compress(data, compresslevel=_COMPRESS_LEVEL_BEST, *, mtime=None): +def compress(data, compresslevel=_COMPRESS_LEVEL_BEST, *, mtime=0): """Compress data in one shot and return the compressed string. compresslevel sets the compression level in range of 0-9. - mtime can be used to set the modification time. The modification time is - set to the current time by default. + mtime can be used to set the modification time. + The modification time is set to 0 by default, for reproducibility. """ # Wbits=31 automatically includes a gzip header and trailer. gzip_data = zlib.compress(data, level=compresslevel, wbits=31) diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index ae384c3849d49e..bf6e1703db8451 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -713,6 +713,17 @@ def test_compress_mtime(self): f.read(1) # to set mtime attribute self.assertEqual(f.mtime, mtime) + def test_compress_mtime_default(self): + # test for gh-125260 + datac = gzip.compress(data1, mtime=0) + datac2 = gzip.compress(data1) + self.assertEqual(datac, datac2) + datac3 = gzip.compress(data1, mtime=None) + self.assertNotEqual(datac, datac3) + with gzip.GzipFile(fileobj=io.BytesIO(datac3), mode="rb") as f: + f.read(1) # to set mtime attribute + self.assertGreater(f.mtime, 1) + def test_compress_correct_level(self): for mtime in (0, 42): with self.subTest(mtime=mtime): diff --git a/Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst b/Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst new file mode 100644 index 00000000000000..fab524ea0185c2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst @@ -0,0 +1,2 @@ +The :func:`gzip.compress` *mtime* parameter now defaults to 0 for reproducible output. +Patch by Bernhard M. Wiedemann and Adam Turner. From c05f9dde8a12dfd63d3ade93da616042df2dc925 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 12 Oct 2024 20:46:21 +0300 Subject: [PATCH 135/247] gh-53203: Fix strptime() for %c and %x formats on many locales (GH-124946) In some locales (like French or Hebrew) the full or abbreviated names of the default month and weekday used in __calc_date_time can be part of other name or constant part of the %c format. The month name can also match %m with constant suffix (like in Japanese). So the code failed to correctly distinguish formats %a, %A, %b, %B and %m. Cycle all month and all days of the week to find the variable part and distinguish %a from %A and %b from %B or %m. Fixed locales for the following languges: Arabic, Bislama, Breton, Bodo, Kashubian, Chuvash, Estonian, French, Irish, Ge'ez, Gurajati, Manx Gaelic, Hebrew, Hindi, Chhattisgarhi, Haitian Kreyol, Japanese, Kannada, Korean, Marathi, Malay, Norwegian, Nynorsk, Punjabi, Rajasthani, Tok Pisin, Yoruba, Yue Chinese, Yau/Nungon and Chinese. Co-authored-by: Eli Bendersky --- Lib/_strptime.py | 127 +++++++++++++++--- Lib/test/test_strptime.py | 36 +++-- ...4-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst | 5 + 3 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst diff --git a/Lib/_strptime.py b/Lib/_strptime.py index a3f8bb544d518d..89adc174e5ad30 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -28,6 +28,18 @@ def _getlang(): # Figure out what the current language is set to. return locale.getlocale(locale.LC_TIME) +def _findall(haystack, needle): + # Find all positions of needle in haystack. + if not needle: + return + i = 0 + while True: + i = haystack.find(needle, i) + if i < 0: + break + yield i + i += len(needle) + class LocaleTime(object): """Stores and handles locale-specific information related to time. @@ -102,7 +114,8 @@ def __calc_am_pm(self): am_pm = [] for hour in (1, 22): time_tuple = time.struct_time((1999,3,17,hour,44,55,2,76,0)) - am_pm.append(time.strftime("%p", time_tuple).lower()) + # br_FR has AM/PM info (' ',' '). + am_pm.append(time.strftime("%p", time_tuple).lower().strip()) self.am_pm = am_pm def __calc_date_time(self): @@ -114,42 +127,114 @@ def __calc_date_time(self): # values within the format string is very important; it eliminates # possible ambiguity for what something represents. time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0)) - date_time = [None, None, None] - date_time[0] = time.strftime("%c", time_tuple).lower() - date_time[1] = time.strftime("%x", time_tuple).lower() - date_time[2] = time.strftime("%X", time_tuple).lower() - replacement_pairs = [('%', '%%'), (self.f_weekday[2], '%A'), - (self.f_month[3], '%B'), (self.a_weekday[2], '%a'), - (self.a_month[3], '%b'), (self.am_pm[1], '%p'), + time_tuple2 = time.struct_time((1999,1,3,1,1,1,6,3,0)) + replacement_pairs = [ ('1999', '%Y'), ('99', '%y'), ('22', '%H'), ('44', '%M'), ('55', '%S'), ('76', '%j'), ('17', '%d'), ('03', '%m'), ('3', '%m'), # '3' needed for when no leading zero. ('2', '%w'), ('10', '%I')] - replacement_pairs.extend([(tz, "%Z") for tz_values in self.timezone - for tz in tz_values]) - for offset,directive in ((0,'%c'), (1,'%x'), (2,'%X')): - current_format = date_time[offset] - for old, new in replacement_pairs: + date_time = [] + for directive in ('%c', '%x', '%X'): + current_format = time.strftime(directive, time_tuple).lower() + current_format = current_format.replace('%', '%%') + # The month and the day of the week formats are treated specially + # because of a possible ambiguity in some locales where the full + # and abbreviated names are equal or names of different types + # are equal. See doc of __find_month_format for more details. + lst, fmt = self.__find_weekday_format(directive) + if lst: + current_format = current_format.replace(lst[2], fmt, 1) + lst, fmt = self.__find_month_format(directive) + if lst: + current_format = current_format.replace(lst[3], fmt, 1) + if self.am_pm[1]: # Must deal with possible lack of locale info # manifesting itself as the empty string (e.g., Swedish's # lack of AM/PM info) or a platform returning a tuple of empty # strings (e.g., MacOS 9 having timezone as ('','')). - if old: - current_format = current_format.replace(old, new) + current_format = current_format.replace(self.am_pm[1], '%p') + for tz_values in self.timezone: + for tz in tz_values: + if tz: + current_format = current_format.replace(tz, "%Z") + for old, new in replacement_pairs: + current_format = current_format.replace(old, new) # If %W is used, then Sunday, 2005-01-03 will fall on week 0 since # 2005-01-03 occurs before the first Monday of the year. Otherwise # %U is used. - time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0)) - if '00' in time.strftime(directive, time_tuple): + if '00' in time.strftime(directive, time_tuple2): U_W = '%W' else: U_W = '%U' - date_time[offset] = current_format.replace('11', U_W) + current_format = current_format.replace('11', U_W) + date_time.append(current_format) self.LC_date_time = date_time[0] self.LC_date = date_time[1] self.LC_time = date_time[2] + def __find_month_format(self, directive): + """Find the month format appropriate for the current locale. + + In some locales (for example French and Hebrew), the default month + used in __calc_date_time has the same name in full and abbreviated + form. Also, the month name can by accident match other part of the + representation: the day of the week name (for example in Morisyen) + or the month number (for example in Japanese). Thus, cycle months + of the year and find all positions that match the month name for + each month, If no common positions are found, the representation + does not use the month name. + """ + full_indices = abbr_indices = None + for m in range(1, 13): + time_tuple = time.struct_time((1999, m, 17, 22, 44, 55, 2, 76, 0)) + datetime = time.strftime(directive, time_tuple).lower() + indices = set(_findall(datetime, self.f_month[m])) + if full_indices is None: + full_indices = indices + else: + full_indices &= indices + indices = set(_findall(datetime, self.a_month[m])) + if abbr_indices is None: + abbr_indices = indices + else: + abbr_indices &= indices + if not full_indices and not abbr_indices: + return None, None + if full_indices: + return self.f_month, '%B' + if abbr_indices: + return self.a_month, '%b' + return None, None + + def __find_weekday_format(self, directive): + """Find the day of the week format appropriate for the current locale. + + Similar to __find_month_format(). + """ + full_indices = abbr_indices = None + for wd in range(7): + time_tuple = time.struct_time((1999, 3, 17, 22, 44, 55, wd, 76, 0)) + datetime = time.strftime(directive, time_tuple).lower() + indices = set(_findall(datetime, self.f_weekday[wd])) + if full_indices is None: + full_indices = indices + else: + full_indices &= indices + if self.f_weekday[wd] != self.a_weekday[wd]: + indices = set(_findall(datetime, self.a_weekday[wd])) + if abbr_indices is None: + abbr_indices = indices + else: + abbr_indices &= indices + if not full_indices and not abbr_indices: + return None, None + if full_indices: + return self.f_weekday, '%A' + if abbr_indices: + return self.a_weekday, '%a' + return None, None + def __calc_timezone(self): # Set self.timezone by using time.tzname. # Do not worry about possibility of time.tzname[0] == time.tzname[1] @@ -187,7 +272,7 @@ def __init__(self, locale_time=None): 'd': r"(?P3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", 'f': r"(?P[0-9]{1,6})", 'H': r"(?P2[0-3]|[0-1]\d|\d)", - 'I': r"(?P1[0-2]|0[1-9]|[1-9])", + 'I': r"(?P1[0-2]|0[1-9]|[1-9]| [1-9])", 'G': r"(?P\d\d\d\d)", 'j': r"(?P36[0-6]|3[0-5]\d|[1-2]\d\d|0[1-9]\d|00[1-9]|[1-9]\d|0[1-9]|[1-9])", 'm': r"(?P1[0-2]|0[1-9]|[1-9])", @@ -349,8 +434,8 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): _regex_cache[format] = format_regex found = format_regex.match(data_string) if not found: - raise ValueError("time data %r does not match format %r" % - (data_string, format)) + raise ValueError("time data %r does not match format %r :: /%s/" % + (data_string, format, format_regex.pattern)) if len(data_string) != found.end(): raise ValueError("unconverted data remains: %s" % data_string[found.end():]) diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 37f6b08db28b3e..79f48dfe44abde 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -5,6 +5,7 @@ import locale import re import os +import platform import sys from test import support from test.support import warnings_helper @@ -13,6 +14,13 @@ import _strptime +libc_ver = platform.libc_ver() +if libc_ver[0] == 'glibc': + glibc_ver = tuple(map(int, libc_ver[1].split('.'))) +else: + glibc_ver = None + + class getlang_Tests(unittest.TestCase): """Test _getlang""" def test_basic(self): @@ -478,16 +486,16 @@ def test_bad_timezone(self): # * Year is not included: ha_NG. # * Use non-Gregorian calendar: lo_LA, thai, th_TH. # - # BUG: Generates invalid regexp for br_FR, csb_PL, Arabic. - # BUG: Generates regexp that does not match the current date and time - # for fa_IR, gez_ER, gez_ET, lzh_TW, my_MM, or_IN, shn_MM, yo_NG. # BUG: Generates regexp that does not match the current date and time - # for fa_IR, gez_ER, gez_ET, lzh_TW, my_MM, or_IN, shn_MM, yo_NG, - # fr_FR, ja_JP, he_IL, ko_KR, zh_CN, etc. - @run_with_locales('LC_TIME', 'C', 'en_US', 'de_DE', - 'eu_ES', 'mfe_MU') + # for az_IR, fa_IR, lzh_TW, my_MM, or_IN, shn_MM. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'he_IL', 'eu_ES', 'ar_AE', 'mfe_MU', 'yo_NG', + 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN') def test_date_time_locale(self): # Test %c directive + loc = locale.getlocale(locale.LC_TIME)[0] + if glibc_ver and glibc_ver < (2, 31) and loc == 'br_FR': + self.skipTest('%c in locale br_FR does not include time') now = time.time() self.roundtrip('%c', slice(0, 6), time.localtime(now)) # 1 hour 20 minutes 30 seconds ago @@ -505,7 +513,9 @@ def test_date_time_locale(self): # NB: Dates before 1969 do not roundtrip on some locales: # bo_CN, bo_IN, dz_BT, eu_ES, eu_FR. - @run_with_locales('LC_TIME', 'C', 'en_US', 'de_DE', 'ja_JP') + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'he_IL', 'ar_AE', 'mfe_MU', 'yo_NG', + 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN') def test_date_time_locale2(self): # Test %c directive self.roundtrip('%c', slice(0, 6), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) @@ -513,10 +523,9 @@ def test_date_time_locale2(self): # NB: Does not roundtrip because use non-Gregorian calendar: # lo_LA, thai, th_TH. # BUG: Generates regexp that does not match the current date - # for az_IR, fa_IR, lzh_TW, my_MM, or_IN, shn_MM, - # Arabic, ja_JP, ko_KR, zh_CN, etc. - @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', - 'he_IL', 'eu_ES') + # for az_IR, fa_IR, lzh_TW, my_MM, or_IN, shn_MM. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'he_IL', 'eu_ES', 'ar_AE') def test_date_locale(self): # Test %x directive now = time.time() @@ -535,7 +544,8 @@ def test_date_locale(self): support.is_emscripten or support.is_wasi, "musl libc issue on Emscripten, bpo-46390" ) - @run_with_locales('LC_TIME', 'en_US', 'fr_FR', 'de_DE', 'ja_JP') + @run_with_locales('LC_TIME', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'eu_ES', 'ar_AE') def test_date_locale2(self): # Test %x directive self.roundtrip('%x', slice(0, 3), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) diff --git a/Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst b/Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst new file mode 100644 index 00000000000000..6895cffcf545fd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst @@ -0,0 +1,5 @@ +Fix :func:`time.strptime` for ``%c`` and ``%x`` formats in many locales: +Arabic, Bislama, Breton, Bodo, Kashubian, Chuvash, Estonian, French, Irish, +Ge'ez, Gurajati, Manx Gaelic, Hebrew, Hindi, Chhattisgarhi, Haitian Kreyol, +Japanese, Kannada, Korean, Marathi, Malay, Norwegian, Nynorsk, Punjabi, +Rajasthani, Tok Pisin, Yoruba, Yue Chinese, Yau/Nungon and Chinese. From 62d5a53a0b2a5262a86984cfe9817aeb653ebfca Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 12 Oct 2024 15:33:00 -0400 Subject: [PATCH 136/247] gh-124872: Move PyThreadState to first argument for consistency (#124774) --- Python/context.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Python/context.c b/Python/context.c index 36e2677c398f59..9b742136b0726d 100644 --- a/Python/context.c +++ b/Python/context.c @@ -112,7 +112,8 @@ context_event_name(PyContextEvent event) { Py_UNREACHABLE(); } -static void notify_context_watchers(PyContextEvent event, PyContext *ctx, PyThreadState *ts) +static void +notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyContext *ctx) { assert(Py_REFCNT(ctx) > 0); PyInterpreterState *interp = ts->interp; @@ -192,7 +193,7 @@ _PyContext_Enter(PyThreadState *ts, PyObject *octx) ts->context = Py_NewRef(ctx); ts->context_ver++; - notify_context_watchers(Py_CONTEXT_EVENT_ENTER, ctx, ts); + notify_context_watchers(ts, Py_CONTEXT_EVENT_ENTER, ctx); return 0; } @@ -226,7 +227,7 @@ _PyContext_Exit(PyThreadState *ts, PyObject *octx) return -1; } - notify_context_watchers(Py_CONTEXT_EVENT_EXIT, ctx, ts); + notify_context_watchers(ts, Py_CONTEXT_EVENT_EXIT, ctx); Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev); ts->context_ver++; From 4a2282b0679bbf7b7fbd36aae1b1565145238961 Mon Sep 17 00:00:00 2001 From: Stephen Rosen Date: Sat, 12 Oct 2024 15:21:55 -0500 Subject: [PATCH 137/247] Prefer "similar" over "equivalent" in tutorial (#125343) In the datastructures tutorial doc, some operations are described as "equivalent to" others. This has led to some user-confusion -- at least in the Discourse forums -- about cases in which the operations differ. This change doesn't systematically eliminate the word "equivalent" from the tutorial. It just substitutes "similar to" in several cases in which "equivalent to" could mislead users into expecting exact equivalence. --- Doc/tutorial/datastructures.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index 73f17adeea72de..31941bc112a135 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -19,13 +19,13 @@ objects: .. method:: list.append(x) :noindex: - Add an item to the end of the list. Equivalent to ``a[len(a):] = [x]``. + Add an item to the end of the list. Similar to ``a[len(a):] = [x]``. .. method:: list.extend(iterable) :noindex: - Extend the list by appending all the items from the iterable. Equivalent to + Extend the list by appending all the items from the iterable. Similar to ``a[len(a):] = iterable``. @@ -56,7 +56,7 @@ objects: .. method:: list.clear() :noindex: - Remove all items from the list. Equivalent to ``del a[:]``. + Remove all items from the list. Similar to ``del a[:]``. .. method:: list.index(x[, start[, end]]) @@ -93,7 +93,7 @@ objects: .. method:: list.copy() :noindex: - Return a shallow copy of the list. Equivalent to ``a[:]``. + Return a shallow copy of the list. Similar to ``a[:]``. An example that uses most of the list methods:: From fa52b82c91a8e1a0971bd5fef656473ec93f41e3 Mon Sep 17 00:00:00 2001 From: "Ghorban M. Tavakoly" <58617996+galmyk@users.noreply.github.com> Date: Sun, 13 Oct 2024 00:08:13 +0330 Subject: [PATCH 138/247] gh-125289: Update sample code in asyncio-task.rst (GH-125292) * Update sample code in asyncio-task.rst This will change **coroutines** sample code in the **Awaitables** section and make the example clearer. * Update Doc/library/asyncio-task.rst Revert the added print Co-authored-by: Carol Willing * Update Doc/library/asyncio-task.rst Co-authored-by: Carol Willing --------- Co-authored-by: Carol Willing --- Doc/library/asyncio-task.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 4716a3f9c8ac79..f27e858cf420f4 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -158,7 +158,7 @@ other coroutines:: # Nothing happens if we just call "nested()". # A coroutine object is created but not awaited, # so it *won't run at all*. - nested() + nested() # will raise a "RuntimeWarning". # Let's do it differently now and await it: print(await nested()) # will print "42". From 330c527299a5380f39c658bfa9321706cabc445d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 12 Oct 2024 16:57:27 -0400 Subject: [PATCH 139/247] gh-124872: Change PyContext_WatchCallback to take PyObject (#124737) The PyContext struct is not intended to be public, and users of the API don't need anything more specific than PyObject. Also see gh-78943. --- Doc/c-api/contextvars.rst | 2 +- Include/cpython/context.h | 2 +- Modules/_testcapi/watchers.c | 10 +++++----- Python/context.c | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/c-api/contextvars.rst b/Doc/c-api/contextvars.rst index 59e74ba1ac7022..8eba54a80dc80d 100644 --- a/Doc/c-api/contextvars.rst +++ b/Doc/c-api/contextvars.rst @@ -136,7 +136,7 @@ Context object management functions: .. versionadded:: 3.14 -.. c:type:: int (*PyContext_WatchCallback)(PyContextEvent event, PyContext* ctx) +.. c:type:: int (*PyContext_WatchCallback)(PyContextEvent event, PyObject *obj) Context object watcher callback function. The object passed to the callback is event-specific; see :c:type:`PyContextEvent` for details. diff --git a/Include/cpython/context.h b/Include/cpython/context.h index d722b4d93134f7..3c9be7873b9399 100644 --- a/Include/cpython/context.h +++ b/Include/cpython/context.h @@ -52,7 +52,7 @@ typedef enum { * if the callback returns with an exception set, it must return -1. Otherwise * it should return 0 */ -typedef int (*PyContext_WatchCallback)(PyContextEvent, PyContext *); +typedef int (*PyContext_WatchCallback)(PyContextEvent, PyObject *); /* * Register a per-interpreter callback that will be invoked for context object diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index 689863d098ad8a..b4233d07134aea 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -630,7 +630,7 @@ static int num_context_object_enter_events[NUM_CONTEXT_WATCHERS] = {0, 0}; static int num_context_object_exit_events[NUM_CONTEXT_WATCHERS] = {0, 0}; static int -handle_context_watcher_event(int which_watcher, PyContextEvent event, PyContext *ctx) { +handle_context_watcher_event(int which_watcher, PyContextEvent event, PyObject *ctx) { if (event == Py_CONTEXT_EVENT_ENTER) { num_context_object_enter_events[which_watcher]++; } @@ -644,22 +644,22 @@ handle_context_watcher_event(int which_watcher, PyContextEvent event, PyContext } static int -first_context_watcher_callback(PyContextEvent event, PyContext *ctx) { +first_context_watcher_callback(PyContextEvent event, PyObject *ctx) { return handle_context_watcher_event(0, event, ctx); } static int -second_context_watcher_callback(PyContextEvent event, PyContext *ctx) { +second_context_watcher_callback(PyContextEvent event, PyObject *ctx) { return handle_context_watcher_event(1, event, ctx); } static int -noop_context_event_handler(PyContextEvent event, PyContext *ctx) { +noop_context_event_handler(PyContextEvent event, PyObject *ctx) { return 0; } static int -error_context_event_handler(PyContextEvent event, PyContext *ctx) { +error_context_event_handler(PyContextEvent event, PyObject *ctx) { PyErr_SetString(PyExc_RuntimeError, "boom!"); return -1; } diff --git a/Python/context.c b/Python/context.c index 9b742136b0726d..8bc487a33c890b 100644 --- a/Python/context.c +++ b/Python/context.c @@ -113,7 +113,7 @@ context_event_name(PyContextEvent event) { } static void -notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyContext *ctx) +notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyObject *ctx) { assert(Py_REFCNT(ctx) > 0); PyInterpreterState *interp = ts->interp; @@ -193,7 +193,7 @@ _PyContext_Enter(PyThreadState *ts, PyObject *octx) ts->context = Py_NewRef(ctx); ts->context_ver++; - notify_context_watchers(ts, Py_CONTEXT_EVENT_ENTER, ctx); + notify_context_watchers(ts, Py_CONTEXT_EVENT_ENTER, octx); return 0; } @@ -227,7 +227,7 @@ _PyContext_Exit(PyThreadState *ts, PyObject *octx) return -1; } - notify_context_watchers(ts, Py_CONTEXT_EVENT_EXIT, ctx); + notify_context_watchers(ts, Py_CONTEXT_EVENT_EXIT, octx); Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev); ts->context_ver++; From a8fa4ad9e9f7aa0cba8b23af2c583d17bb1d1847 Mon Sep 17 00:00:00 2001 From: Ruoyu Zhong Date: Sun, 13 Oct 2024 08:53:28 +0800 Subject: [PATCH 140/247] Doc: Fix suggested usage of `-X gil=0` in the glossary (#125366) Currently, the "global interpreter lock" entry in the glossary mentions that `-X gil 0` can be used to disable the GIL [1]. However, this is invalid; the correct usage should be `-X gil=0`. $ python -X gil 0 -c 'print("Hello, world")' Fatal Python error: config_read_gil: PYTHON_GIL / -X gil must be "0" or "1" Python runtime state: preinitialized $ python -X gil=0 -c 'print("Hello, world")' Hello, world [1]: https://docs.python.org/3/using/cmdline.html#cmdoption-X Signed-off-by: Ruoyu Zhong --- Doc/glossary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 1d407732eef576..f67f3ecad0bc40 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -617,7 +617,7 @@ Glossary As of Python 3.13, the GIL can be disabled using the :option:`--disable-gil` build configuration. After building Python with this option, code must be - run with :option:`-X gil 0 <-X>` or after setting the :envvar:`PYTHON_GIL=0 ` + run with :option:`-X gil=0 <-X>` or after setting the :envvar:`PYTHON_GIL=0 ` environment variable. This feature enables improved performance for multi-threaded applications and makes it easier to use multi-core CPUs efficiently. For more details, see :pep:`703`. From 82bcaf15890cf85b76b4f62d2dd1710bb49c3ed1 Mon Sep 17 00:00:00 2001 From: Andrew Athan <24279435+aathan@users.noreply.github.com> Date: Sun, 13 Oct 2024 00:22:05 -0700 Subject: [PATCH 141/247] Trivial change: Update comments in activate about what running hash -r does (GH-125385) Update comments about what running hash -r does The old comment said "hash -r" forgets "past commands." However, the documentation for "hash" states that it forgets past locations. The old comment was, in my opinion, confusing. This is because it could be interpreted to mean it does something to the command history (HISTORY/HISTFILE etc) vs the cache of locations. --- Lib/venv/scripts/common/activate | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate index cbd4873f012246..4593799b7e9b0e 100644 --- a/Lib/venv/scripts/common/activate +++ b/Lib/venv/scripts/common/activate @@ -14,8 +14,9 @@ deactivate () { unset _OLD_VIRTUAL_PYTHONHOME fi - # Call hash to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected + # Call hash to forget past locations. Without forgetting + # past locations the $PATH changes we made may not be respected. + # See "man bash" for more details. hash is usually a builtin of your shell hash -r 2> /dev/null if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then From 4197a796ecf3a751ad7245b8d4f980d6d444b614 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 13 Oct 2024 09:38:47 +0200 Subject: [PATCH 142/247] gh-86673: Loosen test_ttk.test_identify() requirements (#125335) In aeca373b3 (PR gh-12011, issue gh-71500), test_identify() was changed to expect different results on Darwin. Ned's fix was later adjusted by e52f9bee8. This workaround is only needed for some variants of Tk/Tcl on macOS, so we now allow both the workaround and the generic results for these tests. --- Lib/test/test_ttk/test_widgets.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 88740b18864006..10bec33be617a1 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -336,7 +336,8 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase): 'show', 'state', 'style', 'takefocus', 'textvariable', 'validate', 'validatecommand', 'width', 'xscrollcommand', ) - IDENTIFY_AS = 'Entry.field' if sys.platform == 'darwin' else 'textarea' + # bpo-27313: macOS Tk/Tcl may or may not report 'Entry.field'. + IDENTIFY_AS = {'Entry.field', 'textarea'} def setUp(self): super().setUp() @@ -373,8 +374,7 @@ def test_identify(self): self.entry.pack() self.entry.update() - # bpo-27313: macOS Cocoa widget differs from X, allow either - self.assertEqual(self.entry.identify(5, 5), self.IDENTIFY_AS) + self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS) self.assertEqual(self.entry.identify(-1, -1), "") self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) @@ -461,7 +461,7 @@ class ComboboxTest(EntryTest, unittest.TestCase): 'validate', 'validatecommand', 'values', 'width', 'xscrollcommand', ) - IDENTIFY_AS = 'Combobox.button' if sys.platform == 'darwin' else 'textarea' + IDENTIFY_AS = {'Combobox.button', 'textarea'} def setUp(self): super().setUp() @@ -1204,7 +1204,7 @@ class SpinboxTest(EntryTest, unittest.TestCase): 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand', 'values', 'width', 'wrap', 'xscrollcommand', ) - IDENTIFY_AS = 'Spinbox.field' if sys.platform == 'darwin' else 'textarea' + IDENTIFY_AS = {'Spinbox.field', 'textarea'} def setUp(self): super().setUp() From ce740d46246b28bb675ba9d62214b59be9b8411e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 13 Oct 2024 10:22:31 +0200 Subject: [PATCH 143/247] gh-61698: Use launchctl to detect macOS window manager in tests (#118390) --- Lib/test/support/__init__.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 72ce5dacd1be4c..d768bead7120c7 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -253,22 +253,16 @@ class USEROBJECTFLAGS(ctypes.Structure): # process not running under the same user id as the current console # user. To avoid that, raise an exception if the window manager # connection is not available. - from ctypes import cdll, c_int, pointer, Structure - from ctypes.util import find_library - - app_services = cdll.LoadLibrary(find_library("ApplicationServices")) - - if app_services.CGMainDisplayID() == 0: - reason = "gui tests cannot run without OS X window manager" + import subprocess + try: + rc = subprocess.run(["launchctl", "managername"], + capture_output=True, check=True) + managername = rc.stdout.decode("utf-8").strip() + except subprocess.CalledProcessError: + reason = "unable to detect macOS launchd job manager" else: - class ProcessSerialNumber(Structure): - _fields_ = [("highLongOfPSN", c_int), - ("lowLongOfPSN", c_int)] - psn = ProcessSerialNumber() - psn_p = pointer(psn) - if ( (app_services.GetCurrentProcess(psn_p) < 0) or - (app_services.SetFrontProcess(psn_p) < 0) ): - reason = "cannot run without OS X gui process" + if managername != "Aqua": + reason = f"{managername=} -- can only run in a macOS GUI session" # check on every platform whether tkinter can actually do anything if not reason: From 283ea5f3b2b6a18605b8598a979afe263b0f21ce Mon Sep 17 00:00:00 2001 From: Wulian Date: Sun, 13 Oct 2024 19:10:59 +0800 Subject: [PATCH 144/247] gh-125383: Update `fib` function comment for accuracy (#125386) `Doc/tutorial/controlflow.rst`: fix comment for `fib` function --- Doc/tutorial/controlflow.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 9b73ac475c78d5..b830ce94ba4f47 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -461,8 +461,8 @@ Defining Functions We can create a function that writes the Fibonacci series to an arbitrary boundary:: - >>> def fib(n): # write Fibonacci series up to n - ... """Print a Fibonacci series up to n.""" + >>> def fib(n): # write Fibonacci series less than n + ... """Print a Fibonacci series less than n.""" ... a, b = 0, 1 ... while a < n: ... print(a, end=' ') From 022c50d190e14affb952a244c4eb6e4a644ad0c9 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sun, 13 Oct 2024 20:59:07 +0530 Subject: [PATCH 145/247] fix comment in _PyMutex_TryUnlock (#125319) --- Include/internal/pycore_lock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_lock.h b/Include/internal/pycore_lock.h index e6da083b807ce5..cd7deda00c7bee 100644 --- a/Include/internal/pycore_lock.h +++ b/Include/internal/pycore_lock.h @@ -64,8 +64,8 @@ PyMutex_LockFlags(PyMutex *m, _PyLockFlags flags) } } -// Unlock a mutex, returns 0 if the mutex is not locked (used for improved -// error messages). +// Unlock a mutex, returns -1 if the mutex is not locked (used for improved +// error messages) otherwise returns 0. extern int _PyMutex_TryUnlock(PyMutex *m); From 08489325d1cd94eba97c5f5f8cac49521fd0b0d7 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sun, 13 Oct 2024 20:59:41 +0530 Subject: [PATCH 146/247] gh-125161: return non zero value in pthread_self on wasi (#125303) --- Python/thread_pthread_stubs.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Python/thread_pthread_stubs.h b/Python/thread_pthread_stubs.h index 4741e594e52e65..458f8fc5951720 100644 --- a/Python/thread_pthread_stubs.h +++ b/Python/thread_pthread_stubs.h @@ -1,5 +1,9 @@ #include "cpython/pthread_stubs.h" +typedef struct py_stub_tls_entry py_tls_entry; + +#define py_tls_entries (_PyRuntime.threads.stubs.tls_entries) + // mutex int pthread_mutex_init(pthread_mutex_t *restrict mutex, @@ -105,7 +109,7 @@ pthread_join(pthread_t thread, void** value_ptr) PyAPI_FUNC(pthread_t) pthread_self(void) { - return 0; + return (pthread_t)(uintptr_t)&py_tls_entries; } int @@ -134,10 +138,6 @@ pthread_attr_destroy(pthread_attr_t *attr) } -typedef struct py_stub_tls_entry py_tls_entry; - -#define py_tls_entries (_PyRuntime.threads.stubs.tls_entries) - int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) { From cd0f9d111a040ad863c680e9f464419640c8c3fd Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sun, 13 Oct 2024 21:05:05 +0530 Subject: [PATCH 147/247] gh-89967: make WeakKeyDictionary and WeakValueDictionary thread safe (#125325) Make `WeakKeyDictionary` and `WeakValueDictionary` thread safe by copying the underlying the dict before iterating over it. --- Lib/_weakrefset.py | 25 --- Lib/weakref.py | 198 +++++------------- ...4-10-11-16-19-46.gh-issue-89967.vhWUOR.rst | 1 + 3 files changed, 50 insertions(+), 174 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py index 2071755d71dfc8..d1c7fcaeec9821 100644 --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -8,31 +8,6 @@ __all__ = ['WeakSet'] -class _IterationGuard: - # This context manager registers itself in the current iterators of the - # weak container, such as to delay all removals until the context manager - # exits. - # This technique should be relatively thread-safe (since sets are). - - def __init__(self, weakcontainer): - # Don't create cycles - self.weakcontainer = ref(weakcontainer) - - def __enter__(self): - w = self.weakcontainer() - if w is not None: - w._iterating.add(self) - return self - - def __exit__(self, e, t, b): - w = self.weakcontainer() - if w is not None: - s = w._iterating - s.remove(self) - if not s: - w._commit_removals() - - class WeakSet: def __init__(self, data=None): self.data = set() diff --git a/Lib/weakref.py b/Lib/weakref.py index 25b70927e29c31..94e4278143c987 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -19,7 +19,7 @@ ReferenceType, _remove_dead_weakref) -from _weakrefset import WeakSet, _IterationGuard +from _weakrefset import WeakSet import _collections_abc # Import after _weakref to avoid circular import. import sys @@ -105,34 +105,14 @@ def __init__(self, other=(), /, **kw): def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref): self = selfref() if self is not None: - if self._iterating: - self._pending_removals.append(wr.key) - else: - # Atomic removal is necessary since this function - # can be called asynchronously by the GC - _atomic_removal(self.data, wr.key) + # Atomic removal is necessary since this function + # can be called asynchronously by the GC + _atomic_removal(self.data, wr.key) self._remove = remove - # A list of keys to be removed - self._pending_removals = [] - self._iterating = set() self.data = {} self.update(other, **kw) - def _commit_removals(self, _atomic_removal=_remove_dead_weakref): - pop = self._pending_removals.pop - d = self.data - # We shouldn't encounter any KeyError, because this method should - # always be called *before* mutating the dict. - while True: - try: - key = pop() - except IndexError: - return - _atomic_removal(d, key) - def __getitem__(self, key): - if self._pending_removals: - self._commit_removals() o = self.data[key]() if o is None: raise KeyError(key) @@ -140,18 +120,12 @@ def __getitem__(self, key): return o def __delitem__(self, key): - if self._pending_removals: - self._commit_removals() del self.data[key] def __len__(self): - if self._pending_removals: - self._commit_removals() return len(self.data) def __contains__(self, key): - if self._pending_removals: - self._commit_removals() try: o = self.data[key]() except KeyError: @@ -162,38 +136,28 @@ def __repr__(self): return "<%s at %#x>" % (self.__class__.__name__, id(self)) def __setitem__(self, key, value): - if self._pending_removals: - self._commit_removals() self.data[key] = KeyedRef(value, self._remove, key) def copy(self): - if self._pending_removals: - self._commit_removals() new = WeakValueDictionary() - with _IterationGuard(self): - for key, wr in self.data.items(): - o = wr() - if o is not None: - new[key] = o + for key, wr in self.data.copy().items(): + o = wr() + if o is not None: + new[key] = o return new __copy__ = copy def __deepcopy__(self, memo): from copy import deepcopy - if self._pending_removals: - self._commit_removals() new = self.__class__() - with _IterationGuard(self): - for key, wr in self.data.items(): - o = wr() - if o is not None: - new[deepcopy(key, memo)] = o + for key, wr in self.data.copy().items(): + o = wr() + if o is not None: + new[deepcopy(key, memo)] = o return new def get(self, key, default=None): - if self._pending_removals: - self._commit_removals() try: wr = self.data[key] except KeyError: @@ -207,21 +171,15 @@ def get(self, key, default=None): return o def items(self): - if self._pending_removals: - self._commit_removals() - with _IterationGuard(self): - for k, wr in self.data.items(): - v = wr() - if v is not None: - yield k, v + for k, wr in self.data.copy().items(): + v = wr() + if v is not None: + yield k, v def keys(self): - if self._pending_removals: - self._commit_removals() - with _IterationGuard(self): - for k, wr in self.data.items(): - if wr() is not None: - yield k + for k, wr in self.data.copy().items(): + if wr() is not None: + yield k __iter__ = keys @@ -235,23 +193,15 @@ def itervaluerefs(self): keep the values around longer than needed. """ - if self._pending_removals: - self._commit_removals() - with _IterationGuard(self): - yield from self.data.values() + yield from self.data.copy().values() def values(self): - if self._pending_removals: - self._commit_removals() - with _IterationGuard(self): - for wr in self.data.values(): - obj = wr() - if obj is not None: - yield obj + for wr in self.data.copy().values(): + obj = wr() + if obj is not None: + yield obj def popitem(self): - if self._pending_removals: - self._commit_removals() while True: key, wr = self.data.popitem() o = wr() @@ -259,8 +209,6 @@ def popitem(self): return key, o def pop(self, key, *args): - if self._pending_removals: - self._commit_removals() try: o = self.data.pop(key)() except KeyError: @@ -279,16 +227,12 @@ def setdefault(self, key, default=None): except KeyError: o = None if o is None: - if self._pending_removals: - self._commit_removals() self.data[key] = KeyedRef(default, self._remove, key) return default else: return o def update(self, other=None, /, **kwargs): - if self._pending_removals: - self._commit_removals() d = self.data if other is not None: if not hasattr(other, "items"): @@ -308,9 +252,7 @@ def valuerefs(self): keep the values around longer than needed. """ - if self._pending_removals: - self._commit_removals() - return list(self.data.values()) + return list(self.data.copy().values()) def __ior__(self, other): self.update(other) @@ -369,57 +311,22 @@ def __init__(self, dict=None): def remove(k, selfref=ref(self)): self = selfref() if self is not None: - if self._iterating: - self._pending_removals.append(k) - else: - try: - del self.data[k] - except KeyError: - pass + try: + del self.data[k] + except KeyError: + pass self._remove = remove - # A list of dead weakrefs (keys to be removed) - self._pending_removals = [] - self._iterating = set() - self._dirty_len = False if dict is not None: self.update(dict) - def _commit_removals(self): - # NOTE: We don't need to call this method before mutating the dict, - # because a dead weakref never compares equal to a live weakref, - # even if they happened to refer to equal objects. - # However, it means keys may already have been removed. - pop = self._pending_removals.pop - d = self.data - while True: - try: - key = pop() - except IndexError: - return - - try: - del d[key] - except KeyError: - pass - - def _scrub_removals(self): - d = self.data - self._pending_removals = [k for k in self._pending_removals if k in d] - self._dirty_len = False - def __delitem__(self, key): - self._dirty_len = True del self.data[ref(key)] def __getitem__(self, key): return self.data[ref(key)] def __len__(self): - if self._dirty_len and self._pending_removals: - # self._pending_removals may still contain keys which were - # explicitly removed, we have to scrub them (see issue #21173). - self._scrub_removals() - return len(self.data) - len(self._pending_removals) + return len(self.data) def __repr__(self): return "<%s at %#x>" % (self.__class__.__name__, id(self)) @@ -429,11 +336,10 @@ def __setitem__(self, key, value): def copy(self): new = WeakKeyDictionary() - with _IterationGuard(self): - for key, value in self.data.items(): - o = key() - if o is not None: - new[o] = value + for key, value in self.data.copy().items(): + o = key() + if o is not None: + new[o] = value return new __copy__ = copy @@ -441,11 +347,10 @@ def copy(self): def __deepcopy__(self, memo): from copy import deepcopy new = self.__class__() - with _IterationGuard(self): - for key, value in self.data.items(): - o = key() - if o is not None: - new[o] = deepcopy(value, memo) + for key, value in self.data.copy().items(): + o = key() + if o is not None: + new[o] = deepcopy(value, memo) return new def get(self, key, default=None): @@ -459,26 +364,23 @@ def __contains__(self, key): return wr in self.data def items(self): - with _IterationGuard(self): - for wr, value in self.data.items(): - key = wr() - if key is not None: - yield key, value + for wr, value in self.data.copy().items(): + key = wr() + if key is not None: + yield key, value def keys(self): - with _IterationGuard(self): - for wr in self.data: - obj = wr() - if obj is not None: - yield obj + for wr in self.data.copy(): + obj = wr() + if obj is not None: + yield obj __iter__ = keys def values(self): - with _IterationGuard(self): - for wr, value in self.data.items(): - if wr() is not None: - yield value + for wr, value in self.data.copy().items(): + if wr() is not None: + yield value def keyrefs(self): """Return a list of weak references to the keys. @@ -493,7 +395,6 @@ def keyrefs(self): return list(self.data) def popitem(self): - self._dirty_len = True while True: key, value = self.data.popitem() o = key() @@ -501,7 +402,6 @@ def popitem(self): return o, value def pop(self, key, *args): - self._dirty_len = True return self.data.pop(ref(key), *args) def setdefault(self, key, default=None): diff --git a/Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst b/Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst new file mode 100644 index 00000000000000..d0860457c8e813 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst @@ -0,0 +1 @@ +Make :class:`~weakref.WeakKeyDictionary` and :class:`~weakref.WeakValueDictionary` safe against concurrent mutations from other threads. Patch by Kumar Aditya. From 6c386b703d19aaec9a34fd1e843a4d0a144ad14b Mon Sep 17 00:00:00 2001 From: partev Date: Sun, 13 Oct 2024 12:46:15 -0400 Subject: [PATCH 148/247] gh-125403: fix console formatting in Chapter 12 of the tutorial (#125404) --- Doc/tutorial/venv.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index 91e4ce18acef1d..f362e1943b666f 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -76,7 +76,7 @@ virtual environment you're using, and modify the environment so that running ``python`` will get you that particular version and installation of Python. For example: -.. code-block:: bash +.. code-block:: console $ source ~/envs/tutorial-env/bin/activate (tutorial-env) $ python @@ -108,7 +108,7 @@ complete documentation for ``pip``.) You can install the latest version of a package by specifying a package's name: -.. code-block:: bash +.. code-block:: console (tutorial-env) $ python -m pip install novas Collecting novas @@ -120,7 +120,7 @@ You can install the latest version of a package by specifying a package's name: You can also install a specific version of a package by giving the package name followed by ``==`` and the version number: -.. code-block:: bash +.. code-block:: console (tutorial-env) $ python -m pip install requests==2.6.0 Collecting requests==2.6.0 @@ -133,7 +133,7 @@ version is already installed and do nothing. You can supply a different version number to get that version, or you can run ``python -m pip install --upgrade`` to upgrade the package to the latest version: -.. code-block:: bash +.. code-block:: console (tutorial-env) $ python -m pip install --upgrade requests Collecting requests @@ -148,7 +148,7 @@ remove the packages from the virtual environment. ``python -m pip show`` will display information about a particular package: -.. code-block:: bash +.. code-block:: console (tutorial-env) $ python -m pip show requests --- @@ -166,7 +166,7 @@ remove the packages from the virtual environment. ``python -m pip list`` will display all of the packages installed in the virtual environment: -.. code-block:: bash +.. code-block:: console (tutorial-env) $ python -m pip list novas (3.1.1.3) @@ -179,7 +179,7 @@ the virtual environment: but the output uses the format that ``python -m pip install`` expects. A common convention is to put this list in a ``requirements.txt`` file: -.. code-block:: bash +.. code-block:: console (tutorial-env) $ python -m pip freeze > requirements.txt (tutorial-env) $ cat requirements.txt @@ -191,7 +191,7 @@ The ``requirements.txt`` can then be committed to version control and shipped as part of an application. Users can then install all the necessary packages with ``install -r``: -.. code-block:: bash +.. code-block:: console (tutorial-env) $ python -m pip install -r requirements.txt Collecting novas==3.1.1.3 (from -r requirements.txt (line 1)) From e79bbd147fd58e825572f1aa93c5398953289fb2 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sun, 13 Oct 2024 22:29:27 +0530 Subject: [PATCH 149/247] add Kumar Aditya as codeowner for weakref (#125405) --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7e9c3caf23f079..221008717b29b1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -280,3 +280,5 @@ Lib/test/test_configparser.py @jaraco # Doc sections Doc/reference/ @willingc + +**/*weakref* @kumaraditya303 \ No newline at end of file From c6d7b644c2425b397cfb641f336bea70eb8a329a Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 13 Oct 2024 20:38:42 +0300 Subject: [PATCH 150/247] gh-101291: Add versionadded directives for PyUnstable_Long_* (#125384) --- Doc/c-api/long.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index e0ae0f77a01db9..02ef8aa7846468 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -608,6 +608,9 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Exactly what values are considered compact is an implementation detail and is subject to change. + .. versionadded:: 3.12 + + .. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op) If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`, @@ -615,3 +618,5 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Otherwise, the return value is undefined. + .. versionadded:: 3.12 + From cb8e5995d89d9b90e83cf43310ec50e177484e70 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sun, 13 Oct 2024 18:46:10 +0100 Subject: [PATCH 151/247] GH-125069: Fix inconsistent joining in `WindowsPath(PosixPath(...))` (#125156) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PurePath.__init__()` incorrectly uses the `_raw_paths` of a given `PurePath` object with a different flavour, even though the procedure to join path segments can differ between flavours. This change makes the `_raw_paths`-enabled deferred joining apply _only_ when the path flavours match. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/pathlib/_local.py | 4 ++-- Lib/test/test_pathlib/test_pathlib.py | 9 +++++++++ .../2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py index 1c02e4168d3a9e..a78997179820b1 100644 --- a/Lib/pathlib/_local.py +++ b/Lib/pathlib/_local.py @@ -119,9 +119,9 @@ def __init__(self, *args): paths = [] for arg in args: if isinstance(arg, PurePath): - if arg.parser is ntpath and self.parser is posixpath: + if arg.parser is not self.parser: # GH-103631: Convert separators for backwards compatibility. - paths.extend(path.replace('\\', '/') for path in arg._raw_paths) + paths.append(arg.as_posix()) else: paths.extend(arg._raw_paths) else: diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index b47b4a194cfaa9..c7104bfda90f6c 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -131,6 +131,15 @@ def test_constructor_nested(self): self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c"))) self.assertEqual(P(P('./a:b')), P('./a:b')) + @needs_windows + def test_constructor_nested_foreign_flavour(self): + # See GH-125069. + p1 = pathlib.PurePosixPath('b/c:\\d') + p2 = pathlib.PurePosixPath('b/', 'c:\\d') + self.assertEqual(p1, p2) + self.assertEqual(self.cls(p1), self.cls('b/c:/d')) + self.assertEqual(self.cls(p2), self.cls('b/c:/d')) + def _check_parse_path(self, raw_path, *expected): sep = self.parser.sep actual = self.cls._parse_path(raw_path.replace('/', sep)) diff --git a/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst new file mode 100644 index 00000000000000..9f1fd871e1d0b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst @@ -0,0 +1,4 @@ +Fix an issue where providing a :class:`pathlib.PurePath` object as an +initializer argument to a second :class:`~pathlib.PurePath` object with a +different :attr:`~pathlib.PurePath.parser` resulted in arguments to the +former object's initializer being joined by the latter object's parser. From f1d33dbddd3496b062e1fbe024fb6d7b023a35f5 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Sun, 13 Oct 2024 16:17:51 -0400 Subject: [PATCH 152/247] gh-125243: Fix ZoneInfo data race in free threading build (#125281) Lock `ZoneInfoType` to protect accesses to `ZONEINFO_STRONG_CACHE`. Refactor the `tp_new` handler to use Argument Clinic so that we can just use `@critical_section` annotations on the relevant functions. Also use `PyDict_SetDefaultRef` instead of `PyDict_SetDefault` when inserting into the `TIMEDELTA_CACHE`. --- ...-10-10-20-39-57.gh-issue-125243.eUbbtu.rst | 2 + Modules/_zoneinfo.c | 44 +++++++------ Modules/clinic/_zoneinfo.c.h | 61 ++++++++++++++++++- 3 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst diff --git a/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst b/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst new file mode 100644 index 00000000000000..49f84d9711819f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst @@ -0,0 +1,2 @@ +Fix data race when creating :class:`zoneinfo.ZoneInfo` objects in the free +threading build. diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 902ece795b575b..c5292575c22f23 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -3,6 +3,7 @@ #endif #include "Python.h" +#include "pycore_critical_section.h" // _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED() #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() @@ -298,15 +299,20 @@ get_weak_cache(zoneinfo_state *state, PyTypeObject *type) } } +/*[clinic input] +@critical_section +@classmethod +zoneinfo.ZoneInfo.__new__ + + key: object + +Create a new ZoneInfo instance. +[clinic start generated code]*/ + static PyObject * -zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw) +zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key) +/*[clinic end generated code: output=95e61dab86bb95c3 input=ef73d7a83bf8790e]*/ { - PyObject *key = NULL; - static char *kwlist[] = {"key", NULL}; - if (PyArg_ParseTupleAndKeywords(args, kw, "O", kwlist, &key) == 0) { - return NULL; - } - zoneinfo_state *state = zoneinfo_get_state_by_self(type); PyObject *instance = zone_from_strong_cache(state, type, key); if (instance != NULL || PyErr_Occurred()) { @@ -467,6 +473,7 @@ zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyTypeObject *cls, } /*[clinic input] +@critical_section @classmethod zoneinfo.ZoneInfo.clear_cache @@ -481,7 +488,7 @@ Clear the ZoneInfo cache. static PyObject * zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls, PyObject *only_keys) -/*[clinic end generated code: output=114d9b7c8a22e660 input=e32ca3bb396788ba]*/ +/*[clinic end generated code: output=114d9b7c8a22e660 input=35944715df26d24e]*/ { zoneinfo_state *state = zoneinfo_get_state_by_cls(cls); PyObject *weak_cache = get_weak_cache(state, type); @@ -816,14 +823,10 @@ zoneinfo_ZoneInfo__unpickle_impl(PyTypeObject *type, PyTypeObject *cls, /*[clinic end generated code: output=556712fc709deecb input=6ac8c73eed3de316]*/ { if (from_cache) { - PyObject *val_args = PyTuple_Pack(1, key); - if (val_args == NULL) { - return NULL; - } - - PyObject *rv = zoneinfo_new(type, val_args, NULL); - - Py_DECREF(val_args); + PyObject *rv; + Py_BEGIN_CRITICAL_SECTION(type); + rv = zoneinfo_ZoneInfo_impl(type, key); + Py_END_CRITICAL_SECTION(); return rv; } else { @@ -858,8 +861,7 @@ load_timedelta(zoneinfo_state *state, long seconds) 0, seconds, 0, 1, PyDateTimeAPI->DeltaType); if (tmp != NULL) { - rv = PyDict_SetDefault(state->TIMEDELTA_CACHE, pyoffset, tmp); - Py_XINCREF(rv); + PyDict_SetDefaultRef(state->TIMEDELTA_CACHE, pyoffset, tmp, &rv); Py_DECREF(tmp); } } @@ -2368,6 +2370,7 @@ strong_cache_free(StrongCacheNode *root) static void remove_from_strong_cache(zoneinfo_state *state, StrongCacheNode *node) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(state->ZoneInfoType); if (state->ZONEINFO_STRONG_CACHE == node) { state->ZONEINFO_STRONG_CACHE = node->next; } @@ -2422,6 +2425,7 @@ eject_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type, return 0; } + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(state->ZoneInfoType); StrongCacheNode *cache = state->ZONEINFO_STRONG_CACHE; StrongCacheNode *node = find_in_strong_cache(cache, key); if (node != NULL) { @@ -2478,6 +2482,7 @@ zone_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type, return NULL; // Strong cache currently only implemented for base class } + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(state->ZoneInfoType); StrongCacheNode *cache = state->ZONEINFO_STRONG_CACHE; StrongCacheNode *node = find_in_strong_cache(cache, key); @@ -2504,6 +2509,7 @@ update_strong_cache(zoneinfo_state *state, const PyTypeObject *const type, return; } + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(state->ZoneInfoType); StrongCacheNode *new_node = strong_cache_node_new(key, zone); if (new_node == NULL) { return; @@ -2631,7 +2637,7 @@ static PyType_Slot zoneinfo_slots[] = { {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_methods, zoneinfo_methods}, {Py_tp_members, zoneinfo_members}, - {Py_tp_new, zoneinfo_new}, + {Py_tp_new, zoneinfo_ZoneInfo}, {Py_tp_dealloc, zoneinfo_dealloc}, {Py_tp_traverse, zoneinfo_traverse}, {Py_tp_clear, zoneinfo_clear}, diff --git a/Modules/clinic/_zoneinfo.c.h b/Modules/clinic/_zoneinfo.c.h index 9905b6425e2f79..bde88b5c4fa65b 100644 --- a/Modules/clinic/_zoneinfo.c.h +++ b/Modules/clinic/_zoneinfo.c.h @@ -6,8 +6,65 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +PyDoc_STRVAR(zoneinfo_ZoneInfo__doc__, +"ZoneInfo(key)\n" +"--\n" +"\n" +"Create a new ZoneInfo instance."); + +static PyObject * +zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key); + +static PyObject * +zoneinfo_ZoneInfo(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(key), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"key", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "ZoneInfo", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *key; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + key = fastargs[0]; + Py_BEGIN_CRITICAL_SECTION(type); + return_value = zoneinfo_ZoneInfo_impl(type, key); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + PyDoc_STRVAR(zoneinfo_ZoneInfo_from_file__doc__, "from_file($type, file_obj, /, key=None)\n" "--\n" @@ -182,7 +239,9 @@ zoneinfo_ZoneInfo_clear_cache(PyTypeObject *type, PyTypeObject *cls, PyObject *c } only_keys = args[0]; skip_optional_kwonly: + Py_BEGIN_CRITICAL_SECTION(type); return_value = zoneinfo_ZoneInfo_clear_cache_impl(type, cls, only_keys); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -372,4 +431,4 @@ zoneinfo_ZoneInfo__unpickle(PyTypeObject *type, PyTypeObject *cls, PyObject *con exit: return return_value; } -/*[clinic end generated code: output=2a15f32fdd2ab6cd input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b4fdc0b30247110a input=a9049054013a1b77]*/ From cfc27bc50fe165330f2295f9ac0ad56ca5b0f31c Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 14 Oct 2024 07:44:48 +0300 Subject: [PATCH 153/247] gh-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426) Co-authored-by: Serhiy Storchaka --- Doc/library/string.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 57a1f920523035..49aeb28d57c8d1 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -509,9 +509,8 @@ The available presentation types for :class:`float` and | | significant digits. With no precision given, uses a | | | precision of ``6`` digits after the decimal point for | | | :class:`float`, and shows all coefficient digits | - | | for :class:`~decimal.Decimal`. If no digits follow the | - | | decimal point, the decimal point is also removed unless | - | | the ``#`` option is used. | + | | for :class:`~decimal.Decimal`. If ``p=0``, the decimal | + | | point is omitted unless the ``#`` option is used. | +---------+----------------------------------------------------------+ | ``'E'`` | Scientific notation. Same as ``'e'`` except it uses | | | an upper case 'E' as the separator character. | @@ -522,9 +521,8 @@ The available presentation types for :class:`float` and | | precision given, uses a precision of ``6`` digits after | | | the decimal point for :class:`float`, and uses a | | | precision large enough to show all coefficient digits | - | | for :class:`~decimal.Decimal`. If no digits follow the | - | | decimal point, the decimal point is also removed unless | - | | the ``#`` option is used. | + | | for :class:`~decimal.Decimal`. If ``p=0``, the decimal | + | | point is omitted unless the ``#`` option is used. | +---------+----------------------------------------------------------+ | ``'F'`` | Fixed-point notation. Same as ``'f'``, but converts | | | ``nan`` to ``NAN`` and ``inf`` to ``INF``. | From 66b3922b97388c328c9bd8df050eef11c0261fae Mon Sep 17 00:00:00 2001 From: rindeal Date: Mon, 14 Oct 2024 06:36:53 +0000 Subject: [PATCH 154/247] gh-86357: argparse: use str() consistently and explicitly to print choices (GH-117766) Signed-off-by: Jan Chren ~rindeal --- Lib/argparse.py | 12 +++---- Lib/test/test_argparse.py | 31 ++++++++++++++++++- ...-04-19-05-58-50.gh-issue-117766.J3xepp.rst | 1 + 3 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index 550415dc93478b..fa9f5211257e96 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -547,8 +547,7 @@ def _metavar_formatter(self, action, default_metavar): if action.metavar is not None: result = action.metavar elif action.choices is not None: - choice_strs = [str(choice) for choice in action.choices] - result = '{%s}' % ','.join(choice_strs) + result = '{%s}' % ','.join(map(str, action.choices)) else: result = default_metavar @@ -599,8 +598,7 @@ def _expand_help(self, action): elif hasattr(value, '__name__'): params[name] = value.__name__ if params.get('choices') is not None: - choices_str = ', '.join([str(c) for c in params['choices']]) - params['choices'] = choices_str + params['choices'] = ', '.join(map(str, params['choices'])) return help_string % params def _iter_indented_subactions(self, action): @@ -717,7 +715,7 @@ def _get_action_name(argument): elif argument.dest not in (None, SUPPRESS): return argument.dest elif argument.choices: - return '{' + ','.join(argument.choices) + '}' + return '{%s}' % ','.join(map(str, argument.choices)) else: return None @@ -2607,8 +2605,8 @@ def _check_value(self, action, value): if isinstance(choices, str): choices = iter(choices) if value not in choices: - args = {'value': value, - 'choices': ', '.join(map(repr, action.choices))} + args = {'value': str(value), + 'choices': ', '.join(map(str, action.choices))} msg = _('invalid choice: %(value)r (choose from %(choices)s)') raise ArgumentError(action, msg % args) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index f52a4b6bdd8aca..78692fd3474782 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -16,6 +16,7 @@ import argparse import warnings +from enum import StrEnum from test.support import captured_stderr from test.support import import_helper from test.support import os_helper @@ -985,6 +986,34 @@ class TestDisallowLongAbbreviationAllowsShortGroupingPrefix(ParserTestCase): ] +class TestStrEnumChoices(TestCase): + class Color(StrEnum): + RED = "red" + GREEN = "green" + BLUE = "blue" + + def test_parse_enum_value(self): + parser = argparse.ArgumentParser() + parser.add_argument('--color', choices=self.Color) + args = parser.parse_args(['--color', 'red']) + self.assertEqual(args.color, self.Color.RED) + + def test_help_message_contains_enum_choices(self): + parser = argparse.ArgumentParser() + parser.add_argument('--color', choices=self.Color, help='Choose a color') + self.assertIn('[--color {red,green,blue}]', parser.format_usage()) + self.assertIn(' --color {red,green,blue}', parser.format_help()) + + def test_invalid_enum_value_raises_error(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('--color', choices=self.Color) + self.assertRaisesRegex( + argparse.ArgumentError, + r"invalid choice: 'yellow' \(choose from red, green, blue\)", + parser.parse_args, + ['--color', 'yellow'], + ) + # ================ # Positional tests # ================ @@ -2485,7 +2514,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" + r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from foo, bar\)\n$" ) def test_optional_subparsers(self): diff --git a/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst b/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst new file mode 100644 index 00000000000000..d090f931f0238d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst @@ -0,0 +1 @@ +Always use :func:`str` to print ``choices`` in :mod:`argparse`. From b52c7306ea4470f9d7548655c2a1b89a07ff5504 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 14 Oct 2024 10:54:59 +0300 Subject: [PATCH 155/247] gh-121797: Add class method Fraction.from_number() (GH-121800) It is an alternative constructor which only accepts a single numeric argument. Unlike to Fraction.from_float() and Fraction.from_decimal() it accepts any real numbers supported by the standard constructor (int, float, Decimal, Rational numbers, objects with as_integer_ratio()). Unlike to the standard constructor, it does not accept strings. --- Doc/library/fractions.rst | 10 ++++ Doc/whatsnew/3.14.rst | 4 ++ Lib/fractions.py | 25 +++++++++- Lib/test/test_fractions.py | 49 ++++++++++++++++--- ...-07-15-19-34-56.gh-issue-121797.qDqj59.rst | 2 + 5 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 2ee154952549ac..fc7f9a6301a915 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -166,6 +166,16 @@ another rational number, or from a string. instance. + .. classmethod:: from_number(number) + + Alternative constructor which only accepts instances of + :class:`numbers.Integral`, :class:`numbers.Rational`, + :class:`float` or :class:`decimal.Decimal`, and objects with + the :meth:`!as_integer_ratio` method, but not strings. + + .. versionadded:: 3.14 + + .. method:: limit_denominator(max_denominator=1000000) Finds and returns the closest :class:`Fraction` to ``self`` that has diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index c62a3ca5872eef..b22d1bd1e99d4e 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -263,6 +263,10 @@ fractions :meth:`!as_integer_ratio` method to a :class:`~fractions.Fraction`. (Contributed by Serhiy Storchaka in :gh:`82017`.) +* Add alternative :class:`~fractions.Fraction` constructor + :meth:`Fraction.from_number() `. + (Contributed by Serhiy Storchaka in :gh:`121797`.) + functools --------- diff --git a/Lib/fractions.py b/Lib/fractions.py index 34fd0803d1b1ab..f0cbc8c2e6c012 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -279,7 +279,8 @@ def __new__(cls, numerator=0, denominator=None): numerator = -numerator else: - raise TypeError("argument should be a string or a number") + raise TypeError("argument should be a string or a Rational " + "instance or have the as_integer_ratio() method") elif type(numerator) is int is type(denominator): pass # *very* normal case @@ -305,6 +306,28 @@ def __new__(cls, numerator=0, denominator=None): self._denominator = denominator return self + @classmethod + def from_number(cls, number): + """Converts a finite real number to a rational number, exactly. + + Beware that Fraction.from_number(0.3) != Fraction(3, 10). + + """ + if type(number) is int: + return cls._from_coprime_ints(number, 1) + + elif isinstance(number, numbers.Rational): + return cls._from_coprime_ints(number.numerator, number.denominator) + + elif (isinstance(number, float) or + (not isinstance(number, type) and + hasattr(number, 'as_integer_ratio'))): + return cls._from_coprime_ints(*number.as_integer_ratio()) + + else: + raise TypeError("argument should be a Rational instance or " + "have the as_integer_ratio() method") + @classmethod def from_float(cls, f): """Converts a finite float to a rational number, exactly. diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 4907f4093f52c9..98dccbec9566ac 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -283,6 +283,13 @@ def __repr__(self): class RectComplex(Rect, complex): pass +class Ratio: + def __init__(self, ratio): + self._ratio = ratio + def as_integer_ratio(self): + return self._ratio + + class FractionTest(unittest.TestCase): def assertTypedEquals(self, expected, actual): @@ -355,14 +362,9 @@ def testInitFromDecimal(self): self.assertRaises(OverflowError, F, Decimal('-inf')) def testInitFromIntegerRatio(self): - class Ratio: - def __init__(self, ratio): - self._ratio = ratio - def as_integer_ratio(self): - return self._ratio - self.assertEqual((7, 3), _components(F(Ratio((7, 3))))) - errmsg = "argument should be a string or a number" + errmsg = (r"argument should be a string or a Rational instance or " + r"have the as_integer_ratio\(\) method") # the type also has an "as_integer_ratio" attribute. self.assertRaisesRegex(TypeError, errmsg, F, Ratio) # bad ratio @@ -388,6 +390,8 @@ class B(metaclass=M): pass self.assertRaisesRegex(TypeError, errmsg, F, B) self.assertRaisesRegex(TypeError, errmsg, F, B()) + self.assertRaises(TypeError, F.from_number, B) + self.assertRaises(TypeError, F.from_number, B()) def testFromString(self): self.assertEqual((5, 1), _components(F("5"))) @@ -594,6 +598,37 @@ def testFromDecimal(self): ValueError, "cannot convert NaN to integer ratio", F.from_decimal, Decimal("snan")) + def testFromNumber(self, cls=F): + def check(arg, numerator, denominator): + f = cls.from_number(arg) + self.assertIs(type(f), cls) + self.assertEqual(f.numerator, numerator) + self.assertEqual(f.denominator, denominator) + + check(10, 10, 1) + check(2.5, 5, 2) + check(Decimal('2.5'), 5, 2) + check(F(22, 7), 22, 7) + check(DummyFraction(22, 7), 22, 7) + check(Rat(22, 7), 22, 7) + check(Ratio((22, 7)), 22, 7) + self.assertRaises(TypeError, cls.from_number, 3+4j) + self.assertRaises(TypeError, cls.from_number, '5/2') + self.assertRaises(TypeError, cls.from_number, []) + self.assertRaises(OverflowError, cls.from_number, float('inf')) + self.assertRaises(OverflowError, cls.from_number, Decimal('inf')) + + # as_integer_ratio not defined in a class + class A: + pass + a = A() + a.as_integer_ratio = lambda: (9, 5) + check(a, 9, 5) + + def testFromNumber_subclass(self): + self.testFromNumber(DummyFraction) + + def test_is_integer(self): self.assertTrue(F(1, 1).is_integer()) self.assertTrue(F(-1, 1).is_integer()) diff --git a/Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst b/Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst new file mode 100644 index 00000000000000..9525379587f6cd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst @@ -0,0 +1,2 @@ +Add alternative :class:`~fractions.Fraction` constructor +:meth:`Fraction.from_number() `. From 4b358ee647809019813f106eb901f466a3846d98 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Mon, 14 Oct 2024 16:17:51 +0800 Subject: [PATCH 156/247] gh-125323: Remove some unsafe Py_DECREFs in bytecodes.c, replacing them with PyStackRef_CLOSEs (GH-125324) --- Include/internal/pycore_stackref.h | 3 ++ Python/bytecodes.c | 40 +++++++++++----------- Python/executor_cases.c.h | 40 +++++++++++----------- Python/generated_cases.c.h | 40 +++++++++++----------- Tools/cases_generator/analyzer.py | 1 + Tools/cases_generator/generators_common.py | 1 + 6 files changed, 65 insertions(+), 60 deletions(-) diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 7d1eb11aa5ecb8..0e6410466b924b 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -153,6 +153,8 @@ PyStackRef_AsStrongReference(_PyStackRef stackref) return PyStackRef_FromPyObjectSteal(PyStackRef_AsPyObjectSteal(stackref)); } +#define PyStackRef_CLOSE_SPECIALIZED(stackref, dealloc) PyStackRef_CLOSE(stackref) + #else // Py_GIL_DISABLED @@ -177,6 +179,7 @@ static const _PyStackRef PyStackRef_NULL = { .bits = 0 }; #define PyStackRef_DUP(stackref) PyStackRef_FromPyObjectSteal(Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref))) +#define PyStackRef_CLOSE_SPECIALIZED(stackref, dealloc) _Py_DECREF_SPECIALIZED(PyStackRef_AsPyObjectBorrow(stackref), dealloc) #endif // Py_GIL_DISABLED diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 34fdfcb05e3c18..299608f252c546 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -474,8 +474,8 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); @@ -487,8 +487,8 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); @@ -500,8 +500,8 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); @@ -594,8 +594,8 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); @@ -636,12 +636,12 @@ dummy_func( * that the string is safe to mutate. */ assert(Py_REFCNT(left_o) >= 2); - _Py_DECREF_NO_DEALLOC(left_o); + PyStackRef_CLOSE(left); DEAD(left); PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); PyUnicode_Append(&temp, right_o); *target_local = PyStackRef_FromPyObjectSteal(temp); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); DEAD(right); ERROR_IF(PyStackRef_IsNull(*target_local), error); #if TIER_ONE @@ -755,7 +755,7 @@ dummy_func( PyObject *res_o = PyList_GET_ITEM(list, index); assert(res_o != NULL); Py_INCREF(res_o); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); DEAD(sub_st); PyStackRef_CLOSE(list_st); res = PyStackRef_FromPyObjectSteal(res_o); @@ -775,7 +775,7 @@ dummy_func( DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c); STAT_INC(BINARY_SUBSCR, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); DEAD(sub_st); PyStackRef_CLOSE(str_st); res = PyStackRef_FromPyObjectSteal(res_o); @@ -796,7 +796,7 @@ dummy_func( PyObject *res_o = PyTuple_GET_ITEM(tuple, index); assert(res_o != NULL); Py_INCREF(res_o); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); DEAD(sub_st); PyStackRef_CLOSE(tuple_st); res = PyStackRef_FromPyObjectSteal(res_o); @@ -908,7 +908,7 @@ dummy_func( PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); Py_DECREF(old_value); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); DEAD(sub_st); PyStackRef_CLOSE(list_st); } @@ -2398,9 +2398,9 @@ dummy_func( double dright = PyFloat_AS_DOUBLE(right_o); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); - _Py_DECREF_SPECIALIZED(left_o, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); DEAD(left); - _Py_DECREF_SPECIALIZED(right_o, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); DEAD(right); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. @@ -2420,9 +2420,9 @@ dummy_func( Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); DEAD(left); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); DEAD(right); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. @@ -2436,9 +2436,9 @@ dummy_func( STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left_o, right_o); assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); - _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); DEAD(left); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); DEAD(right); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ef110e2e2a794a..5532c04e497a75 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -541,8 +541,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -561,8 +561,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -581,8 +581,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -722,8 +722,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -764,11 +764,11 @@ * that the string is safe to mutate. */ assert(Py_REFCNT(left_o) >= 2); - _Py_DECREF_NO_DEALLOC(left_o); + PyStackRef_CLOSE(left); PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); PyUnicode_Append(&temp, right_o); *target_local = PyStackRef_FromPyObjectSteal(temp); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (PyStackRef_IsNull(*target_local)) JUMP_TO_ERROR(); #if TIER_ONE // The STORE_FAST is already done. This is done here in tier one, @@ -904,7 +904,7 @@ PyObject *res_o = PyList_GET_ITEM(list, index); assert(res_o != NULL); Py_INCREF(res_o); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(list_st); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -946,7 +946,7 @@ } STAT_INC(BINARY_SUBSCR, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(str_st); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -985,7 +985,7 @@ PyObject *res_o = PyTuple_GET_ITEM(tuple, index); assert(res_o != NULL); Py_INCREF(res_o); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(tuple_st); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -1160,7 +1160,7 @@ PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); Py_DECREF(old_value); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(list_st); stack_pointer += -3; assert(WITHIN_STACK_BOUNDS()); @@ -2912,8 +2912,8 @@ double dright = PyFloat_AS_DOUBLE(right_o); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); - _Py_DECREF_SPECIALIZED(left_o, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(right_o, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. stack_pointer[-2] = res; @@ -2946,8 +2946,8 @@ Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. stack_pointer[-2] = res; @@ -2968,8 +2968,8 @@ STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left_o, right_o); assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); - _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7023aea369db49..0eeb566a0adadc 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -118,8 +118,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } @@ -153,8 +153,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } @@ -207,11 +207,11 @@ * that the string is safe to mutate. */ assert(Py_REFCNT(left_o) >= 2); - _Py_DECREF_NO_DEALLOC(left_o); + PyStackRef_CLOSE(left); PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); PyUnicode_Append(&temp, right_o); *target_local = PyStackRef_FromPyObjectSteal(temp); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (PyStackRef_IsNull(*target_local)) goto pop_2_error; #if TIER_ONE // The STORE_FAST is already done. This is done here in tier one, @@ -285,8 +285,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } @@ -356,8 +356,8 @@ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } @@ -582,7 +582,7 @@ PyObject *res_o = PyList_GET_ITEM(list, index); assert(res_o != NULL); Py_INCREF(res_o); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(list_st); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -614,7 +614,7 @@ DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c, BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(str_st); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -646,7 +646,7 @@ PyObject *res_o = PyTuple_GET_ITEM(tuple, index); assert(res_o != NULL); Py_INCREF(res_o); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(tuple_st); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; @@ -3284,8 +3284,8 @@ double dright = PyFloat_AS_DOUBLE(right_o); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); - _Py_DECREF_SPECIALIZED(left_o, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(right_o, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. } @@ -3326,8 +3326,8 @@ Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. } @@ -3362,8 +3362,8 @@ STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left_o, right_o); assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); - _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); @@ -7720,7 +7720,7 @@ PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); Py_DECREF(old_value); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free); PyStackRef_CLOSE(list_st); stack_pointer += -3; assert(WITHIN_STACK_BOUNDS()); diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 60f5d010a7a083..19fdeac65cf2df 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -540,6 +540,7 @@ def has_error_without_pop(op: parser.InstDef) -> bool: "PyStackRef_AsPyObjectSteal", "PyStackRef_CLEAR", "PyStackRef_CLOSE", + "PyStackRef_CLOSE_SPECIALIZED", "PyStackRef_DUP", "PyStackRef_False", "PyStackRef_FromPyObjectImmortal", diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index 0bfa1a3b56fbc2..7e032c21d2485c 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -116,6 +116,7 @@ def __init__(self, out: CWriter): "SAVE_STACK": self.save_stack, "RELOAD_STACK": self.reload_stack, "PyStackRef_CLOSE": self.stackref_close, + "PyStackRef_CLOSE_SPECIALIZED": self.stackref_close, "PyStackRef_AsPyObjectSteal": self.stackref_steal, "DISPATCH": self.dispatch } From 5217328f93f599755bd70418952392c54f705a71 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 14 Oct 2024 11:24:01 +0300 Subject: [PATCH 157/247] gh-121798: Add class method Decimal.from_number() (GH-121801) It is an alternate constructor which only accepts a single numeric argument. Unlike to Decimal.from_float() it accepts also Decimal. Unlike to the standard constructor, it does not accept strings and tuples. --- Doc/library/decimal.rst | 17 +++++++ Doc/whatsnew/3.14.rst | 6 +++ Lib/_pydecimal.py | 15 ++++++ Lib/test/test_decimal.py | 23 ++++++++++ ...-07-15-19-25-25.gh-issue-121798.GmuBDu.rst | 2 + Modules/_decimal/_decimal.c | 46 +++++++++++++++++++ Modules/_decimal/docstrings.h | 13 ++++++ 7 files changed, 122 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 916f17cadfaa7e..c9a3e448cad063 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -598,6 +598,23 @@ Decimal objects .. versionadded:: 3.1 + .. classmethod:: from_number(number) + + Alternative constructor that only accepts instances of + :class:`float`, :class:`int` or :class:`Decimal`, but not strings + or tuples. + + .. doctest:: + + >>> Decimal.from_number(314) + Decimal('314') + >>> Decimal.from_number(0.1) + Decimal('0.1000000000000000055511151231257827021181583404541015625') + >>> Decimal.from_number(Decimal('3.14')) + Decimal('3.14') + + .. versionadded:: 3.14 + .. method:: fma(other, third, context=None) Fused multiply-add. Return self*other+third with no rounding of the diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index b22d1bd1e99d4e..25e69a59bdec62 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -239,6 +239,12 @@ ctypes to help match a non-default ABI. (Contributed by Petr Viktorin in :gh:`97702`.) +decimal +------- + +* Add alternative :class:`~decimal.Decimal` constructor + :meth:`Decimal.from_number() `. + (Contributed by Serhiy Storchaka in :gh:`121798`.) dis --- diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py index 75df3db262470b..5b60570c6c592a 100644 --- a/Lib/_pydecimal.py +++ b/Lib/_pydecimal.py @@ -582,6 +582,21 @@ def __new__(cls, value="0", context=None): raise TypeError("Cannot convert %r to Decimal" % value) + @classmethod + def from_number(cls, number): + """Converts a real number to a decimal number, exactly. + + >>> Decimal.from_number(314) # int + Decimal('314') + >>> Decimal.from_number(0.1) # float + Decimal('0.1000000000000000055511151231257827021181583404541015625') + >>> Decimal.from_number(Decimal('3.14')) # another decimal instance + Decimal('3.14') + """ + if isinstance(number, (int, Decimal, float)): + return cls(number) + raise TypeError("Cannot convert %r to Decimal" % number) + @classmethod def from_float(cls, f): """Converts a float to a decimal number, exactly. diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index d1e7e69e7e951b..bc6c6427740949 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -812,6 +812,29 @@ def test_explicit_context_create_from_float(self): x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip + def test_from_number(self, cls=None): + Decimal = self.decimal.Decimal + if cls is None: + cls = Decimal + + def check(arg, expected): + d = cls.from_number(arg) + self.assertIs(type(d), cls) + self.assertEqual(d, expected) + + check(314, Decimal(314)) + check(3.14, Decimal.from_float(3.14)) + check(Decimal('3.14'), Decimal('3.14')) + self.assertRaises(TypeError, cls.from_number, 3+4j) + self.assertRaises(TypeError, cls.from_number, '314') + self.assertRaises(TypeError, cls.from_number, (0, (3, 1, 4), 0)) + self.assertRaises(TypeError, cls.from_number, object()) + + def test_from_number_subclass(self, cls=None): + class DecimalSubclass(self.decimal.Decimal): + pass + self.test_from_number(DecimalSubclass) + def test_unicode_digits(self): Decimal = self.decimal.Decimal diff --git a/Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst b/Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst new file mode 100644 index 00000000000000..5706e4bffeb4a1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst @@ -0,0 +1,2 @@ +Add alternative :class:`~decimal.Decimal` constructor +:meth:`Decimal.from_number() `. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index a33c9793b5ad17..c564813036e504 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2857,6 +2857,51 @@ dec_from_float(PyObject *type, PyObject *pyfloat) return result; } +/* 'v' can have any numeric type accepted by the Decimal constructor. Attempt + an exact conversion. If the result does not meet the restrictions + for an mpd_t, fail with InvalidOperation. */ +static PyObject * +PyDecType_FromNumberExact(PyTypeObject *type, PyObject *v, PyObject *context) +{ + decimal_state *state = get_module_state_by_def(type); + assert(v != NULL); + if (PyDec_Check(state, v)) { + return PyDecType_FromDecimalExact(type, v, context); + } + else if (PyLong_Check(v)) { + return PyDecType_FromLongExact(type, v, context); + } + else if (PyFloat_Check(v)) { + if (dec_addstatus(context, MPD_Float_operation)) { + return NULL; + } + return PyDecType_FromFloatExact(type, v, context); + } + else { + PyErr_Format(PyExc_TypeError, + "conversion from %s to Decimal is not supported", + Py_TYPE(v)->tp_name); + return NULL; + } +} + +/* class method */ +static PyObject * +dec_from_number(PyObject *type, PyObject *number) +{ + PyObject *context; + PyObject *result; + + decimal_state *state = get_module_state_by_def((PyTypeObject *)type); + CURRENT_CONTEXT(state, context); + result = PyDecType_FromNumberExact(state->PyDec_Type, number, context); + if (type != (PyObject *)state->PyDec_Type && result != NULL) { + Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL)); + } + + return result; +} + /* create_decimal_from_float */ static PyObject * ctx_from_float(PyObject *context, PyObject *v) @@ -5052,6 +5097,7 @@ static PyMethodDef dec_methods [] = /* Miscellaneous */ { "from_float", dec_from_float, METH_O|METH_CLASS, doc_from_float }, + { "from_number", dec_from_number, METH_O|METH_CLASS, doc_from_number }, { "as_tuple", PyDec_AsTuple, METH_NOARGS, doc_as_tuple }, { "as_integer_ratio", dec_as_integer_ratio, METH_NOARGS, doc_as_integer_ratio }, diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index a1823cdd32b74c..b34bff83d3f4e9 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -189,6 +189,19 @@ Decimal.from_float(0.1) is not the same as Decimal('0.1').\n\ \n\ \n"); +PyDoc_STRVAR(doc_from_number, +"from_number($type, number, /)\n--\n\n\ +Class method that converts a real number to a decimal number, exactly.\n\ +\n\ + >>> Decimal.from_number(314) # int\n\ + Decimal('314')\n\ + >>> Decimal.from_number(0.1) # float\n\ + Decimal('0.1000000000000000055511151231257827021181583404541015625')\n\ + >>> Decimal.from_number(Decimal('3.14')) # another decimal instance\n\ + Decimal('3.14')\n\ +\n\ +\n"); + PyDoc_STRVAR(doc_fma, "fma($self, /, other, third, context=None)\n--\n\n\ Fused multiply-add. Return self*other+third with no rounding of the\n\ From 67f6e08147bc005e460d82fcce85bf5d56009cf5 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Mon, 14 Oct 2024 14:06:31 +0530 Subject: [PATCH 158/247] gh-125139: use `_PyRecursiveMutex` in `_thread.RLock` (#125144) --- Include/internal/pycore_lock.h | 3 +- Modules/_threadmodule.c | 151 +++++++-------------------------- Python/lock.c | 31 ++++++- 3 files changed, 63 insertions(+), 122 deletions(-) diff --git a/Include/internal/pycore_lock.h b/Include/internal/pycore_lock.h index cd7deda00c7bee..57cbce8f126aca 100644 --- a/Include/internal/pycore_lock.h +++ b/Include/internal/pycore_lock.h @@ -160,8 +160,9 @@ typedef struct { PyAPI_FUNC(int) _PyRecursiveMutex_IsLockedByCurrentThread(_PyRecursiveMutex *m); PyAPI_FUNC(void) _PyRecursiveMutex_Lock(_PyRecursiveMutex *m); +extern PyLockStatus _PyRecursiveMutex_LockTimed(_PyRecursiveMutex *m, PyTime_t timeout, _PyLockFlags flags); PyAPI_FUNC(void) _PyRecursiveMutex_Unlock(_PyRecursiveMutex *m); - +extern int _PyRecursiveMutex_TryUnlock(_PyRecursiveMutex *m); // A readers-writer (RW) lock. The lock supports multiple concurrent readers or // a single writer. The lock is write-preferring: if a writer is waiting while diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 9617f9cafe76ff..d4408aa9e42d9d 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -726,11 +726,6 @@ lock_dealloc(PyObject *op) Py_DECREF(tp); } -static inline PyLockStatus -acquire_timed(PyThread_type_lock lock, PyTime_t timeout) -{ - return PyThread_acquire_lock_timed_with_retries(lock, timeout); -} static int lock_acquire_parse_args(PyObject *args, PyObject *kwds, @@ -973,10 +968,7 @@ static PyType_Spec lock_type_spec = { typedef struct { PyObject_HEAD - PyThread_type_lock rlock_lock; - PyThread_ident_t rlock_owner; - unsigned long rlock_count; - PyObject *in_weakreflist; + _PyRecursiveMutex lock; } rlockobject; static int @@ -992,59 +984,26 @@ rlock_dealloc(PyObject *op) { rlockobject *self = (rlockobject*)op; PyObject_GC_UnTrack(self); - if (self->in_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) self); - /* self->rlock_lock can be NULL if PyThread_allocate_lock() failed - in rlock_new() */ - if (self->rlock_lock != NULL) { - /* Unlock the lock so it's safe to free it */ - if (self->rlock_count > 0) - PyThread_release_lock(self->rlock_lock); - - PyThread_free_lock(self->rlock_lock); - } + PyObject_ClearWeakRefs((PyObject *) self); PyTypeObject *tp = Py_TYPE(self); tp->tp_free(self); Py_DECREF(tp); } -static bool -rlock_is_owned_by(rlockobject *self, PyThread_ident_t tid) -{ - PyThread_ident_t owner_tid = - _Py_atomic_load_ullong_relaxed(&self->rlock_owner); - return owner_tid == tid && self->rlock_count > 0; -} static PyObject * rlock_acquire(PyObject *op, PyObject *args, PyObject *kwds) { rlockobject *self = (rlockobject*)op; PyTime_t timeout; - PyThread_ident_t tid; - PyLockStatus r = PY_LOCK_ACQUIRED; - if (lock_acquire_parse_args(args, kwds, &timeout) < 0) + if (lock_acquire_parse_args(args, kwds, &timeout) < 0) { return NULL; - - tid = PyThread_get_thread_ident_ex(); - if (rlock_is_owned_by(self, tid)) { - unsigned long count = self->rlock_count + 1; - if (count <= self->rlock_count) { - PyErr_SetString(PyExc_OverflowError, - "Internal lock count overflowed"); - return NULL; - } - self->rlock_count = count; - Py_RETURN_TRUE; - } - r = acquire_timed(self->rlock_lock, timeout); - if (r == PY_LOCK_ACQUIRED) { - assert(self->rlock_count == 0); - _Py_atomic_store_ullong_relaxed(&self->rlock_owner, tid); - self->rlock_count = 1; } - else if (r == PY_LOCK_INTR) { + + PyLockStatus r = _PyRecursiveMutex_LockTimed(&self->lock, timeout, + _PY_LOCK_HANDLE_SIGNALS | _PY_LOCK_DETACH); + if (r == PY_LOCK_INTR) { return NULL; } @@ -1078,17 +1037,12 @@ static PyObject * rlock_release(PyObject *op, PyObject *Py_UNUSED(ignored)) { rlockobject *self = (rlockobject*)op; - PyThread_ident_t tid = PyThread_get_thread_ident_ex(); - if (!rlock_is_owned_by(self, tid)) { + if (_PyRecursiveMutex_TryUnlock(&self->lock) < 0) { PyErr_SetString(PyExc_RuntimeError, "cannot release un-acquired lock"); return NULL; } - if (--self->rlock_count == 0) { - _Py_atomic_store_ullong_relaxed(&self->rlock_owner, 0); - PyThread_release_lock(self->rlock_lock); - } Py_RETURN_NONE; } @@ -1116,25 +1070,15 @@ rlock_acquire_restore(PyObject *op, PyObject *args) { rlockobject *self = (rlockobject*)op; PyThread_ident_t owner; - unsigned long count; - int r = 1; + Py_ssize_t count; - if (!PyArg_ParseTuple(args, "(k" Py_PARSE_THREAD_IDENT_T "):_acquire_restore", + if (!PyArg_ParseTuple(args, "(n" Py_PARSE_THREAD_IDENT_T "):_acquire_restore", &count, &owner)) return NULL; - if (!PyThread_acquire_lock(self->rlock_lock, 0)) { - Py_BEGIN_ALLOW_THREADS - r = PyThread_acquire_lock(self->rlock_lock, 1); - Py_END_ALLOW_THREADS - } - if (!r) { - PyErr_SetString(ThreadError, "couldn't acquire lock"); - return NULL; - } - assert(self->rlock_count == 0); - _Py_atomic_store_ullong_relaxed(&self->rlock_owner, owner); - self->rlock_count = count; + _PyRecursiveMutex_Lock(&self->lock); + _Py_atomic_store_ullong_relaxed(&self->lock.thread, owner); + self->lock.level = (size_t)count - 1; Py_RETURN_NONE; } @@ -1148,21 +1092,18 @@ static PyObject * rlock_release_save(PyObject *op, PyObject *Py_UNUSED(ignored)) { rlockobject *self = (rlockobject*)op; - PyThread_ident_t owner; - unsigned long count; - if (self->rlock_count == 0) { + if (!_PyRecursiveMutex_IsLockedByCurrentThread(&self->lock)) { PyErr_SetString(PyExc_RuntimeError, "cannot release un-acquired lock"); return NULL; } - owner = self->rlock_owner; - count = self->rlock_count; - self->rlock_count = 0; - _Py_atomic_store_ullong_relaxed(&self->rlock_owner, 0); - PyThread_release_lock(self->rlock_lock); - return Py_BuildValue("k" Py_PARSE_THREAD_IDENT_T, count, owner); + PyThread_ident_t owner = self->lock.thread; + Py_ssize_t count = self->lock.level + 1; + self->lock.level = 0; // ensure the unlock releases the lock + _PyRecursiveMutex_Unlock(&self->lock); + return Py_BuildValue("n" Py_PARSE_THREAD_IDENT_T, count, owner); } PyDoc_STRVAR(rlock_release_save_doc, @@ -1175,10 +1116,10 @@ static PyObject * rlock_recursion_count(PyObject *op, PyObject *Py_UNUSED(ignored)) { rlockobject *self = (rlockobject*)op; - PyThread_ident_t tid = PyThread_get_thread_ident_ex(); - PyThread_ident_t owner = - _Py_atomic_load_ullong_relaxed(&self->rlock_owner); - return PyLong_FromUnsignedLong(owner == tid ? self->rlock_count : 0UL); + if (_PyRecursiveMutex_IsLockedByCurrentThread(&self->lock)) { + return PyLong_FromSize_t(self->lock.level + 1); + } + return PyLong_FromLong(0); } PyDoc_STRVAR(rlock_recursion_count_doc, @@ -1191,12 +1132,8 @@ static PyObject * rlock_is_owned(PyObject *op, PyObject *Py_UNUSED(ignored)) { rlockobject *self = (rlockobject*)op; - PyThread_ident_t tid = PyThread_get_thread_ident_ex(); - - if (rlock_is_owned_by(self, tid)) { - Py_RETURN_TRUE; - } - Py_RETURN_FALSE; + long owned = _PyRecursiveMutex_IsLockedByCurrentThread(&self->lock); + return PyBool_FromLong(owned); } PyDoc_STRVAR(rlock_is_owned_doc, @@ -1212,16 +1149,7 @@ rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (self == NULL) { return NULL; } - self->in_weakreflist = NULL; - self->rlock_owner = 0; - self->rlock_count = 0; - - self->rlock_lock = PyThread_allocate_lock(); - if (self->rlock_lock == NULL) { - Py_DECREF(self); - PyErr_SetString(ThreadError, "can't allocate lock"); - return NULL; - } + self->lock = (_PyRecursiveMutex){0}; return (PyObject *) self; } @@ -1229,13 +1157,13 @@ static PyObject * rlock_repr(PyObject *op) { rlockobject *self = (rlockobject*)op; - PyThread_ident_t owner = - _Py_atomic_load_ullong_relaxed(&self->rlock_owner); + PyThread_ident_t owner = self->lock.thread; + size_t count = self->lock.level + 1; return PyUnicode_FromFormat( - "<%s %s object owner=%" PY_FORMAT_THREAD_IDENT_T " count=%lu at %p>", - self->rlock_count ? "locked" : "unlocked", + "<%s %s object owner=%" PY_FORMAT_THREAD_IDENT_T " count=%zu at %p>", + owner ? "locked" : "unlocked", Py_TYPE(self)->tp_name, owner, - self->rlock_count, self); + count, self); } @@ -1243,14 +1171,7 @@ rlock_repr(PyObject *op) static PyObject * rlock__at_fork_reinit(rlockobject *self, PyObject *Py_UNUSED(args)) { - if (_PyThread_at_fork_reinit(&self->rlock_lock) < 0) { - PyErr_SetString(ThreadError, "failed to reinitialize lock at fork"); - return NULL; - } - - self->rlock_owner = 0; - self->rlock_count = 0; - + self->lock = (_PyRecursiveMutex){0}; Py_RETURN_NONE; } #endif /* HAVE_FORK */ @@ -1281,18 +1202,12 @@ static PyMethodDef rlock_methods[] = { }; -static PyMemberDef rlock_type_members[] = { - {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(rlockobject, in_weakreflist), Py_READONLY}, - {NULL}, -}; - static PyType_Slot rlock_type_slots[] = { {Py_tp_dealloc, rlock_dealloc}, {Py_tp_repr, rlock_repr}, {Py_tp_methods, rlock_methods}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, rlock_new}, - {Py_tp_members, rlock_type_members}, {Py_tp_traverse, rlock_traverse}, {0, 0}, }; @@ -1301,7 +1216,7 @@ static PyType_Spec rlock_type_spec = { .name = "_thread.RLock", .basicsize = sizeof(rlockobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_WEAKREF), .slots = rlock_type_slots, }; diff --git a/Python/lock.c b/Python/lock.c index 57675fe1873fa2..554c51d7780322 100644 --- a/Python/lock.c +++ b/Python/lock.c @@ -377,21 +377,46 @@ _PyRecursiveMutex_Lock(_PyRecursiveMutex *m) assert(m->level == 0); } +PyLockStatus +_PyRecursiveMutex_LockTimed(_PyRecursiveMutex *m, PyTime_t timeout, _PyLockFlags flags) +{ + PyThread_ident_t thread = PyThread_get_thread_ident_ex(); + if (recursive_mutex_is_owned_by(m, thread)) { + m->level++; + return PY_LOCK_ACQUIRED; + } + PyLockStatus s = _PyMutex_LockTimed(&m->mutex, timeout, flags); + if (s == PY_LOCK_ACQUIRED) { + _Py_atomic_store_ullong_relaxed(&m->thread, thread); + assert(m->level == 0); + } + return s; +} + void _PyRecursiveMutex_Unlock(_PyRecursiveMutex *m) +{ + if (_PyRecursiveMutex_TryUnlock(m) < 0) { + Py_FatalError("unlocking a recursive mutex that is not " + "owned by the current thread"); + } +} + +int +_PyRecursiveMutex_TryUnlock(_PyRecursiveMutex *m) { PyThread_ident_t thread = PyThread_get_thread_ident_ex(); if (!recursive_mutex_is_owned_by(m, thread)) { - Py_FatalError("unlocking a recursive mutex that is not owned by the" - " current thread"); + return -1; } if (m->level > 0) { m->level--; - return; + return 0; } assert(m->level == 0); _Py_atomic_store_ullong_relaxed(&m->thread, 0); PyMutex_Unlock(&m->mutex); + return 0; } #define _Py_WRITE_LOCKED 1 From 06ca33020e1168459fc6c3e0df93664daf801339 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 14 Oct 2024 14:18:57 +0100 Subject: [PATCH 159/247] GH-125323: Convert DECREF_INPUTS_AND_REUSE_FLOAT into a function that takes PyStackRefs. (GH-125439) --- Include/internal/pycore_ceval.h | 2 ++ Include/internal/pycore_opcode_metadata.h | 6 ++-- Include/internal/pycore_stackref.h | 7 +++++ Include/internal/pycore_uop_metadata.h | 6 ++-- Objects/floatobject.c | 35 +++++++++++++++++++++++ Python/bytecodes.c | 12 ++++---- Python/ceval_macros.h | 20 ------------- Python/executor_cases.c.h | 12 ++++---- Python/generated_cases.c.h | 12 ++++---- Tools/cases_generator/analyzer.py | 1 + 10 files changed, 69 insertions(+), 44 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 594fbb1c8e443b..cff2b1f7114793 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -316,6 +316,8 @@ _Py_eval_breaker_bit_is_set(PyThreadState *tstate, uintptr_t bit) void _Py_set_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit); void _Py_unset_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit); +PyAPI_FUNC(PyObject *) _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value); + #ifdef __cplusplus } diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 8fec45b1e8d5c3..c18423476d3962 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1015,13 +1015,13 @@ extern const struct opcode_metadata _PyOpcode_opcode_metadata[266]; #ifdef NEED_OPCODE_METADATA const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, + [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, + [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, + [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 0e6410466b924b..588e57f6cd97e0 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -76,6 +76,13 @@ PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) #define PyStackRef_IsDeferred(ref) (((ref).bits & Py_TAG_BITS) == Py_TAG_DEFERRED) +static inline PyObject * +PyStackRef_NotDeferred_AsPyObject(_PyStackRef stackref) +{ + assert(!PyStackRef_IsDeferred(stackref)); + return (PyObject *)stackref.bits; +} + static inline PyObject * PyStackRef_AsPyObjectSteal(_PyStackRef stackref) { diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index fd41e9a5fe862b..2f0a7fb2f6e549 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -69,9 +69,9 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG, [_GUARD_NOS_FLOAT] = HAS_EXIT_FLAG, [_GUARD_TOS_FLOAT] = HAS_EXIT_FLAG, - [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG, - [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG, - [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, + [_BINARY_OP_MULTIPLY_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_ADD_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_SUBTRACT_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG, [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG, diff --git a/Objects/floatobject.c b/Objects/floatobject.c index a48a210adee3b9..d66863febe8c86 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -134,6 +134,41 @@ PyFloat_FromDouble(double fval) return (PyObject *) op; } +#ifdef Py_GIL_DISABLED + +PyObject *_PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value) +{ + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); + return PyFloat_FromDouble(value); +} + +#else // Py_GIL_DISABLED + +PyObject *_PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value) +{ + PyObject *left_o = PyStackRef_AsPyObjectSteal(left); + PyObject *right_o = PyStackRef_AsPyObjectSteal(right); + if (Py_REFCNT(left_o) == 1) { + ((PyFloatObject *)left_o)->ob_fval = value; + _Py_DECREF_SPECIALIZED(right_o, _PyFloat_ExactDealloc); + return left_o; + } + else if (Py_REFCNT(right_o) == 1) { + ((PyFloatObject *)right_o)->ob_fval = value; + _Py_DECREF_NO_DEALLOC(left_o); + return right_o; + } + else { + PyObject *result = PyFloat_FromDouble(value); + _Py_DECREF_NO_DEALLOC(left_o); + _Py_DECREF_NO_DEALLOC(right_o); + return result; + } +} + +#endif // Py_GIL_DISABLED + static PyObject * float_from_string_inner(const char *s, Py_ssize_t len, void *obj) { diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 299608f252c546..b22916aeaa248b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -539,9 +539,9 @@ dummy_func( double dres = ((PyFloatObject *)left_o)->ob_fval * ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); INPUTS_DEAD(); + ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -553,9 +553,9 @@ dummy_func( double dres = ((PyFloatObject *)left_o)->ob_fval + ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); INPUTS_DEAD(); + ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -567,9 +567,9 @@ dummy_func( double dres = ((PyFloatObject *)left_o)->ob_fval - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); INPUTS_DEAD(); + ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index e0e9cc156ed62f..6674c4ccf9f693 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -327,26 +327,6 @@ GETITEM(PyObject *v, Py_ssize_t i) { " in enclosing scope" #define NAME_ERROR_MSG "name '%.200s' is not defined" -#define DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dval, result) \ -do { \ - if (Py_REFCNT(left) == 1) { \ - ((PyFloatObject *)left)->ob_fval = (dval); \ - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);\ - result = (left); \ - } \ - else if (Py_REFCNT(right) == 1) {\ - ((PyFloatObject *)right)->ob_fval = (dval); \ - _Py_DECREF_NO_DEALLOC(left); \ - result = (right); \ - }\ - else { \ - result = PyFloat_FromDouble(dval); \ - if ((result) == NULL) GOTO_ERROR(error); \ - _Py_DECREF_NO_DEALLOC(left); \ - _Py_DECREF_NO_DEALLOC(right); \ - } \ -} while (0) - // If a trace function sets a new f_lineno and // *then* raises, we use the destination when searching // for an exception handler, displaying the traceback, and so on diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 5532c04e497a75..0ed361a2ee7fb0 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -643,8 +643,8 @@ double dres = ((PyFloatObject *)left_o)->ob_fval * ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; stack_pointer += -1; @@ -664,8 +664,8 @@ double dres = ((PyFloatObject *)left_o)->ob_fval + ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; stack_pointer += -1; @@ -685,8 +685,8 @@ double dres = ((PyFloatObject *)left_o)->ob_fval - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + if (res_o == NULL) JUMP_TO_ERROR(); res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[-2] = res; stack_pointer += -1; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0eeb566a0adadc..7bd1b7dd5aba27 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -84,8 +84,8 @@ double dres = ((PyFloatObject *)left_o)->ob_fval + ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } stack_pointer[-2] = res; @@ -251,8 +251,8 @@ double dres = ((PyFloatObject *)left_o)->ob_fval * ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } stack_pointer[-2] = res; @@ -322,8 +322,8 @@ double dres = ((PyFloatObject *)left_o)->ob_fval - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o; - DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + if (res_o == NULL) goto pop_2_error; res = PyStackRef_FromPyObjectSteal(res_o); } stack_pointer[-2] = res; diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 19fdeac65cf2df..381ad3a4e2082c 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -575,6 +575,7 @@ def has_error_without_pop(op: parser.InstDef) -> bool: "_PyDictValues_AddToInsertionOrder", "_PyErr_Occurred", "_PyEval_FrameClearAndPop", + "_PyFloat_FromDouble_ConsumeInputs", "_PyFrame_GetCode", "_PyFrame_IsIncomplete", "_PyFrame_PushUnchecked", From 5f4e5b598cab86d5fd5727d423c9728221889ed0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 14 Oct 2024 16:29:20 +0300 Subject: [PATCH 160/247] gh-53203: Fix strptime() for %c, %x and %X formats on many locales (GH-125406) Fixed most locales that use non-ASCII digits, like Persian, Burmese, Odia and Shan. --- Lib/_strptime.py | 68 ++++++++++++------- Lib/test/test_strptime.py | 34 ++++++---- Lib/test/test_time.py | 2 +- ...4-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst | 2 + 4 files changed, 66 insertions(+), 40 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst diff --git a/Lib/_strptime.py b/Lib/_strptime.py index 89adc174e5ad30..5f4d2475c0169b 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -15,6 +15,7 @@ import locale import calendar from re import compile as re_compile +from re import sub as re_sub from re import IGNORECASE from re import escape as re_escape from datetime import (date as datetime_date, @@ -129,11 +130,23 @@ def __calc_date_time(self): time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0)) time_tuple2 = time.struct_time((1999,1,3,1,1,1,6,3,0)) replacement_pairs = [ - ('1999', '%Y'), ('99', '%y'), ('22', '%H'), - ('44', '%M'), ('55', '%S'), ('76', '%j'), - ('17', '%d'), ('03', '%m'), ('3', '%m'), - # '3' needed for when no leading zero. - ('2', '%w'), ('10', '%I')] + ('1999', '%Y'), ('99', '%y'), ('22', '%H'), + ('44', '%M'), ('55', '%S'), ('76', '%j'), + ('17', '%d'), ('03', '%m'), ('3', '%m'), + # '3' needed for when no leading zero. + ('2', '%w'), ('10', '%I'), + # Non-ASCII digits + ('\u0661\u0669\u0669\u0669', '%Y'), + ('\u0669\u0669', '%Oy'), + ('\u0662\u0662', '%OH'), + ('\u0664\u0664', '%OM'), + ('\u0665\u0665', '%OS'), + ('\u0661\u0667', '%Od'), + ('\u0660\u0663', '%Om'), + ('\u0663', '%Om'), + ('\u0662', '%Ow'), + ('\u0661\u0660', '%OI'), + ] date_time = [] for directive in ('%c', '%x', '%X'): current_format = time.strftime(directive, time_tuple).lower() @@ -158,6 +171,10 @@ def __calc_date_time(self): for tz in tz_values: if tz: current_format = current_format.replace(tz, "%Z") + # Transform all non-ASCII digits to digits in range U+0660 to U+0669. + current_format = re_sub(r'\d(?3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", 'f': r"(?P[0-9]{1,6})", @@ -296,11 +313,15 @@ def __init__(self, locale_time=None): 'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone for tz in tz_names), 'Z'), - '%': '%'}) - base.__setitem__('W', base.__getitem__('U').replace('U', 'W')) - base.__setitem__('c', self.pattern(self.locale_time.LC_date_time)) - base.__setitem__('x', self.pattern(self.locale_time.LC_date)) + '%': '%'} + for d in 'dmyHIMS': + mapping['O' + d] = r'(?P<%s>\d\d|\d| \d)' % d + mapping['Ow'] = r'(?P\d)' + mapping['W'] = mapping['U'].replace('U', 'W') + base.__init__(mapping) base.__setitem__('X', self.pattern(self.locale_time.LC_time)) + base.__setitem__('x', self.pattern(self.locale_time.LC_date)) + base.__setitem__('c', self.pattern(self.locale_time.LC_date_time)) def __seqToRE(self, to_convert, directive): """Convert a list to a regex string for matching a directive. @@ -328,28 +349,25 @@ def pattern(self, format): regex syntax are escaped. """ - processed_format = '' # The sub() call escapes all characters that might be misconstrued # as regex syntax. Cannot use re.escape since we have to deal with # format directives (%m, etc.). - regex_chars = re_compile(r"([\\.^$*+?\(\){}\[\]|])") - format = regex_chars.sub(r"\\\1", format) - whitespace_replacement = re_compile(r'\s+') - format = whitespace_replacement.sub(r'\\s+', format) + format = re_sub(r"([\\.^$*+?\(\){}\[\]|])", r"\\\1", format) + format = re_sub(r'\s+', r'\\s+', format) + format = re_sub(r"'", "['\u02bc]", format) # needed for br_FR year_in_format = False day_of_month_in_format = False - while '%' in format: - directive_index = format.index('%')+1 - format_char = format[directive_index] - processed_format = "%s%s%s" % (processed_format, - format[:directive_index-1], - self[format_char]) - format = format[directive_index+1:] + def repl(m): + format_char = m[1] match format_char: case 'Y' | 'y' | 'G': + nonlocal year_in_format year_in_format = True case 'd': + nonlocal day_of_month_in_format day_of_month_in_format = True + return self[format_char] + format = re_sub(r'%(O?.)', repl, format) if day_of_month_in_format and not year_in_format: import warnings warnings.warn("""\ @@ -360,7 +378,7 @@ def pattern(self, format): See https://github.com/python/cpython/issues/70647.""", DeprecationWarning, skip_file_prefixes=(os.path.dirname(__file__),)) - return "%s%s" % (processed_format, format) + return format def compile(self, format): """Return a compiled re object for the format string.""" @@ -434,8 +452,8 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): _regex_cache[format] = format_regex found = format_regex.match(data_string) if not found: - raise ValueError("time data %r does not match format %r :: /%s/" % - (data_string, format, format_regex.pattern)) + raise ValueError("time data %r does not match format %r" % + (data_string, format)) if len(data_string) != found.end(): raise ValueError("unconverted data remains: %s" % data_string[found.end():]) diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 79f48dfe44abde..12366b053a2fc1 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -292,7 +292,7 @@ def test_strptime_exception_context(self): # additional check for IndexError branch (issue #19545) with self.assertRaises(ValueError) as e: _strptime._strptime_time('19', '%Y %') - self.assertIs(e.exception.__suppress_context__, True) + self.assertIsNone(e.exception.__context__) def test_unconverteddata(self): # Check ValueError is raised when there is unconverted data @@ -485,12 +485,14 @@ def test_bad_timezone(self): # id_ID, ms_MY. # * Year is not included: ha_NG. # * Use non-Gregorian calendar: lo_LA, thai, th_TH. + # On Windows: ar_IN, ar_SA, fa_IR, ps_AF. # # BUG: Generates regexp that does not match the current date and time - # for az_IR, fa_IR, lzh_TW, my_MM, or_IN, shn_MM. + # for lzh_TW. @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', 'he_IL', 'eu_ES', 'ar_AE', 'mfe_MU', 'yo_NG', - 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN') + 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN', + 'my_MM', 'or_IN', 'shn_MM', 'az_IR') def test_date_time_locale(self): # Test %c directive loc = locale.getlocale(locale.LC_TIME)[0] @@ -512,20 +514,23 @@ def test_date_time_locale(self): self.roundtrip('%c', slice(0, 6), time.localtime(now - 366*24*3600)) # NB: Dates before 1969 do not roundtrip on some locales: - # bo_CN, bo_IN, dz_BT, eu_ES, eu_FR. + # az_IR, bo_CN, bo_IN, dz_BT, eu_ES, eu_FR, fa_IR, or_IN. @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', 'he_IL', 'ar_AE', 'mfe_MU', 'yo_NG', - 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN') + 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN', + 'my_MM', 'shn_MM') def test_date_time_locale2(self): # Test %c directive self.roundtrip('%c', slice(0, 6), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + self.roundtrip('%c', slice(0, 6), (1800, 1, 1, 0, 0, 0, 0, 1, 0)) # NB: Does not roundtrip because use non-Gregorian calendar: - # lo_LA, thai, th_TH. + # lo_LA, thai, th_TH. On Windows: ar_IN, ar_SA, fa_IR, ps_AF. # BUG: Generates regexp that does not match the current date - # for az_IR, fa_IR, lzh_TW, my_MM, or_IN, shn_MM. + # for lzh_TW. @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', - 'he_IL', 'eu_ES', 'ar_AE') + 'he_IL', 'eu_ES', 'ar_AE', + 'az_IR', 'my_MM', 'or_IN', 'shn_MM') def test_date_locale(self): # Test %x directive now = time.time() @@ -545,10 +550,11 @@ def test_date_locale(self): "musl libc issue on Emscripten, bpo-46390" ) @run_with_locales('LC_TIME', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', - 'eu_ES', 'ar_AE') + 'eu_ES', 'ar_AE', 'my_MM', 'shn_MM') def test_date_locale2(self): # Test %x directive self.roundtrip('%x', slice(0, 3), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + self.roundtrip('%x', slice(0, 3), (1800, 1, 1, 0, 0, 0, 0, 1, 0)) # NB: Does not roundtrip in some locales due to the ambiguity of # the time representation (bugs in locales?): @@ -556,11 +562,11 @@ def test_date_locale2(self): # norwegian, nynorsk. # * Hours are in 12-hour notation without AM/PM indication: hy_AM, # ms_MY, sm_WS. - # BUG: Generates regexp that does not match the current time for - # aa_DJ, aa_ER, aa_ET, am_ET, az_IR, byn_ER, fa_IR, gez_ER, gez_ET, - # lzh_TW, my_MM, om_ET, om_KE, or_IN, shn_MM, sid_ET, so_DJ, so_ET, - # so_SO, ti_ER, ti_ET, tig_ER, wal_ET. - @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP') + # BUG: Generates regexp that does not match the current time for lzh_TW. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'aa_ET', 'am_ET', 'az_IR', 'byn_ER', 'fa_IR', 'gez_ET', + 'my_MM', 'om_ET', 'or_IN', 'shn_MM', 'sid_ET', 'so_SO', + 'ti_ET', 'tig_ER', 'wal_ET') def test_time_locale(self): # Test %X directive now = time.time() diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 5b5779231f06ce..27c0f51acc58ab 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -298,7 +298,7 @@ def test_strptime_exception_context(self): # additional check for IndexError branch (issue #19545) with self.assertRaises(ValueError) as e: time.strptime('19', '%Y %') - self.assertIs(e.exception.__suppress_context__, True) + self.assertIsNone(e.exception.__context__) def test_strptime_leap_year(self): # GH-70647: warns if parsing a format with a day and no year. diff --git a/Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst b/Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst new file mode 100644 index 00000000000000..cdfa8c191e8242 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst @@ -0,0 +1,2 @@ +Fix :func:`time.strptime` for ``%c``, ``%x`` and ``%X`` formats in many +locales that use non-ASCII digits, like Persian, Burmese, Odia and Shan. From 6a08a753b702ac63c9b6ac58dd204d1fe9662e9d Mon Sep 17 00:00:00 2001 From: Wulian Date: Mon, 14 Oct 2024 21:53:50 +0800 Subject: [PATCH 161/247] gh-124960: Fixed `barry_as_FLUFL` future flag does not work in new REPL (#124999) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nice Zombies Co-authored-by: Łukasz Langa --- Lib/_pyrepl/console.py | 10 +++++-- Lib/codeop.py | 7 +++-- Lib/test/test_pyrepl/test_interact.py | 27 ++++++++++++++++++- ...-10-05-15-49-53.gh-issue-124960.Bol9hT.rst | 1 + 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst diff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py index 3e72a56807f6fb..03266c4dfc2dd8 100644 --- a/Lib/_pyrepl/console.py +++ b/Lib/_pyrepl/console.py @@ -174,7 +174,13 @@ def _excepthook(self, typ, value, tb): def runsource(self, source, filename="", symbol="single"): try: - tree = ast.parse(source) + tree = self.compile.compiler( + source, + filename, + "exec", + ast.PyCF_ONLY_AST, + incomplete_input=False, + ) except (SyntaxError, OverflowError, ValueError): self.showsyntaxerror(filename, source=source) return False @@ -185,7 +191,7 @@ def runsource(self, source, filename="", symbol="single"): the_symbol = symbol if stmt is last_stmt else "exec" item = wrapper([stmt]) try: - code = self.compile.compiler(item, filename, the_symbol, dont_inherit=True) + code = self.compile.compiler(item, filename, the_symbol) except SyntaxError as e: if e.args[0] == "'await' outside function": python = os.path.basename(sys.executable) diff --git a/Lib/codeop.py b/Lib/codeop.py index a0276b52d484e3..adf000ba29f88c 100644 --- a/Lib/codeop.py +++ b/Lib/codeop.py @@ -44,6 +44,7 @@ # Caveat emptor: These flags are undocumented on purpose and depending # on their effect outside the standard library is **unsupported**. PyCF_DONT_IMPLY_DEDENT = 0x200 +PyCF_ONLY_AST = 0x400 PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000 def _maybe_compile(compiler, source, filename, symbol): @@ -109,12 +110,14 @@ class Compile: def __init__(self): self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT - def __call__(self, source, filename, symbol, **kwargs): - flags = self.flags + def __call__(self, source, filename, symbol, flags=0, **kwargs): + flags |= self.flags if kwargs.get('incomplete_input', True) is False: flags &= ~PyCF_DONT_IMPLY_DEDENT flags &= ~PyCF_ALLOW_INCOMPLETE_INPUT codeob = compile(source, filename, symbol, flags, True) + if flags & PyCF_ONLY_AST: + return codeob # this is an ast.Module in this case for feature in _features: if codeob.co_flags & feature.compiler_flag: self.flags |= feature.compiler_flag diff --git a/Lib/test/test_pyrepl/test_interact.py b/Lib/test/test_pyrepl/test_interact.py index b7adaffbac0e22..0c6df4e5dae869 100644 --- a/Lib/test/test_pyrepl/test_interact.py +++ b/Lib/test/test_pyrepl/test_interact.py @@ -119,13 +119,38 @@ def test_runsource_shows_syntax_error_for_failed_compilation(self): def test_no_active_future(self): console = InteractiveColoredConsole() - source = "x: int = 1; print(__annotate__(1))" + source = dedent("""\ + x: int = 1 + print(__annotate__(1)) + """) f = io.StringIO() with contextlib.redirect_stdout(f): result = console.runsource(source) self.assertFalse(result) self.assertEqual(f.getvalue(), "{'x': }\n") + def test_future_annotations(self): + console = InteractiveColoredConsole() + source = dedent("""\ + from __future__ import annotations + def g(x: int): ... + print(g.__annotations__) + """) + f = io.StringIO() + with contextlib.redirect_stdout(f): + result = console.runsource(source) + self.assertFalse(result) + self.assertEqual(f.getvalue(), "{'x': 'int'}\n") + + def test_future_barry_as_flufl(self): + console = InteractiveColoredConsole() + f = io.StringIO() + with contextlib.redirect_stdout(f): + result = console.runsource("from __future__ import barry_as_FLUFL\n") + result = console.runsource("""print("black" <> 'blue')\n""") + self.assertFalse(result) + self.assertEqual(f.getvalue(), "True\n") + class TestMoreLines(unittest.TestCase): def test_invalid_syntax_single_line(self): diff --git a/Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst b/Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst new file mode 100644 index 00000000000000..332d6bb54d80c7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst @@ -0,0 +1 @@ +Fix support for the ``barry_as_FLUFL`` future flag in the new REPL. From c77121e9f19702b1ab280299394e38e8f15c0fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:23:05 +0200 Subject: [PATCH 162/247] gh-111178: fix USAN failures for `partialobject` (#124733) --- Modules/_functoolsmodule.c | 59 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 4ab3adc0fe44cc..802b1cf792c555 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -144,10 +144,13 @@ typedef struct { vectorcallfunc vectorcall; } partialobject; +// cast a PyObject pointer PTR to a partialobject pointer (no type checks) +#define _PyPartialObject_CAST(PTR) ((partialobject *)(PTR)) + static void partial_setvectorcall(partialobject *pto); static struct PyModuleDef _functools_module; static PyObject * -partial_call(partialobject *pto, PyObject *args, PyObject *kwargs); +partial_call(PyObject *pto, PyObject *args, PyObject *kwargs); static inline _functools_state * get_functools_state_by_type(PyTypeObject *type) @@ -307,8 +310,9 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) } static int -partial_clear(partialobject *pto) +partial_clear(PyObject *self) { + partialobject *pto = _PyPartialObject_CAST(self); Py_CLEAR(pto->fn); Py_CLEAR(pto->args); Py_CLEAR(pto->kw); @@ -317,8 +321,9 @@ partial_clear(partialobject *pto) } static int -partial_traverse(partialobject *pto, visitproc visit, void *arg) +partial_traverse(PyObject *self, visitproc visit, void *arg) { + partialobject *pto = _PyPartialObject_CAST(self); Py_VISIT(Py_TYPE(pto)); Py_VISIT(pto->fn); Py_VISIT(pto->args); @@ -328,16 +333,16 @@ partial_traverse(partialobject *pto, visitproc visit, void *arg) } static void -partial_dealloc(partialobject *pto) +partial_dealloc(PyObject *self) { - PyTypeObject *tp = Py_TYPE(pto); + PyTypeObject *tp = Py_TYPE(self); /* bpo-31095: UnTrack is needed before calling any callbacks */ - PyObject_GC_UnTrack(pto); - if (pto->weakreflist != NULL) { - PyObject_ClearWeakRefs((PyObject *) pto); + PyObject_GC_UnTrack(self); + if (_PyPartialObject_CAST(self)->weakreflist != NULL) { + PyObject_ClearWeakRefs(self); } - (void)partial_clear(pto); - tp->tp_free(pto); + (void)partial_clear(self); + tp->tp_free(self); Py_DECREF(tp); } @@ -360,14 +365,14 @@ partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto, { pto->vectorcall = NULL; Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); - return _PyObject_MakeTpCall(tstate, (PyObject *)pto, - args, nargs, kwnames); + return _PyObject_MakeTpCall(tstate, (PyObject *)pto, args, nargs, kwnames); } static PyObject * -partial_vectorcall(partialobject *pto, PyObject *const *args, +partial_vectorcall(PyObject *self, PyObject *const *args, size_t nargsf, PyObject *kwnames) { + partialobject *pto = _PyPartialObject_CAST(self);; PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); @@ -468,15 +473,16 @@ partial_setvectorcall(partialobject *pto) * but that is unlikely (why use partial without arguments?), * so we don't optimize that */ else { - pto->vectorcall = (vectorcallfunc)partial_vectorcall; + pto->vectorcall = partial_vectorcall; } } // Not converted to argument clinic, because of `*args, **kwargs` arguments. static PyObject * -partial_call(partialobject *pto, PyObject *args, PyObject *kwargs) +partial_call(PyObject *self, PyObject *args, PyObject *kwargs) { + partialobject *pto = _PyPartialObject_CAST(self); assert(PyCallable_Check(pto->fn)); assert(PyTuple_Check(pto->args)); assert(PyDict_Check(pto->kw)); @@ -587,8 +593,9 @@ static PyGetSetDef partial_getsetlist[] = { }; static PyObject * -partial_repr(partialobject *pto) +partial_repr(PyObject *self) { + partialobject *pto = _PyPartialObject_CAST(self); PyObject *result = NULL; PyObject *arglist; PyObject *mod; @@ -597,7 +604,7 @@ partial_repr(partialobject *pto) PyObject *key, *value; int status; - status = Py_ReprEnter((PyObject *)pto); + status = Py_ReprEnter(self); if (status != 0) { if (status < 0) return NULL; @@ -608,7 +615,7 @@ partial_repr(partialobject *pto) if (arglist == NULL) goto done; /* Pack positional arguments */ - assert (PyTuple_Check(pto->args)); + assert(PyTuple_Check(pto->args)); n = PyTuple_GET_SIZE(pto->args); for (i = 0; i < n; i++) { Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist, @@ -643,11 +650,11 @@ partial_repr(partialobject *pto) Py_DECREF(arglist); done: - Py_ReprLeave((PyObject *)pto); + Py_ReprLeave(self); return result; error: Py_DECREF(arglist); - Py_ReprLeave((PyObject *)pto); + Py_ReprLeave(self); return NULL; } @@ -659,16 +666,18 @@ partial_repr(partialobject *pto) */ static PyObject * -partial_reduce(partialobject *pto, PyObject *unused) +partial_reduce(PyObject *self, PyObject *Py_UNUSED(args)) { + partialobject *pto = _PyPartialObject_CAST(self); return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn, pto->args, pto->kw, pto->dict ? pto->dict : Py_None); } static PyObject * -partial_setstate(partialobject *pto, PyObject *state) +partial_setstate(PyObject *self, PyObject *state) { + partialobject *pto = _PyPartialObject_CAST(self); PyObject *fn, *fnargs, *kw, *dict; if (!PyTuple_Check(state)) { @@ -730,8 +739,8 @@ partial_setstate(partialobject *pto, PyObject *state) } static PyMethodDef partial_methods[] = { - {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS}, - {"__setstate__", (PyCFunction)partial_setstate, METH_O}, + {"__reduce__", partial_reduce, METH_NOARGS}, + {"__setstate__", partial_setstate, METH_O}, {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {NULL, NULL} /* sentinel */ @@ -749,7 +758,7 @@ static PyType_Slot partial_type_slots[] = { {Py_tp_methods, partial_methods}, {Py_tp_members, partial_memberlist}, {Py_tp_getset, partial_getsetlist}, - {Py_tp_descr_get, (descrgetfunc)partial_descr_get}, + {Py_tp_descr_get, partial_descr_get}, {Py_tp_new, partial_new}, {Py_tp_free, PyObject_GC_Del}, {0, 0} From 45df264f3ffbc0893cbfd257131d3abe21043786 Mon Sep 17 00:00:00 2001 From: Mikhail Efimov Date: Mon, 14 Oct 2024 17:53:08 +0300 Subject: [PATCH 163/247] gh-112088: aclocal version is updated to 1.16.5 in docs (#125457) --- Doc/using/configure.rst | 4 ++-- Doc/whatsnew/3.13.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 4976418ba33cf8..10cdf2376229ff 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -29,7 +29,7 @@ Features and minimum versions required to build CPython: * Tcl/Tk 8.5.12 for the :mod:`tkinter` module. -* Autoconf 2.71 and aclocal 1.16.4 are required to regenerate the +* Autoconf 2.71 and aclocal 1.16.5 are required to regenerate the :file:`configure` script. .. versionchanged:: 3.1 @@ -56,7 +56,7 @@ Features and minimum versions required to build CPython: Tcl/Tk version 8.5.12 is now required for the :mod:`tkinter` module. .. versionchanged:: 3.13 - Autoconf 2.71, aclocal 1.16.4 and SQLite 3.15.2 are now required. + Autoconf 2.71, aclocal 1.16.5 and SQLite 3.15.2 are now required. See also :pep:`7` "Style Guide for C Code" and :pep:`11` "CPython platform support". diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index a2897097aaba57..f9e74a9b8ff9c6 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -2495,9 +2495,9 @@ Build Changes * Building CPython now requires a compiler with support for the C11 atomic library, GCC built-in atomic functions, or MSVC interlocked intrinsics. -* Autoconf 2.71 and aclocal 1.16.4 are now required to regenerate +* Autoconf 2.71 and aclocal 1.16.5 are now required to regenerate the :file:`configure` script. - (Contributed by Christian Heimes in :gh:`89886`.) + (Contributed by Christian Heimes in :gh:`89886` and by Victor Stinner in :gh:`112090`.) * SQLite 3.15.2 or newer is required to build the :mod:`sqlite3` extension module. From d5dbbf4372cd3dbf3eead1cc70ddc4261c061fd9 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 14 Oct 2024 16:19:56 +0100 Subject: [PATCH 164/247] gh-124958: fix asyncio.TaskGroup and _PyFuture refcycles (#124959) --- Lib/asyncio/futures.py | 6 +- Lib/asyncio/taskgroups.py | 41 +++++++-- Lib/test/test_asyncio/test_futures.py | 22 +++++ Lib/test/test_asyncio/test_taskgroups.py | 92 ++++++++++++++++++- ...-10-04-08-46-00.gh-issue-124958.rea9-x.rst | 1 + 5 files changed, 147 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 5f6fa2348726cf..c95fce035cd548 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -190,8 +190,7 @@ def result(self): the future is done and has an exception set, this exception is raised. """ if self._state == _CANCELLED: - exc = self._make_cancelled_error() - raise exc + raise self._make_cancelled_error() if self._state != _FINISHED: raise exceptions.InvalidStateError('Result is not ready.') self.__log_traceback = False @@ -208,8 +207,7 @@ def exception(self): InvalidStateError. """ if self._state == _CANCELLED: - exc = self._make_cancelled_error() - raise exc + raise self._make_cancelled_error() if self._state != _FINISHED: raise exceptions.InvalidStateError('Exception is not set.') self.__log_traceback = False diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index f2ee9648c43876..9fa772ca9d02cc 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -66,6 +66,20 @@ async def __aenter__(self): return self async def __aexit__(self, et, exc, tb): + tb = None + try: + return await self._aexit(et, exc) + finally: + # Exceptions are heavy objects that can have object + # cycles (bad for GC); let's not keep a reference to + # a bunch of them. It would be nicer to use a try/finally + # in __aexit__ directly but that introduced some diff noise + self._parent_task = None + self._errors = None + self._base_error = None + exc = None + + async def _aexit(self, et, exc): self._exiting = True if (exc is not None and @@ -122,7 +136,10 @@ async def __aexit__(self, et, exc, tb): assert not self._tasks if self._base_error is not None: - raise self._base_error + try: + raise self._base_error + finally: + exc = None if self._parent_cancel_requested: # If this flag is set we *must* call uncancel(). @@ -133,8 +150,14 @@ async def __aexit__(self, et, exc, tb): # Propagate CancelledError if there is one, except if there # are other errors -- those have priority. - if propagate_cancellation_error is not None and not self._errors: - raise propagate_cancellation_error + try: + if propagate_cancellation_error is not None and not self._errors: + try: + raise propagate_cancellation_error + finally: + exc = None + finally: + propagate_cancellation_error = None if et is not None and not issubclass(et, exceptions.CancelledError): self._errors.append(exc) @@ -146,14 +169,14 @@ async def __aexit__(self, et, exc, tb): if self._parent_task.cancelling(): self._parent_task.uncancel() self._parent_task.cancel() - # Exceptions are heavy objects that can have object - # cycles (bad for GC); let's not keep a reference to - # a bunch of them. try: - me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors) - raise me from None + raise BaseExceptionGroup( + 'unhandled errors in a TaskGroup', + self._errors, + ) from None finally: - self._errors = None + exc = None + def create_task(self, coro, *, name=None, context=None): """Create a new task in this group and return it. diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 458b70451a306a..c566b28adb2408 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -659,6 +659,28 @@ def __del__(self): fut = self._new_future(loop=self.loop) fut.set_result(Evil()) + def test_future_cancelled_result_refcycles(self): + f = self._new_future(loop=self.loop) + f.cancel() + exc = None + try: + f.result() + except asyncio.CancelledError as e: + exc = e + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + + def test_future_cancelled_exception_refcycles(self): + f = self._new_future(loop=self.loop) + f.cancel() + exc = None + try: + f.exception() + except asyncio.CancelledError as e: + exc = e + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py index 4852536defc93d..138f59ebf57ef7 100644 --- a/Lib/test/test_asyncio/test_taskgroups.py +++ b/Lib/test/test_asyncio/test_taskgroups.py @@ -1,7 +1,7 @@ # Adapted with permission from the EdgeDB project; # license: PSFL. - +import gc import asyncio import contextvars import contextlib @@ -11,7 +11,6 @@ from test.test_asyncio.utils import await_without_task - # To prevent a warning "test altered the execution environment" def tearDownModule(): asyncio.set_event_loop_policy(None) @@ -899,6 +898,95 @@ async def outer(): await outer() + async def test_exception_refcycles_direct(self): + """Test that TaskGroup doesn't keep a reference to the raised ExceptionGroup""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + try: + async with tg: + raise _Done + except ExceptionGroup as e: + exc = e + + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + + + async def test_exception_refcycles_errors(self): + """Test that TaskGroup deletes self._errors, and __aexit__ args""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + try: + async with tg: + raise _Done + except* _Done as excs: + exc = excs.exceptions[0] + + self.assertIsInstance(exc, _Done) + self.assertListEqual(gc.get_referrers(exc), []) + + + async def test_exception_refcycles_parent_task(self): + """Test that TaskGroup deletes self._parent_task""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + async def coro_fn(): + async with tg: + raise _Done + + try: + async with asyncio.TaskGroup() as tg2: + tg2.create_task(coro_fn()) + except* _Done as excs: + exc = excs.exceptions[0].exceptions[0] + + self.assertIsInstance(exc, _Done) + self.assertListEqual(gc.get_referrers(exc), []) + + async def test_exception_refcycles_propagate_cancellation_error(self): + """Test that TaskGroup deletes propagate_cancellation_error""" + tg = asyncio.TaskGroup() + exc = None + + try: + async with asyncio.timeout(-1): + async with tg: + await asyncio.sleep(0) + except TimeoutError as e: + exc = e.__cause__ + + self.assertIsInstance(exc, asyncio.CancelledError) + self.assertListEqual(gc.get_referrers(exc), []) + + async def test_exception_refcycles_base_error(self): + """Test that TaskGroup deletes self._base_error""" + class MyKeyboardInterrupt(KeyboardInterrupt): + pass + + tg = asyncio.TaskGroup() + exc = None + + try: + async with tg: + raise MyKeyboardInterrupt + except MyKeyboardInterrupt as e: + exc = e + + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst b/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst new file mode 100644 index 00000000000000..534d5bb8c898da --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst @@ -0,0 +1 @@ +Fix refcycles in exceptions raised from :class:`asyncio.TaskGroup` and the python implementation of :class:`asyncio.Future` From 5dac0dceda9097d46a0b5a6ad7c927e002c6c7a5 Mon Sep 17 00:00:00 2001 From: Paul Hoffman Date: Mon, 14 Oct 2024 08:26:57 -0700 Subject: [PATCH 165/247] gh-125461: Remove Python 2 from identifiers in doc (GH-125462) Remove Python 2 from identifiers in doc --- Doc/reference/lexical_analysis.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index ae5408ee386bbd..f7167032ad7df9 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -284,11 +284,10 @@ UAX-31, with elaboration and changes as defined below; see also :pep:`3131` for further details. Within the ASCII range (U+0001..U+007F), the valid characters for identifiers -are the same as in Python 2.x: the uppercase and lowercase letters ``A`` through +include the uppercase and lowercase letters ``A`` through ``Z``, the underscore ``_`` and, except for the first character, the digits ``0`` through ``9``. - -Python 3.0 introduces additional characters from outside the ASCII range (see +Python 3.0 introduced additional characters from outside the ASCII range (see :pep:`3131`). For these characters, the classification uses the version of the Unicode Character Database as included in the :mod:`unicodedata` module. From 187580d95c8339a3b6e2b012f98d86101c346cfa Mon Sep 17 00:00:00 2001 From: Mikhail Efimov Date: Mon, 14 Oct 2024 20:24:54 +0300 Subject: [PATCH 166/247] gh-119786: [doc] broken link and typo fix in interpreter_definition.md (#125455) --- InternalDocs/README.md | 2 ++ Tools/cases_generator/interpreter_definition.md | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/InternalDocs/README.md b/InternalDocs/README.md index 805e2f97937e1e..0a6ecf899458ed 100644 --- a/InternalDocs/README.md +++ b/InternalDocs/README.md @@ -11,6 +11,8 @@ The core dev team attempts to keep this documentation up to date. If it is not, please report that through the [issue tracker](https://github.com/python/cpython/issues). +Index: +----- [Guide to the parser](parser.md) diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index ba09931c541646..6cf36f343d5fa7 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -74,7 +74,7 @@ We update it as the need arises. ### Syntax Each op definition has a kind, a name, a stack and instruction stream effect, -and a piece of C code describing its semantics:: +and a piece of C code describing its semantics: ``` file: @@ -245,7 +245,8 @@ The same is true for all members of a pseudo instruction ## Examples -(Another source of examples can be found in the [tests](test_generator.py).) +(Another source of examples can be found in the +[tests](https://github.com/python/cpython/blob/main/Lib/test/test_generated_cases.py).) Some examples: From e99650b80ace3893c2a80b3f2a4aca99cb305191 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Mon, 14 Oct 2024 20:59:13 +0300 Subject: [PATCH 167/247] =?UTF-8?q?gh-125472:=20Revert=20"gh-124958:=20fix?= =?UTF-8?q?=20asyncio.TaskGroup=20and=20=5FPyFuture=20refcycles=20(#12?= =?UTF-8?q?=E2=80=A6=20(#125476)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "gh-124958: fix asyncio.TaskGroup and _PyFuture refcycles (#124959)" This reverts commit d5dbbf4372cd3dbf3eead1cc70ddc4261c061fd9. --- Lib/asyncio/futures.py | 6 +- Lib/asyncio/taskgroups.py | 41 ++------- Lib/test/test_asyncio/test_futures.py | 22 ----- Lib/test/test_asyncio/test_taskgroups.py | 92 +------------------ ...-10-04-08-46-00.gh-issue-124958.rea9-x.rst | 1 - 5 files changed, 15 insertions(+), 147 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index c95fce035cd548..5f6fa2348726cf 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -190,7 +190,8 @@ def result(self): the future is done and has an exception set, this exception is raised. """ if self._state == _CANCELLED: - raise self._make_cancelled_error() + exc = self._make_cancelled_error() + raise exc if self._state != _FINISHED: raise exceptions.InvalidStateError('Result is not ready.') self.__log_traceback = False @@ -207,7 +208,8 @@ def exception(self): InvalidStateError. """ if self._state == _CANCELLED: - raise self._make_cancelled_error() + exc = self._make_cancelled_error() + raise exc if self._state != _FINISHED: raise exceptions.InvalidStateError('Exception is not set.') self.__log_traceback = False diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 9fa772ca9d02cc..f2ee9648c43876 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -66,20 +66,6 @@ async def __aenter__(self): return self async def __aexit__(self, et, exc, tb): - tb = None - try: - return await self._aexit(et, exc) - finally: - # Exceptions are heavy objects that can have object - # cycles (bad for GC); let's not keep a reference to - # a bunch of them. It would be nicer to use a try/finally - # in __aexit__ directly but that introduced some diff noise - self._parent_task = None - self._errors = None - self._base_error = None - exc = None - - async def _aexit(self, et, exc): self._exiting = True if (exc is not None and @@ -136,10 +122,7 @@ async def _aexit(self, et, exc): assert not self._tasks if self._base_error is not None: - try: - raise self._base_error - finally: - exc = None + raise self._base_error if self._parent_cancel_requested: # If this flag is set we *must* call uncancel(). @@ -150,14 +133,8 @@ async def _aexit(self, et, exc): # Propagate CancelledError if there is one, except if there # are other errors -- those have priority. - try: - if propagate_cancellation_error is not None and not self._errors: - try: - raise propagate_cancellation_error - finally: - exc = None - finally: - propagate_cancellation_error = None + if propagate_cancellation_error is not None and not self._errors: + raise propagate_cancellation_error if et is not None and not issubclass(et, exceptions.CancelledError): self._errors.append(exc) @@ -169,14 +146,14 @@ async def _aexit(self, et, exc): if self._parent_task.cancelling(): self._parent_task.uncancel() self._parent_task.cancel() + # Exceptions are heavy objects that can have object + # cycles (bad for GC); let's not keep a reference to + # a bunch of them. try: - raise BaseExceptionGroup( - 'unhandled errors in a TaskGroup', - self._errors, - ) from None + me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors) + raise me from None finally: - exc = None - + self._errors = None def create_task(self, coro, *, name=None, context=None): """Create a new task in this group and return it. diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index c566b28adb2408..458b70451a306a 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -659,28 +659,6 @@ def __del__(self): fut = self._new_future(loop=self.loop) fut.set_result(Evil()) - def test_future_cancelled_result_refcycles(self): - f = self._new_future(loop=self.loop) - f.cancel() - exc = None - try: - f.result() - except asyncio.CancelledError as e: - exc = e - self.assertIsNotNone(exc) - self.assertListEqual(gc.get_referrers(exc), []) - - def test_future_cancelled_exception_refcycles(self): - f = self._new_future(loop=self.loop) - f.cancel() - exc = None - try: - f.exception() - except asyncio.CancelledError as e: - exc = e - self.assertIsNotNone(exc) - self.assertListEqual(gc.get_referrers(exc), []) - @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py index 138f59ebf57ef7..4852536defc93d 100644 --- a/Lib/test/test_asyncio/test_taskgroups.py +++ b/Lib/test/test_asyncio/test_taskgroups.py @@ -1,7 +1,7 @@ # Adapted with permission from the EdgeDB project; # license: PSFL. -import gc + import asyncio import contextvars import contextlib @@ -11,6 +11,7 @@ from test.test_asyncio.utils import await_without_task + # To prevent a warning "test altered the execution environment" def tearDownModule(): asyncio.set_event_loop_policy(None) @@ -898,95 +899,6 @@ async def outer(): await outer() - async def test_exception_refcycles_direct(self): - """Test that TaskGroup doesn't keep a reference to the raised ExceptionGroup""" - tg = asyncio.TaskGroup() - exc = None - - class _Done(Exception): - pass - - try: - async with tg: - raise _Done - except ExceptionGroup as e: - exc = e - - self.assertIsNotNone(exc) - self.assertListEqual(gc.get_referrers(exc), []) - - - async def test_exception_refcycles_errors(self): - """Test that TaskGroup deletes self._errors, and __aexit__ args""" - tg = asyncio.TaskGroup() - exc = None - - class _Done(Exception): - pass - - try: - async with tg: - raise _Done - except* _Done as excs: - exc = excs.exceptions[0] - - self.assertIsInstance(exc, _Done) - self.assertListEqual(gc.get_referrers(exc), []) - - - async def test_exception_refcycles_parent_task(self): - """Test that TaskGroup deletes self._parent_task""" - tg = asyncio.TaskGroup() - exc = None - - class _Done(Exception): - pass - - async def coro_fn(): - async with tg: - raise _Done - - try: - async with asyncio.TaskGroup() as tg2: - tg2.create_task(coro_fn()) - except* _Done as excs: - exc = excs.exceptions[0].exceptions[0] - - self.assertIsInstance(exc, _Done) - self.assertListEqual(gc.get_referrers(exc), []) - - async def test_exception_refcycles_propagate_cancellation_error(self): - """Test that TaskGroup deletes propagate_cancellation_error""" - tg = asyncio.TaskGroup() - exc = None - - try: - async with asyncio.timeout(-1): - async with tg: - await asyncio.sleep(0) - except TimeoutError as e: - exc = e.__cause__ - - self.assertIsInstance(exc, asyncio.CancelledError) - self.assertListEqual(gc.get_referrers(exc), []) - - async def test_exception_refcycles_base_error(self): - """Test that TaskGroup deletes self._base_error""" - class MyKeyboardInterrupt(KeyboardInterrupt): - pass - - tg = asyncio.TaskGroup() - exc = None - - try: - async with tg: - raise MyKeyboardInterrupt - except MyKeyboardInterrupt as e: - exc = e - - self.assertIsNotNone(exc) - self.assertListEqual(gc.get_referrers(exc), []) - if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst b/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst deleted file mode 100644 index 534d5bb8c898da..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst +++ /dev/null @@ -1 +0,0 @@ -Fix refcycles in exceptions raised from :class:`asyncio.TaskGroup` and the python implementation of :class:`asyncio.Future` From 843d28f59d2616d052d9d45f31823976da07f0f3 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 14 Oct 2024 15:28:41 -0400 Subject: [PATCH 168/247] gh-124872: Replace enter/exit events with "switched" (#124776) Users want to know when the current context switches to a different context object. Right now this happens when and only when a context is entered or exited, so the enter and exit events are synonymous with "switched". However, if the changes proposed for gh-99633 are implemented, the current context will also switch for reasons other than context enter or exit. Since users actually care about context switches and not enter or exit, replace the enter and exit events with a single switched event. The former exit event was emitted just before exiting the context. The new switched event is emitted after the context is exited to match the semantics users expect of an event with a past-tense name. If users need the ability to clean up before the switch takes effect, another event type can be added in the future. It is not added here because YAGNI. I skipped 0 in the enum as a matter of practice. Skipping 0 makes it easier to troubleshoot when code forgets to set zeroed memory, and it aligns with best practices for other tools (e.g., https://protobuf.dev/programming-guides/dos-donts/#unspecified-enum). --- Doc/c-api/contextvars.rst | 14 ++--- Include/cpython/context.h | 17 ++---- Lib/test/test_capi/test_watchers.py | 89 ++++++++++++++-------------- Modules/_testcapi/watchers.c | 79 ++++++++++++------------ Python/context.c | 31 ++++++---- Tools/c-analyzer/cpython/ignored.tsv | 4 +- 6 files changed, 117 insertions(+), 117 deletions(-) diff --git a/Doc/c-api/contextvars.rst b/Doc/c-api/contextvars.rst index 8eba54a80dc80d..b7c6550ff34aac 100644 --- a/Doc/c-api/contextvars.rst +++ b/Doc/c-api/contextvars.rst @@ -123,16 +123,10 @@ Context object management functions: Enumeration of possible context object watcher events: - - ``Py_CONTEXT_EVENT_ENTER``: A context has been entered, causing the - :term:`current context` to switch to it. The object passed to the watch - callback is the now-current :class:`contextvars.Context` object. Each - enter event will eventually have a corresponding exit event for the same - context object after any subsequently entered contexts have themselves been - exited. - - ``Py_CONTEXT_EVENT_EXIT``: A context is about to be exited, which will - cause the :term:`current context` to switch back to what it was before the - context was entered. The object passed to the watch callback is the - still-current :class:`contextvars.Context` object. + - ``Py_CONTEXT_SWITCHED``: The :term:`current context` has switched to a + different context. The object passed to the watch callback is the + now-current :class:`contextvars.Context` object, or None if no context is + current. .. versionadded:: 3.14 diff --git a/Include/cpython/context.h b/Include/cpython/context.h index 3c9be7873b9399..3a7a4b459c09ad 100644 --- a/Include/cpython/context.h +++ b/Include/cpython/context.h @@ -29,20 +29,11 @@ PyAPI_FUNC(int) PyContext_Exit(PyObject *); typedef enum { /* - * A context has been entered, causing the "current context" to switch to - * it. The object passed to the watch callback is the now-current - * contextvars.Context object. Each enter event will eventually have a - * corresponding exit event for the same context object after any - * subsequently entered contexts have themselves been exited. + * The current context has switched to a different context. The object + * passed to the watch callback is the now-current contextvars.Context + * object, or None if no context is current. */ - Py_CONTEXT_EVENT_ENTER, - /* - * A context is about to be exited, which will cause the "current context" - * to switch back to what it was before the context was entered. The - * object passed to the watch callback is the still-current - * contextvars.Context object. - */ - Py_CONTEXT_EVENT_EXIT, + Py_CONTEXT_SWITCHED = 1, } PyContextEvent; /* diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py index f21d2627c6094b..4680d6765de122 100644 --- a/Lib/test/test_capi/test_watchers.py +++ b/Lib/test/test_capi/test_watchers.py @@ -577,68 +577,62 @@ class TestContextObjectWatchers(unittest.TestCase): def context_watcher(self, which_watcher): wid = _testcapi.add_context_watcher(which_watcher) try: - yield wid + switches = _testcapi.get_context_switches(which_watcher) + except ValueError: + switches = None + try: + yield switches finally: _testcapi.clear_context_watcher(wid) - def assert_event_counts(self, exp_enter_0, exp_exit_0, - exp_enter_1, exp_exit_1): - self.assertEqual( - exp_enter_0, _testcapi.get_context_watcher_num_enter_events(0)) - self.assertEqual( - exp_exit_0, _testcapi.get_context_watcher_num_exit_events(0)) - self.assertEqual( - exp_enter_1, _testcapi.get_context_watcher_num_enter_events(1)) - self.assertEqual( - exp_exit_1, _testcapi.get_context_watcher_num_exit_events(1)) + def assert_event_counts(self, want_0, want_1): + self.assertEqual(len(_testcapi.get_context_switches(0)), want_0) + self.assertEqual(len(_testcapi.get_context_switches(1)), want_1) def test_context_object_events_dispatched(self): # verify that all counts are zero before any watchers are registered - self.assert_event_counts(0, 0, 0, 0) + self.assert_event_counts(0, 0) # verify that all counts remain zero when a context object is # entered and exited with no watchers registered ctx = contextvars.copy_context() - ctx.run(self.assert_event_counts, 0, 0, 0, 0) - self.assert_event_counts(0, 0, 0, 0) + ctx.run(self.assert_event_counts, 0, 0) + self.assert_event_counts(0, 0) # verify counts are as expected when first watcher is registered with self.context_watcher(0): - self.assert_event_counts(0, 0, 0, 0) - ctx.run(self.assert_event_counts, 1, 0, 0, 0) - self.assert_event_counts(1, 1, 0, 0) + self.assert_event_counts(0, 0) + ctx.run(self.assert_event_counts, 1, 0) + self.assert_event_counts(2, 0) # again with second watcher registered with self.context_watcher(1): - self.assert_event_counts(1, 1, 0, 0) - ctx.run(self.assert_event_counts, 2, 1, 1, 0) - self.assert_event_counts(2, 2, 1, 1) + self.assert_event_counts(2, 0) + ctx.run(self.assert_event_counts, 3, 1) + self.assert_event_counts(4, 2) # verify counts are reset and don't change after both watchers are cleared - ctx.run(self.assert_event_counts, 0, 0, 0, 0) - self.assert_event_counts(0, 0, 0, 0) - - def test_enter_error(self): - with self.context_watcher(2): - with catch_unraisable_exception() as cm: - ctx = contextvars.copy_context() - ctx.run(int, 0) - self.assertEqual( - cm.unraisable.err_msg, - "Exception ignored in " - f"Py_CONTEXT_EVENT_EXIT watcher callback for {ctx!r}" - ) - self.assertEqual(str(cm.unraisable.exc_value), "boom!") - - def test_exit_error(self): - ctx = contextvars.copy_context() - def _in_context(stack): - stack.enter_context(self.context_watcher(2)) - - with catch_unraisable_exception() as cm: - with ExitStack() as stack: - ctx.run(_in_context, stack) - self.assertEqual(str(cm.unraisable.exc_value), "boom!") + ctx.run(self.assert_event_counts, 0, 0) + self.assert_event_counts(0, 0) + + def test_callback_error(self): + ctx_outer = contextvars.copy_context() + ctx_inner = contextvars.copy_context() + unraisables = [] + + def _in_outer(): + with self.context_watcher(2): + with catch_unraisable_exception() as cm: + ctx_inner.run(lambda: unraisables.append(cm.unraisable)) + unraisables.append(cm.unraisable) + + ctx_outer.run(_in_outer) + self.assertEqual([x.err_msg for x in unraisables], + ["Exception ignored in Py_CONTEXT_SWITCHED " + f"watcher callback for {ctx!r}" + for ctx in [ctx_inner, ctx_outer]]) + self.assertEqual([str(x.exc_value) for x in unraisables], + ["boom!", "boom!"]) def test_clear_out_of_range_watcher_id(self): with self.assertRaisesRegex(ValueError, r"Invalid context watcher ID -1"): @@ -654,5 +648,12 @@ def test_allocate_too_many_watchers(self): with self.assertRaisesRegex(RuntimeError, r"no more context watcher IDs available"): _testcapi.allocate_too_many_context_watchers() + def test_exit_base_context(self): + ctx = contextvars.Context() + _testcapi.clear_context_stack() + with self.context_watcher(0) as switches: + ctx.run(lambda: None) + self.assertEqual(switches, [ctx, None]) + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index b4233d07134aea..321d3aeffb6ad1 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -626,16 +626,12 @@ allocate_too_many_func_watchers(PyObject *self, PyObject *args) // Test contexct object watchers #define NUM_CONTEXT_WATCHERS 2 static int context_watcher_ids[NUM_CONTEXT_WATCHERS] = {-1, -1}; -static int num_context_object_enter_events[NUM_CONTEXT_WATCHERS] = {0, 0}; -static int num_context_object_exit_events[NUM_CONTEXT_WATCHERS] = {0, 0}; +static PyObject *context_switches[NUM_CONTEXT_WATCHERS]; static int handle_context_watcher_event(int which_watcher, PyContextEvent event, PyObject *ctx) { - if (event == Py_CONTEXT_EVENT_ENTER) { - num_context_object_enter_events[which_watcher]++; - } - else if (event == Py_CONTEXT_EVENT_EXIT) { - num_context_object_exit_events[which_watcher]++; + if (event == Py_CONTEXT_SWITCHED) { + PyList_Append(context_switches[which_watcher], ctx); } else { return -1; @@ -667,31 +663,28 @@ error_context_event_handler(PyContextEvent event, PyObject *ctx) { static PyObject * add_context_watcher(PyObject *self, PyObject *which_watcher) { - int watcher_id; + static const PyContext_WatchCallback callbacks[] = { + &first_context_watcher_callback, + &second_context_watcher_callback, + &error_context_event_handler, + }; assert(PyLong_Check(which_watcher)); long which_l = PyLong_AsLong(which_watcher); - if (which_l == 0) { - watcher_id = PyContext_AddWatcher(first_context_watcher_callback); - context_watcher_ids[0] = watcher_id; - num_context_object_enter_events[0] = 0; - num_context_object_exit_events[0] = 0; - } - else if (which_l == 1) { - watcher_id = PyContext_AddWatcher(second_context_watcher_callback); - context_watcher_ids[1] = watcher_id; - num_context_object_enter_events[1] = 0; - num_context_object_exit_events[1] = 0; - } - else if (which_l == 2) { - watcher_id = PyContext_AddWatcher(error_context_event_handler); - } - else { + if (which_l < 0 || which_l >= (long)Py_ARRAY_LENGTH(callbacks)) { PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l); return NULL; } + int watcher_id = PyContext_AddWatcher(callbacks[which_l]); if (watcher_id < 0) { return NULL; } + if (which_l >= 0 && which_l < NUM_CONTEXT_WATCHERS) { + context_watcher_ids[which_l] = watcher_id; + Py_XSETREF(context_switches[which_l], PyList_New(0)); + if (context_switches[which_l] == NULL) { + return NULL; + } + } return PyLong_FromLong(watcher_id); } @@ -708,8 +701,7 @@ clear_context_watcher(PyObject *self, PyObject *watcher_id) for (int i = 0; i < NUM_CONTEXT_WATCHERS; i++) { if (watcher_id_l == context_watcher_ids[i]) { context_watcher_ids[i] = -1; - num_context_object_enter_events[i] = 0; - num_context_object_exit_events[i] = 0; + Py_CLEAR(context_switches[i]); } } } @@ -717,21 +709,34 @@ clear_context_watcher(PyObject *self, PyObject *watcher_id) } static PyObject * -get_context_watcher_num_enter_events(PyObject *self, PyObject *watcher_id) +clear_context_stack(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { - assert(PyLong_Check(watcher_id)); - long watcher_id_l = PyLong_AsLong(watcher_id); - assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); - return PyLong_FromLong(num_context_object_enter_events[watcher_id_l]); + PyThreadState *tstate = PyThreadState_Get(); + if (tstate->context == NULL) { + Py_RETURN_NONE; + } + if (((PyContext *)tstate->context)->ctx_prev != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "must first exit all non-base contexts"); + return NULL; + } + Py_CLEAR(tstate->context); + Py_RETURN_NONE; } static PyObject * -get_context_watcher_num_exit_events(PyObject *self, PyObject *watcher_id) +get_context_switches(PyObject *Py_UNUSED(self), PyObject *watcher_id) { assert(PyLong_Check(watcher_id)); long watcher_id_l = PyLong_AsLong(watcher_id); - assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); - return PyLong_FromLong(num_context_object_exit_events[watcher_id_l]); + if (watcher_id_l < 0 || watcher_id_l >= NUM_CONTEXT_WATCHERS) { + PyErr_Format(PyExc_ValueError, "invalid watcher %ld", watcher_id_l); + return NULL; + } + if (context_switches[watcher_id_l] == NULL) { + return PyList_New(0); + } + return Py_NewRef(context_switches[watcher_id_l]); } static PyObject * @@ -835,10 +840,8 @@ static PyMethodDef test_methods[] = { // Code object watchers. {"add_context_watcher", add_context_watcher, METH_O, NULL}, {"clear_context_watcher", clear_context_watcher, METH_O, NULL}, - {"get_context_watcher_num_enter_events", - get_context_watcher_num_enter_events, METH_O, NULL}, - {"get_context_watcher_num_exit_events", - get_context_watcher_num_exit_events, METH_O, NULL}, + {"clear_context_stack", clear_context_stack, METH_NOARGS, NULL}, + {"get_context_switches", get_context_switches, METH_O, NULL}, {"allocate_too_many_context_watchers", (PyCFunction) allocate_too_many_context_watchers, METH_NOARGS, NULL}, {NULL}, diff --git a/Python/context.c b/Python/context.c index 8bc487a33c890b..95aa82206270f9 100644 --- a/Python/context.c +++ b/Python/context.c @@ -102,10 +102,8 @@ PyContext_CopyCurrent(void) static const char * context_event_name(PyContextEvent event) { switch (event) { - case Py_CONTEXT_EVENT_ENTER: - return "Py_CONTEXT_EVENT_ENTER"; - case Py_CONTEXT_EVENT_EXIT: - return "Py_CONTEXT_EVENT_EXIT"; + case Py_CONTEXT_SWITCHED: + return "Py_CONTEXT_SWITCHED"; default: return "?"; } @@ -115,6 +113,13 @@ context_event_name(PyContextEvent event) { static void notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyObject *ctx) { + if (ctx == NULL) { + // This will happen after exiting the last context in the stack, which + // can occur if context_get was never called before entering a context + // (e.g., called `contextvars.Context().run()` on a fresh thread, as + // PyContext_Enter doesn't call context_get). + ctx = Py_None; + } assert(Py_REFCNT(ctx) > 0); PyInterpreterState *interp = ts->interp; assert(interp->_initialized); @@ -175,6 +180,16 @@ PyContext_ClearWatcher(int watcher_id) } +static inline void +context_switched(PyThreadState *ts) +{ + ts->context_ver++; + // ts->context is used instead of context_get() because context_get() might + // throw if ts->context is NULL. + notify_context_watchers(ts, Py_CONTEXT_SWITCHED, ts->context); +} + + static int _PyContext_Enter(PyThreadState *ts, PyObject *octx) { @@ -191,9 +206,7 @@ _PyContext_Enter(PyThreadState *ts, PyObject *octx) ctx->ctx_entered = 1; ts->context = Py_NewRef(ctx); - ts->context_ver++; - - notify_context_watchers(ts, Py_CONTEXT_EVENT_ENTER, octx); + context_switched(ts); return 0; } @@ -227,13 +240,11 @@ _PyContext_Exit(PyThreadState *ts, PyObject *octx) return -1; } - notify_context_watchers(ts, Py_CONTEXT_EVENT_EXIT, octx); Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev); - ts->context_ver++; ctx->ctx_prev = NULL; ctx->ctx_entered = 0; - + context_switched(ts); return 0; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index e6c599a2ac4a46..2605825d3d0078 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -455,8 +455,8 @@ Modules/_testcapi/watchers.c - pyfunc_watchers - Modules/_testcapi/watchers.c - func_watcher_ids - Modules/_testcapi/watchers.c - func_watcher_callbacks - Modules/_testcapi/watchers.c - context_watcher_ids - -Modules/_testcapi/watchers.c - num_context_object_enter_events - -Modules/_testcapi/watchers.c - num_context_object_exit_events - +Modules/_testcapi/watchers.c - context_switches - +Modules/_testcapi/watchers.c add_context_watcher callbacks - Modules/_testcapimodule.c - BasicStaticTypes - Modules/_testcapimodule.c - num_basic_static_types_used - Modules/_testcapimodule.c - ContainerNoGC_members - From 0c8c665581ede95fe119f902b070e395614b78ed Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 14 Oct 2024 23:46:17 +0300 Subject: [PATCH 169/247] gh-125470: Fix warning in `Python/generated_cases.c.h` (#125471) Co-authored-by: Kirill Podoprigora --- Python/bytecodes.c | 2 ++ Python/executor_cases.c.h | 2 ++ Python/generated_cases.c.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b22916aeaa248b..e6525657cabc2b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -611,7 +611,9 @@ dummy_func( // specializations, but there is no output. // At the end we just skip over the STORE_FAST. op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { + #ifndef NDEBUG PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + #endif PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); int next_oparg; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 0ed361a2ee7fb0..15a6c7bc1a7966 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -737,7 +737,9 @@ _PyStackRef left; right = stack_pointer[-1]; left = stack_pointer[-2]; + #ifndef NDEBUG PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + #endif PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); int next_oparg; #if TIER_ONE diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7bd1b7dd5aba27..a9290986c24f45 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -183,7 +183,9 @@ /* Skip 1 cache entry */ // _BINARY_OP_INPLACE_ADD_UNICODE { + #ifndef NDEBUG PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + #endif PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); int next_oparg; #if TIER_ONE From 3fea1d000ef0a74062fd3fe218ad94618b08d9f2 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 14 Oct 2024 17:11:58 -0400 Subject: [PATCH 170/247] Fix idlelib typos (#125484) Propagate fixes in Doc/library/idle.rst to help.html. Change 'interruptable' to 'interruptible' in run.py. The latter was reported by ember91 in PR 125473. --- Lib/idlelib/help.html | 21 ++++++++++++--------- Lib/idlelib/run.py | 12 ++++++------ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index 827d230b54e159..2a4adc6a4d395f 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -5,7 +5,7 @@ - IDLE — Python 3.13.0a2 documentation + IDLE — Python 3.14.0a0 documentation @@ -18,7 +18,7 @@ @@ -26,6 +26,7 @@ + @@ -45,6 +46,8 @@ + + @@ -184,7 +187,7 @@

Navigation

  • - 3.13.0a2 Documentation » + 3.14.0a0 Documentation »
  • @@ -554,7 +557,7 @@

    Key bindingsControl key on Windows and -Unix and the Command key on macOS. (And all such dicussions +Unix and the Command key on macOS. (And all such discussions assume that the keys have not been re-bound to something else.)

    @@ -694,7 +697,7 @@

    Shell window -
  • C-c attemps to interrupt statement execution (but may fail).

  • +
  • C-c attempts to interrupt statement execution (but may fail).

  • C-d closes Shell if typed at a >>> prompt.

  • Alt-p and Alt-n (C-p and C-n on macOS) retrieve to the current prompt the previous or next previously @@ -1136,7 +1139,7 @@

    Navigation

  • - 3.13.0a2 Documentation » + 3.14.0a0 Documentation »
  • @@ -1180,7 +1183,7 @@

    Navigation



    - Last updated on Jan 17, 2024 (06:57 UTC). + Last updated on Oct 14, 2024 (20:27 UTC). Found a bug?
    diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 8f98e73258e778..a30db99a619a93 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -108,11 +108,11 @@ def handle_tk_events(tcl=tcl): # Thread shared globals: Establish a queue between a subthread (which handles # the socket) and the main thread (which runs user code), plus global -# completion, exit and interruptable (the main thread) flags: +# completion, exit and interruptible (the main thread) flags: exit_now = False quitting = False -interruptable = False +interruptible = False def main(del_exitfunc=False): """Start the Python execution server in a subprocess @@ -582,14 +582,14 @@ def __init__(self, rpchandler): self.locals = {} def runcode(self, code): - global interruptable + global interruptible try: self.user_exc_info = None - interruptable = True + interruptible = True try: exec(code, self.locals) finally: - interruptable = False + interruptible = False except SystemExit as e: if e.args: # SystemExit called with an argument. ob = e.args[0] @@ -615,7 +615,7 @@ def runcode(self, code): flush_stdout() def interrupt_the_server(self): - if interruptable: + if interruptible: thread.interrupt_main() def start_the_debugger(self, gui_adap_oid): From 2a5cdb251674ce8d9a824c102f7cd846d944cfa4 Mon Sep 17 00:00:00 2001 From: edson duarte Date: Mon, 14 Oct 2024 19:02:58 -0300 Subject: [PATCH 171/247] gh-85453: Improve variable mark up for datetime.rst (#120702) Variables and literals are marked up using backticks. --- Doc/library/datetime.rst | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index f0b465bc9ce39c..2f81080d525f86 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -180,19 +180,19 @@ Objects of the :class:`date` type are always naive. An object of type :class:`.time` or :class:`.datetime` may be aware or naive. -A :class:`.datetime` object *d* is aware if both of the following hold: +A :class:`.datetime` object ``d`` is aware if both of the following hold: 1. ``d.tzinfo`` is not ``None`` 2. ``d.tzinfo.utcoffset(d)`` does not return ``None`` -Otherwise, *d* is naive. +Otherwise, ``d`` is naive. -A :class:`.time` object *t* is aware if both of the following hold: +A :class:`.time` object ``t`` is aware if both of the following hold: 1. ``t.tzinfo`` is not ``None`` 2. ``t.tzinfo.utcoffset(None)`` does not return ``None``. -Otherwise, *t* is naive. +Otherwise, ``t`` is naive. The distinction between aware and naive doesn't apply to :class:`timedelta` objects. @@ -358,8 +358,8 @@ Supported operations: +--------------------------------+-----------------------------------------------+ | ``q, r = divmod(t1, t2)`` | Computes the quotient and the remainder: | | | ``q = t1 // t2`` (3) and ``r = t1 % t2``. | -| | q is an integer and r is a :class:`timedelta` | -| | object. | +| | ``q`` is an integer and ``r`` is a | +| | :class:`timedelta` object. | +--------------------------------+-----------------------------------------------+ | ``+t1`` | Returns a :class:`timedelta` object with the | | | same value. (2) | @@ -526,7 +526,7 @@ Other constructors, all class methods: January 1 of year 1 has ordinal 1. :exc:`ValueError` is raised unless ``1 <= ordinal <= - date.max.toordinal()``. For any date *d*, + date.max.toordinal()``. For any date ``d``, ``date.fromordinal(d.toordinal()) == d``. @@ -730,7 +730,7 @@ Instance methods: .. method:: date.toordinal() Return the proleptic Gregorian ordinal of the date, where January 1 of year 1 - has ordinal 1. For any :class:`date` object *d*, + has ordinal 1. For any :class:`date` object ``d``, ``date.fromordinal(d.toordinal()) == d``. @@ -782,7 +782,7 @@ Instance methods: .. method:: date.__str__() - For a date *d*, ``str(d)`` is equivalent to ``d.isoformat()``. + For a date ``d``, ``str(d)`` is equivalent to ``d.isoformat()``. .. method:: date.ctime() @@ -1063,7 +1063,7 @@ Other constructors, all class methods: is used. If the *date* argument is a :class:`.datetime` object, its time components and :attr:`.tzinfo` attributes are ignored. - For any :class:`.datetime` object *d*, + For any :class:`.datetime` object ``d``, ``d == datetime.combine(d.date(), d.time(), d.tzinfo)``. .. versionchanged:: 3.6 @@ -1270,11 +1270,11 @@ Supported operations: If both are naive, or both are aware and have the same :attr:`~.datetime.tzinfo` attribute, the :attr:`~.datetime.tzinfo` attributes are ignored, and the result is a :class:`timedelta` - object *t* such that ``datetime2 + t == datetime1``. No time zone adjustments + object ``t`` such that ``datetime2 + t == datetime1``. No time zone adjustments are done in this case. If both are aware and have different :attr:`~.datetime.tzinfo` attributes, ``a-b`` acts - as if *a* and *b* were first converted to naive UTC datetimes. The + as if ``a`` and ``b`` were first converted to naive UTC datetimes. The result is ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - b.utcoffset())`` except that the implementation never overflows. @@ -1454,11 +1454,11 @@ Instance methods: .. method:: datetime.utctimetuple() - If :class:`.datetime` instance *d* is naive, this is the same as + If :class:`.datetime` instance ``d`` is naive, this is the same as ``d.timetuple()`` except that :attr:`~.time.struct_time.tm_isdst` is forced to 0 regardless of what ``d.dst()`` returns. DST is never in effect for a UTC time. - If *d* is aware, *d* is normalized to UTC time, by subtracting + If ``d`` is aware, ``d`` is normalized to UTC time, by subtracting ``d.utcoffset()``, and a :class:`time.struct_time` for the normalized time is returned. :attr:`!tm_isdst` is forced to 0. Note that an :exc:`OverflowError` may be raised if ``d.year`` was @@ -1606,7 +1606,7 @@ Instance methods: .. method:: datetime.__str__() - For a :class:`.datetime` instance *d*, ``str(d)`` is equivalent to + For a :class:`.datetime` instance ``d``, ``str(d)`` is equivalent to ``d.isoformat(' ')``. @@ -1853,7 +1853,7 @@ Instance attributes (read-only): .. versionadded:: 3.6 :class:`.time` objects support equality and order comparisons, -where *a* is considered less than *b* when *a* precedes *b* in time. +where ``a`` is considered less than ``b`` when ``a`` precedes ``b`` in time. Naive and aware :class:`!time` objects are never equal. Order comparison between naive and aware :class:`!time` objects raises @@ -2000,7 +2000,7 @@ Instance methods: .. method:: time.__str__() - For a time *t*, ``str(t)`` is equivalent to ``t.isoformat()``. + For a time ``t``, ``str(t)`` is equivalent to ``t.isoformat()``. .. method:: time.strftime(format) From 1bffd7a2a738506a4ad50c6c3c2c32926cce6d14 Mon Sep 17 00:00:00 2001 From: Steven Jin Date: Mon, 14 Oct 2024 18:36:38 -0400 Subject: [PATCH 172/247] gh-124944: Add socket.SO_ORIGINAL_DST (#124945) --- .../Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst | 1 + Modules/socketmodule.c | 3 +++ Modules/socketmodule.h | 4 ++++ configure | 6 ++++++ configure.ac | 2 +- pyconfig.h.in | 3 +++ 6 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst diff --git a/Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst b/Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst new file mode 100644 index 00000000000000..66af712c5ae5a8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst @@ -0,0 +1 @@ +Add ``SO_ORIGINAL_DST`` to the :mod:`socket` module. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 0829d2358129d2..744e5e0c0b2b54 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -7921,6 +7921,9 @@ socket_exec(PyObject *m) #ifdef SO_OOBINLINE ADD_INT_MACRO(m, SO_OOBINLINE); #endif +#ifdef SO_ORIGINAL_DST + ADD_INT_MACRO(m, SO_ORIGINAL_DST); +#endif #ifndef __GNU__ #ifdef SO_REUSEPORT ADD_INT_MACRO(m, SO_REUSEPORT); diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index a77c620c2ef630..e1d96377728eb9 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -172,6 +172,10 @@ typedef int socklen_t; # undef AF_VSOCK #endif +#ifdef HAVE_LINUX_NETFILTER_IPV4_H +# include +#endif + #ifdef HAVE_SOCKADDR_ALG # include diff --git a/configure b/configure index 0cc73e4e66552d..c5bec6a1b0d7c2 100755 --- a/configure +++ b/configure @@ -11092,6 +11092,12 @@ if test "x$ac_cv_header_linux_memfd_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_MEMFD_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "linux/netfilter_ipv4.h" "ac_cv_header_linux_netfilter_ipv4_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_netfilter_ipv4_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_NETFILTER_IPV4_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "linux/random.h" "ac_cv_header_linux_random_h" "$ac_includes_default" if test "x$ac_cv_header_linux_random_h" = xyes diff --git a/configure.ac b/configure.ac index 1864e94ace9243..d4b7942190207a 100644 --- a/configure.ac +++ b/configure.ac @@ -3013,7 +3013,7 @@ AC_DEFINE([STDC_HEADERS], [1], AC_CHECK_HEADERS([ \ alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \ io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/limits.h linux/memfd.h \ - linux/random.h linux/soundcard.h \ + linux/netfilter_ipv4.h linux/random.h linux/soundcard.h \ linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \ sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \ sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \ diff --git a/pyconfig.h.in b/pyconfig.h.in index 7f02603e26f5d0..1947d8ee14f83e 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -739,6 +739,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_MEMFD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_NETFILTER_IPV4_H + /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NETLINK_H From 0b28ea4a35dc7c68c97127f7aad8f0175d77c520 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 14 Oct 2024 23:45:58 +0100 Subject: [PATCH 173/247] gh-124958: Revert "gh-125472: Revert "gh-124958: fix asyncio.TaskGroup and _PyFuture refcycles ... (#125486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert "gh-125472: Revert "gh-124958: fix asyncio.TaskGroup and _PyFuture refcycles (#12… (#125476)" This reverts commit e99650b80ace3893c2a80b3f2a4aca99cb305191. * fix incompatability with gh-124392 --- Lib/asyncio/futures.py | 6 +- Lib/asyncio/taskgroups.py | 41 +++++-- Lib/test/test_asyncio/test_futures.py | 22 ++++ Lib/test/test_asyncio/test_taskgroups.py | 102 +++++++++++++++++- ...-10-04-08-46-00.gh-issue-124958.rea9-x.rst | 1 + 5 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 5f6fa2348726cf..c95fce035cd548 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -190,8 +190,7 @@ def result(self): the future is done and has an exception set, this exception is raised. """ if self._state == _CANCELLED: - exc = self._make_cancelled_error() - raise exc + raise self._make_cancelled_error() if self._state != _FINISHED: raise exceptions.InvalidStateError('Result is not ready.') self.__log_traceback = False @@ -208,8 +207,7 @@ def exception(self): InvalidStateError. """ if self._state == _CANCELLED: - exc = self._make_cancelled_error() - raise exc + raise self._make_cancelled_error() if self._state != _FINISHED: raise exceptions.InvalidStateError('Exception is not set.') self.__log_traceback = False diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index f2ee9648c43876..9fa772ca9d02cc 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -66,6 +66,20 @@ async def __aenter__(self): return self async def __aexit__(self, et, exc, tb): + tb = None + try: + return await self._aexit(et, exc) + finally: + # Exceptions are heavy objects that can have object + # cycles (bad for GC); let's not keep a reference to + # a bunch of them. It would be nicer to use a try/finally + # in __aexit__ directly but that introduced some diff noise + self._parent_task = None + self._errors = None + self._base_error = None + exc = None + + async def _aexit(self, et, exc): self._exiting = True if (exc is not None and @@ -122,7 +136,10 @@ async def __aexit__(self, et, exc, tb): assert not self._tasks if self._base_error is not None: - raise self._base_error + try: + raise self._base_error + finally: + exc = None if self._parent_cancel_requested: # If this flag is set we *must* call uncancel(). @@ -133,8 +150,14 @@ async def __aexit__(self, et, exc, tb): # Propagate CancelledError if there is one, except if there # are other errors -- those have priority. - if propagate_cancellation_error is not None and not self._errors: - raise propagate_cancellation_error + try: + if propagate_cancellation_error is not None and not self._errors: + try: + raise propagate_cancellation_error + finally: + exc = None + finally: + propagate_cancellation_error = None if et is not None and not issubclass(et, exceptions.CancelledError): self._errors.append(exc) @@ -146,14 +169,14 @@ async def __aexit__(self, et, exc, tb): if self._parent_task.cancelling(): self._parent_task.uncancel() self._parent_task.cancel() - # Exceptions are heavy objects that can have object - # cycles (bad for GC); let's not keep a reference to - # a bunch of them. try: - me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors) - raise me from None + raise BaseExceptionGroup( + 'unhandled errors in a TaskGroup', + self._errors, + ) from None finally: - self._errors = None + exc = None + def create_task(self, coro, *, name=None, context=None): """Create a new task in this group and return it. diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 458b70451a306a..c566b28adb2408 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -659,6 +659,28 @@ def __del__(self): fut = self._new_future(loop=self.loop) fut.set_result(Evil()) + def test_future_cancelled_result_refcycles(self): + f = self._new_future(loop=self.loop) + f.cancel() + exc = None + try: + f.result() + except asyncio.CancelledError as e: + exc = e + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + + def test_future_cancelled_exception_refcycles(self): + f = self._new_future(loop=self.loop) + f.cancel() + exc = None + try: + f.exception() + except asyncio.CancelledError as e: + exc = e + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py index 4852536defc93d..1b4de96a572fb9 100644 --- a/Lib/test/test_asyncio/test_taskgroups.py +++ b/Lib/test/test_asyncio/test_taskgroups.py @@ -1,7 +1,8 @@ # Adapted with permission from the EdgeDB project; # license: PSFL. - +import sys +import gc import asyncio import contextvars import contextlib @@ -11,7 +12,6 @@ from test.test_asyncio.utils import await_without_task - # To prevent a warning "test altered the execution environment" def tearDownModule(): asyncio.set_event_loop_policy(None) @@ -29,6 +29,15 @@ def get_error_types(eg): return {type(exc) for exc in eg.exceptions} +def no_other_refs(): + # due to gh-124392 coroutines now refer to their locals + coro = asyncio.current_task().get_coro() + frame = sys._getframe(1) + while coro.cr_frame != frame: + coro = coro.cr_await + return [coro] + + class TestTaskGroup(unittest.IsolatedAsyncioTestCase): async def test_taskgroup_01(self): @@ -899,6 +908,95 @@ async def outer(): await outer() + async def test_exception_refcycles_direct(self): + """Test that TaskGroup doesn't keep a reference to the raised ExceptionGroup""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + try: + async with tg: + raise _Done + except ExceptionGroup as e: + exc = e + + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), no_other_refs()) + + + async def test_exception_refcycles_errors(self): + """Test that TaskGroup deletes self._errors, and __aexit__ args""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + try: + async with tg: + raise _Done + except* _Done as excs: + exc = excs.exceptions[0] + + self.assertIsInstance(exc, _Done) + self.assertListEqual(gc.get_referrers(exc), no_other_refs()) + + + async def test_exception_refcycles_parent_task(self): + """Test that TaskGroup deletes self._parent_task""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + async def coro_fn(): + async with tg: + raise _Done + + try: + async with asyncio.TaskGroup() as tg2: + tg2.create_task(coro_fn()) + except* _Done as excs: + exc = excs.exceptions[0].exceptions[0] + + self.assertIsInstance(exc, _Done) + self.assertListEqual(gc.get_referrers(exc), no_other_refs()) + + async def test_exception_refcycles_propagate_cancellation_error(self): + """Test that TaskGroup deletes propagate_cancellation_error""" + tg = asyncio.TaskGroup() + exc = None + + try: + async with asyncio.timeout(-1): + async with tg: + await asyncio.sleep(0) + except TimeoutError as e: + exc = e.__cause__ + + self.assertIsInstance(exc, asyncio.CancelledError) + self.assertListEqual(gc.get_referrers(exc), no_other_refs()) + + async def test_exception_refcycles_base_error(self): + """Test that TaskGroup deletes self._base_error""" + class MyKeyboardInterrupt(KeyboardInterrupt): + pass + + tg = asyncio.TaskGroup() + exc = None + + try: + async with tg: + raise MyKeyboardInterrupt + except MyKeyboardInterrupt as e: + exc = e + + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), no_other_refs()) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst b/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst new file mode 100644 index 00000000000000..534d5bb8c898da --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst @@ -0,0 +1 @@ +Fix refcycles in exceptions raised from :class:`asyncio.TaskGroup` and the python implementation of :class:`asyncio.Future` From 8d42e2d915c3096e7eac1c649751d1da567bb7c3 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Mon, 14 Oct 2024 20:09:48 -0400 Subject: [PATCH 174/247] gh-125269: Use `AC_LINK_IF_ELSE` to detect if `-latomic` is needed (#125416) We previously used `AC_RUN_IF_ELSE` with a short test program to detect if `-latomic` is needed, but that requires choosing a specific default value when cross-compiling because the test program is not run. Some cross compilation targets like `wasm32-emscripten` do not support `-latomic`, while other cross compilation targets, like `arm-linux-gnueabi` require it. --- .../2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst | 2 ++ configure | 12 +++--------- configure.ac | 7 +++---- 3 files changed, 8 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst diff --git a/Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst b/Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst new file mode 100644 index 00000000000000..24f5469e8a664b --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst @@ -0,0 +1,2 @@ +Fix detection of whether ``-latomic`` is needed when cross-compiling CPython +using the configure script. diff --git a/configure b/configure index c5bec6a1b0d7c2..be119f108a060b 100755 --- a/configure +++ b/configure @@ -28999,10 +28999,6 @@ printf %s "checking whether libatomic is needed by ... " >&6; } if test ${ac_cv_libatomic_needed+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes -then : - ac_cv_libatomic_needed=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -29044,16 +29040,14 @@ int main() } _ACEOF -if ac_fn_c_try_run "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_libatomic_needed=no else $as_nop ac_cv_libatomic_needed=yes fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libatomic_needed" >&5 printf "%s\n" "$ac_cv_libatomic_needed" >&6; } diff --git a/configure.ac b/configure.ac index d4b7942190207a..582851695e400f 100644 --- a/configure.ac +++ b/configure.ac @@ -7497,7 +7497,7 @@ CPPFLAGS="${BASECPPFLAGS} -I. -I${srcdir}/Include ${CPPFLAGS}" AC_CACHE_CHECK([whether libatomic is needed by ], [ac_cv_libatomic_needed], -[AC_RUN_IFELSE([AC_LANG_SOURCE([[ +[AC_LINK_IFELSE([AC_LANG_SOURCE([[ // pyatomic.h needs uint64_t and Py_ssize_t types #include // int64_t, intptr_t #ifdef HAVE_SYS_TYPES_H @@ -7534,9 +7534,8 @@ int main() return 0; // all good } ]])], - [ac_cv_libatomic_needed=no], dnl build succeeded - [ac_cv_libatomic_needed=yes], dnl build failed - [ac_cv_libatomic_needed=no]) dnl cross compilation + [ac_cv_libatomic_needed=no], dnl build and link succeeded + [ac_cv_libatomic_needed=yes]) dnl build and link failed ]) AS_VAR_IF([ac_cv_libatomic_needed], [yes], From a2fe9ff11d6104074c19bf328a104caa99becc11 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Tue, 15 Oct 2024 09:29:08 +0200 Subject: [PATCH 175/247] Doc: Update CVE URL (#125489) --- Doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/conf.py b/Doc/conf.py index d7197b17865854..839beaad08bebd 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -614,7 +614,7 @@ # Sphinx 8.1 has in-built CVE and CWE roles. extlinks |= { "cve": ( - "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-%s", + "https://www.cve.org/CVERecord?id=CVE-%s", "CVE-%s", ), "cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"), From 66064c342c6fb54b443aae8ccf8db74bb9d8bc50 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:39:15 +0300 Subject: [PATCH 176/247] gh-123299: Copyedit "What's New in Python 3.14" (#125438) --- .../c-api-pending-removal-in-3.14.rst | 2 +- .../c-api-pending-removal-in-3.15.rst | 2 +- .../c-api-pending-removal-in-future.rst | 2 +- Doc/deprecations/index.rst | 2 +- Doc/deprecations/pending-removal-in-3.13.rst | 2 +- Doc/deprecations/pending-removal-in-3.14.rst | 2 +- Doc/deprecations/pending-removal-in-3.15.rst | 4 +- Doc/deprecations/pending-removal-in-3.16.rst | 29 +++-- .../pending-removal-in-future.rst | 2 +- Doc/whatsnew/3.14.rst | 110 +++++++++--------- 10 files changed, 79 insertions(+), 78 deletions(-) diff --git a/Doc/deprecations/c-api-pending-removal-in-3.14.rst b/Doc/deprecations/c-api-pending-removal-in-3.14.rst index d16da66c29abe7..9e10bf2691e5c8 100644 --- a/Doc/deprecations/c-api-pending-removal-in-3.14.rst +++ b/Doc/deprecations/c-api-pending-removal-in-3.14.rst @@ -1,4 +1,4 @@ -Pending Removal in Python 3.14 +Pending removal in Python 3.14 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * The ``ma_version_tag`` field in :c:type:`PyDictObject` for extension modules diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst index e3974415e0cc89..1bb49e5b4874f2 100644 --- a/Doc/deprecations/c-api-pending-removal-in-3.15.rst +++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst @@ -1,4 +1,4 @@ -Pending Removal in Python 3.15 +Pending removal in Python 3.15 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * The bundled copy of ``libmpdecimal``. diff --git a/Doc/deprecations/c-api-pending-removal-in-future.rst b/Doc/deprecations/c-api-pending-removal-in-future.rst index 0c3ae52b87ff74..8fc1c80c35d092 100644 --- a/Doc/deprecations/c-api-pending-removal-in-future.rst +++ b/Doc/deprecations/c-api-pending-removal-in-future.rst @@ -1,4 +1,4 @@ -Pending Removal in Future Versions +Pending removal in future versions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following APIs are deprecated and will be removed, diff --git a/Doc/deprecations/index.rst b/Doc/deprecations/index.rst index a9efb0bc744335..bac6e3f18d4594 100644 --- a/Doc/deprecations/index.rst +++ b/Doc/deprecations/index.rst @@ -7,7 +7,7 @@ Deprecations .. include:: pending-removal-in-future.rst -C API Deprecations +C API deprecations ------------------ .. include:: c-api-pending-removal-in-3.15.rst diff --git a/Doc/deprecations/pending-removal-in-3.13.rst b/Doc/deprecations/pending-removal-in-3.13.rst index 89790497816e83..2fd2f12cc6a2c4 100644 --- a/Doc/deprecations/pending-removal-in-3.13.rst +++ b/Doc/deprecations/pending-removal-in-3.13.rst @@ -1,4 +1,4 @@ -Pending Removal in Python 3.13 +Pending removal in Python 3.13 ------------------------------ Modules (see :pep:`594`): diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst index de30f4695059ed..b8791b8d6c387e 100644 --- a/Doc/deprecations/pending-removal-in-3.14.rst +++ b/Doc/deprecations/pending-removal-in-3.14.rst @@ -1,4 +1,4 @@ -Pending Removal in Python 3.14 +Pending removal in Python 3.14 ------------------------------ * The import system: diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst index a55fb6bea3fdaa..17029b8d4773bd 100644 --- a/Doc/deprecations/pending-removal-in-3.15.rst +++ b/Doc/deprecations/pending-removal-in-3.15.rst @@ -1,4 +1,4 @@ -Pending Removal in Python 3.15 +Pending removal in Python 3.15 ------------------------------ * The import system: @@ -63,7 +63,7 @@ Pending Removal in Python 3.15 * The undocumented keyword argument syntax for creating :class:`~typing.NamedTuple` classes - (e.g. ``Point = NamedTuple("Point", x=int, y=int)``) + (for example, ``Point = NamedTuple("Point", x=int, y=int)``) has been deprecated since Python 3.13. Use the class-based syntax or the functional syntax instead. diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst index fc2ef33de5e5cc..fac500d34742ca 100644 --- a/Doc/deprecations/pending-removal-in-3.16.rst +++ b/Doc/deprecations/pending-removal-in-3.16.rst @@ -1,15 +1,6 @@ -Pending Removal in Python 3.16 +Pending removal in Python 3.16 ------------------------------ -* :mod:`builtins`: - - * Bitwise inversion on boolean types, ``~True`` or ``~False`` - has been deprecated since Python 3.12, - as it produces surprising and unintuitive results (``-2`` and ``-1``). - Use ``not x`` instead for the logical negation of a Boolean. - In the rare case that you need the bitwise inversion of - the underlying integer, convert to ``int`` explicitly (``~int(x)``). - * :mod:`array`: * The ``'u'`` format code (:c:type:`wchar_t`) @@ -20,11 +11,19 @@ Pending Removal in Python 3.16 * :mod:`asyncio`: - * :mod:`asyncio`: - :func:`!asyncio.iscoroutinefunction` is deprecated - and will be removed in Python 3.16, - use :func:`inspect.iscoroutinefunction` instead. - (Contributed by Jiahao Li and Kumar Aditya in :gh:`122875`.) + * :func:`!asyncio.iscoroutinefunction` is deprecated + and will be removed in Python 3.16, + use :func:`inspect.iscoroutinefunction` instead. + (Contributed by Jiahao Li and Kumar Aditya in :gh:`122875`.) + +* :mod:`builtins`: + + * Bitwise inversion on boolean types, ``~True`` or ``~False`` + has been deprecated since Python 3.12, + as it produces surprising and unintuitive results (``-2`` and ``-1``). + Use ``not x`` instead for the logical negation of a Boolean. + In the rare case that you need the bitwise inversion of + the underlying integer, convert to ``int`` explicitly (``~int(x)``). * :mod:`shutil`: diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst index 3f9cf6f208221a..f916797c07a068 100644 --- a/Doc/deprecations/pending-removal-in-future.rst +++ b/Doc/deprecations/pending-removal-in-future.rst @@ -1,4 +1,4 @@ -Pending Removal in Future Versions +Pending removal in future versions ---------------------------------- The following APIs will be removed in the future, diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 25e69a59bdec62..b106578fe9e8b0 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1,6 +1,6 @@ **************************** - What's New In Python 3.14 + What's new in Python 3.14 **************************** :Editor: TBD @@ -56,7 +56,7 @@ For full details, see the :ref:`changelog `. so it's worth checking back even after reading earlier versions. -Summary -- Release highlights +Summary -- release highlights ============================= .. This section singles out the most important changes in Python 3.14. @@ -67,12 +67,12 @@ Summary -- Release highlights -New Features +New features ============ -.. _whatsnew-314-pep649: +.. _whatsnew314-pep649: -PEP 649: Deferred Evaluation of Annotations +PEP 649: deferred evaluation of annotations ------------------------------------------- The :term:`annotations ` on functions, classes, and modules are no @@ -150,12 +150,12 @@ In Python 3.7, :pep:`563` introduced the ``from __future__ import annotations`` directive, which turns all annotations into strings. This directive is now considered deprecated and it is expected to be removed in a future version of Python. However, this removal will not happen until after Python 3.13, the last version of -Python without deferred evaluation of annotations, reaches its end of life. +Python without deferred evaluation of annotations, reaches its end of life in 2029. In Python 3.14, the behavior of code using ``from __future__ import annotations`` is unchanged. -Improved Error Messages +Improved error messages ----------------------- * When unpacking assignment fails due to incorrect number of variables, the @@ -172,16 +172,16 @@ Improved Error Messages ValueError: too many values to unpack (expected 3, got 4) -Other Language Changes +Other language changes ====================== * Incorrect usage of :keyword:`await` and asynchronous comprehensions is now detected even if the code is optimized away by the :option:`-O` - command line option. For example, ``python -O -c 'assert await 1'`` + command-line option. For example, ``python -O -c 'assert await 1'`` now produces a :exc:`SyntaxError`. (Contributed by Jelle Zijlstra in :gh:`121637`.) * Writes to ``__debug__`` are now detected even if the code is optimized - away by the :option:`-O` command line option. For example, + away by the :option:`-O` command-line option. For example, ``python -O -c 'assert (__debug__ := 1)'`` now produces a :exc:`SyntaxError`. (Contributed by Irit Katriel in :gh:`122245`.) @@ -191,7 +191,7 @@ Other Language Changes (Contributed by Serhiy Storchaka in :gh:`84978`.) -New Modules +New modules =========== * :mod:`annotationlib`: For introspecting :term:`annotations `. @@ -199,7 +199,7 @@ New Modules (Contributed by Jelle Zijlstra in :gh:`119180`.) -Improved Modules +Improved modules ================ argparse @@ -214,7 +214,7 @@ ast --- * Add :func:`ast.compare` for comparing two ASTs. - (Contributed by Batuhan Taskaya and Jeremy Hylton in :issue:`15987`.) + (Contributed by Batuhan Taskaya and Jeremy Hylton in :gh:`60191`.) * Add support for :func:`copy.replace` for AST nodes. (Contributed by Bénédikt Tran in :gh:`121141`.) @@ -246,6 +246,12 @@ decimal :meth:`Decimal.from_number() `. (Contributed by Serhiy Storchaka in :gh:`121798`.) +datetime +-------- + +* Add :meth:`datetime.time.strptime` and :meth:`datetime.date.strptime`. + (Contributed by Wannes Boeykens in :gh:`41431`.) + dis --- @@ -254,9 +260,10 @@ dis This feature is added to the following interfaces via the *show_positions* keyword argument: - - :class:`dis.Bytecode`, - - :func:`dis.dis`, :func:`dis.distb`, and - - :func:`dis.disassemble`. + - :class:`dis.Bytecode` + - :func:`dis.dis` + - :func:`dis.distb` + - :func:`dis.disassemble` This feature is also exposed via :option:`dis --show-positions`. (Contributed by Bénédikt Tran in :gh:`123165`.) @@ -310,7 +317,8 @@ json of the error. (Contributed by Serhiy Storchaka in :gh:`122163`.) -* Enable the :mod:`json` module to work as a script using the :option:`-m` switch: ``python -m json``. +* Enable the :mod:`json` module to work as a script using the :option:`-m` + switch: :program:`python -m json`. See the :ref:`JSON command-line interface ` documentation. (Contributed by Trey Hunner in :gh:`122873`.) @@ -325,12 +333,6 @@ operator (Contributed by Raymond Hettinger and Nico Mexis in :gh:`115808`.) -datetime --------- - -* Add :meth:`datetime.time.strptime` and :meth:`datetime.date.strptime`. - (Contributed by Wannes Boeykens in :gh:`41431`.) - os -- @@ -357,11 +359,11 @@ pathlib pdb --- -* Hard-coded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace`) now +* Hardcoded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace`) now reuse the most recent :class:`~pdb.Pdb` instance that calls :meth:`~pdb.Pdb.set_trace`, instead of creating a new one each time. As a result, all the instance specific data like :pdbcmd:`display` and - :pdbcmd:`commands` are preserved across hard-coded breakpoints. + :pdbcmd:`commands` are preserved across hardcoded breakpoints. (Contributed by Tian Gao in :gh:`121450`.) * Add a new argument *mode* to :class:`pdb.Pdb`. Disable the ``restart`` @@ -391,9 +393,9 @@ symtable * Expose the following :class:`symtable.Symbol` methods: - * :meth:`~symtable.Symbol.is_free_class` - * :meth:`~symtable.Symbol.is_comp_iter` * :meth:`~symtable.Symbol.is_comp_cell` + * :meth:`~symtable.Symbol.is_comp_iter` + * :meth:`~symtable.Symbol.is_free_class` (Contributed by Bénédikt Tran in :gh:`120029`.) @@ -472,11 +474,11 @@ ast * Remove the following classes. They were all deprecated since Python 3.8, and have emitted deprecation warnings since Python 3.12: - * :class:`!ast.Num` - * :class:`!ast.Str` * :class:`!ast.Bytes` - * :class:`!ast.NameConstant` * :class:`!ast.Ellipsis` + * :class:`!ast.NameConstant` + * :class:`!ast.Num` + * :class:`!ast.Str` Use :class:`ast.Constant` instead. As a consequence of these removals, user-defined ``visit_Num``, ``visit_Str``, ``visit_Bytes``, @@ -501,16 +503,16 @@ asyncio * Remove the following classes and functions. They were all deprecated and emitted deprecation warnings since Python 3.12: + * :func:`!asyncio.get_child_watcher` + * :func:`!asyncio.set_child_watcher` + * :meth:`!asyncio.AbstractEventLoopPolicy.get_child_watcher` + * :meth:`!asyncio.AbstractEventLoopPolicy.set_child_watcher` * :class:`!asyncio.AbstractChildWatcher` - * :class:`!asyncio.SafeChildWatcher` - * :class:`!asyncio.MultiLoopChildWatcher` * :class:`!asyncio.FastChildWatcher` - * :class:`!asyncio.ThreadedChildWatcher` + * :class:`!asyncio.MultiLoopChildWatcher` * :class:`!asyncio.PidfdChildWatcher` - * :meth:`!asyncio.AbstractEventLoopPolicy.get_child_watcher` - * :meth:`!asyncio.AbstractEventLoopPolicy.set_child_watcher` - * :func:`!asyncio.get_child_watcher` - * :func:`!asyncio.set_child_watcher` + * :class:`!asyncio.SafeChildWatcher` + * :class:`!asyncio.ThreadedChildWatcher` (Contributed by Kumar Aditya in :gh:`120804`.) @@ -623,14 +625,14 @@ Changes in the Python API (Contributed by Serhiy Storchaka in :gh:`69998`.) -Build Changes +Build changes ============= -C API Changes +C API changes ============= -New Features +New features ------------ * Add :c:func:`PyLong_GetSign` function to get the sign of :class:`int` objects. @@ -640,17 +642,17 @@ New Features object: * :c:func:`PyUnicodeWriter_Create` + * :c:func:`PyUnicodeWriter_DecodeUTF8Stateful` * :c:func:`PyUnicodeWriter_Discard` * :c:func:`PyUnicodeWriter_Finish` + * :c:func:`PyUnicodeWriter_Format` * :c:func:`PyUnicodeWriter_WriteChar` - * :c:func:`PyUnicodeWriter_WriteUTF8` - * :c:func:`PyUnicodeWriter_WriteUCS4` - * :c:func:`PyUnicodeWriter_WriteWideChar` - * :c:func:`PyUnicodeWriter_WriteStr` * :c:func:`PyUnicodeWriter_WriteRepr` + * :c:func:`PyUnicodeWriter_WriteStr` * :c:func:`PyUnicodeWriter_WriteSubstring` - * :c:func:`PyUnicodeWriter_Format` - * :c:func:`PyUnicodeWriter_DecodeUTF8Stateful` + * :c:func:`PyUnicodeWriter_WriteUCS4` + * :c:func:`PyUnicodeWriter_WriteUTF8` + * :c:func:`PyUnicodeWriter_WriteWideChar` (Contributed by Victor Stinner in :gh:`119182`.) @@ -671,14 +673,14 @@ New Features * Add new functions to convert C ```` numbers from/to Python :class:`int`: - * :c:func:`PyLong_FromInt32` - * :c:func:`PyLong_FromInt64` - * :c:func:`PyLong_FromUInt32` - * :c:func:`PyLong_FromUInt64` * :c:func:`PyLong_AsInt32` * :c:func:`PyLong_AsInt64` * :c:func:`PyLong_AsUInt32` * :c:func:`PyLong_AsUInt64` + * :c:func:`PyLong_FromInt32` + * :c:func:`PyLong_FromInt64` + * :c:func:`PyLong_FromUInt32` + * :c:func:`PyLong_FromUInt64` (Contributed by Victor Stinner in :gh:`120389`.) @@ -701,20 +703,20 @@ New Features * Add functions to configure the Python initialization (:pep:`741`): + * :c:func:`Py_InitializeFromInitConfig` + * :c:func:`PyInitConfig_AddModule` * :c:func:`PyInitConfig_Create` * :c:func:`PyInitConfig_Free` + * :c:func:`PyInitConfig_FreeStrList` * :c:func:`PyInitConfig_GetError` * :c:func:`PyInitConfig_GetExitCode` - * :c:func:`PyInitConfig_HasOption` * :c:func:`PyInitConfig_GetInt` * :c:func:`PyInitConfig_GetStr` * :c:func:`PyInitConfig_GetStrList` - * :c:func:`PyInitConfig_FreeStrList` + * :c:func:`PyInitConfig_HasOption` * :c:func:`PyInitConfig_SetInt` * :c:func:`PyInitConfig_SetStr` * :c:func:`PyInitConfig_SetStrList` - * :c:func:`PyInitConfig_AddModule` - * :c:func:`Py_InitializeFromInitConfig` (Contributed by Victor Stinner in :gh:`107954`.) From 92af191a6a5f266b71373f5374ca0c9c522d62d9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 15 Oct 2024 11:05:40 +0300 Subject: [PATCH 177/247] gh-53203: Fix strptime() tests for %X on glibc < 2.29 (#125469) --- Lib/test/test_strptime.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 12366b053a2fc1..09f6f656bfcb0d 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -569,12 +569,20 @@ def test_date_locale2(self): 'ti_ET', 'tig_ER', 'wal_ET') def test_time_locale(self): # Test %X directive + loc = locale.getlocale(locale.LC_TIME)[0] + pos = slice(3, 6) + if glibc_ver and glibc_ver < (2, 29) and loc in { + 'aa_ET', 'am_ET', 'byn_ER', 'gez_ET', 'om_ET', + 'sid_ET', 'so_SO', 'ti_ET', 'tig_ER', 'wal_ET'}: + # Hours are in 12-hour notation without AM/PM indication. + # Ignore hours. + pos = slice(4, 6) now = time.time() - self.roundtrip('%X', slice(3, 6), time.localtime(now)) + self.roundtrip('%X', pos, time.localtime(now)) # 1 hour 20 minutes 30 seconds ago - self.roundtrip('%X', slice(3, 6), time.localtime(now - 4830)) + self.roundtrip('%X', pos, time.localtime(now - 4830)) # 12 hours ago - self.roundtrip('%X', slice(3, 6), time.localtime(now - 12*3600)) + self.roundtrip('%X', pos, time.localtime(now - 12*3600)) def test_percent(self): # Make sure % signs are handled properly From 546dddca43a2a69dbe33d230e9e540636b403270 Mon Sep 17 00:00:00 2001 From: "RUANG (Roy James)" Date: Tue, 15 Oct 2024 17:21:16 +0800 Subject: [PATCH 178/247] gh-125234: Make PyInitConfig_Free(NULL) a no-op (#125266) --- Doc/c-api/init_config.rst | 2 ++ Programs/_testembed.c | 1 + Python/initconfig.c | 3 +++ 3 files changed, 6 insertions(+) diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 6f8962afc7af0d..66e845df2e6aa5 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -1621,6 +1621,8 @@ Create Config Free memory of the initialization configuration *config*. + If *config* is ``NULL``, no operation is performed. + Error Handling -------------- diff --git a/Programs/_testembed.c b/Programs/_testembed.c index ab619e32429d63..0fb45b2265e3c6 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -1896,6 +1896,7 @@ static int test_initconfig_api(void) goto error; } PyInitConfig_Free(config); + PyInitConfig_Free(NULL); dump_config(); Py_Finalize(); diff --git a/Python/initconfig.c b/Python/initconfig.c index 58ac5e7d7eaeff..c142438b02bfd9 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -3457,6 +3457,9 @@ PyInitConfig_Create(void) void PyInitConfig_Free(PyInitConfig *config) { + if (config == NULL) { + return; + } free(config->err_msg); free(config); } From aa18fd55d575a04e3aa782fedcd08dced26676e0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 15 Oct 2024 11:47:36 +0200 Subject: [PATCH 179/247] gh-125196: Use PyUnicodeWriter in HAMT (#125458) --- Python/hamt.c | 81 ++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/Python/hamt.c b/Python/hamt.c index a8fbb00b807934..cfd211f4541446 100644 --- a/Python/hamt.c +++ b/Python/hamt.c @@ -349,7 +349,7 @@ hamt_node_find(PyHamtNode *node, #ifdef Py_DEBUG static int hamt_node_dump(PyHamtNode *node, - _PyUnicodeWriter *writer, int level); + PyUnicodeWriter *writer, int level); #endif static PyHamtNode * @@ -444,7 +444,7 @@ hamt_bitindex(uint32_t bitmap, uint32_t bit) #ifdef Py_DEBUG static int -_hamt_dump_ident(_PyUnicodeWriter *writer, int level) +_hamt_dump_ident(PyUnicodeWriter *writer, int level) { /* Write `' ' * level` to the `writer` */ PyObject *str = NULL; @@ -467,7 +467,7 @@ _hamt_dump_ident(_PyUnicodeWriter *writer, int level) goto error; } - ret = _PyUnicodeWriter_WriteStr(writer, res); + ret = PyUnicodeWriter_WriteStr(writer, res); error: Py_XDECREF(res); @@ -476,29 +476,6 @@ _hamt_dump_ident(_PyUnicodeWriter *writer, int level) return ret; } -static int -_hamt_dump_format(_PyUnicodeWriter *writer, const char *format, ...) -{ - /* A convenient helper combining _PyUnicodeWriter_WriteStr and - PyUnicode_FromFormatV. - */ - PyObject* msg; - int ret; - - va_list vargs; - va_start(vargs, format); - msg = PyUnicode_FromFormatV(format, vargs); - va_end(vargs); - - if (msg == NULL) { - return -1; - } - - ret = _PyUnicodeWriter_WriteStr(writer, msg); - Py_DECREF(msg); - return ret; -} - #endif /* Py_DEBUG */ /////////////////////////////////// Bitmap Node @@ -1154,7 +1131,7 @@ hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self) #ifdef Py_DEBUG static int hamt_node_bitmap_dump(PyHamtNode_Bitmap *node, - _PyUnicodeWriter *writer, int level) + PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for Bitmap nodes. */ @@ -1166,8 +1143,8 @@ hamt_node_bitmap_dump(PyHamtNode_Bitmap *node, goto error; } - if (_hamt_dump_format(writer, "BitmapNode(size=%zd count=%zd ", - Py_SIZE(node), Py_SIZE(node) / 2)) + if (PyUnicodeWriter_Format(writer, "BitmapNode(size=%zd count=%zd ", + Py_SIZE(node), Py_SIZE(node) / 2) < 0) { goto error; } @@ -1181,7 +1158,9 @@ hamt_node_bitmap_dump(PyHamtNode_Bitmap *node, if (tmp2 == NULL) { goto error; } - if (_hamt_dump_format(writer, "bitmap=%S id=%p):\n", tmp2, node)) { + if (PyUnicodeWriter_Format(writer, "bitmap=%S id=%p):\n", + tmp2, node) < 0) + { Py_DECREF(tmp2); goto error; } @@ -1196,7 +1175,7 @@ hamt_node_bitmap_dump(PyHamtNode_Bitmap *node, } if (key_or_null == NULL) { - if (_hamt_dump_format(writer, "NULL:\n")) { + if (PyUnicodeWriter_WriteUTF8(writer, "NULL:\n", -1) < 0) { goto error; } @@ -1207,14 +1186,14 @@ hamt_node_bitmap_dump(PyHamtNode_Bitmap *node, } } else { - if (_hamt_dump_format(writer, "%R: %R", key_or_null, - val_or_node)) + if (PyUnicodeWriter_Format(writer, "%R: %R", + key_or_null, val_or_node) < 0) { goto error; } } - if (_hamt_dump_format(writer, "\n")) { + if (PyUnicodeWriter_WriteUTF8(writer, "\n", 1) < 0) { goto error; } } @@ -1548,7 +1527,7 @@ hamt_node_collision_dealloc(PyHamtNode_Collision *self) #ifdef Py_DEBUG static int hamt_node_collision_dump(PyHamtNode_Collision *node, - _PyUnicodeWriter *writer, int level) + PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for Collision nodes. */ @@ -1558,8 +1537,8 @@ hamt_node_collision_dump(PyHamtNode_Collision *node, goto error; } - if (_hamt_dump_format(writer, "CollisionNode(size=%zd id=%p):\n", - Py_SIZE(node), node)) + if (PyUnicodeWriter_Format(writer, "CollisionNode(size=%zd id=%p):\n", + Py_SIZE(node), node) < 0) { goto error; } @@ -1572,7 +1551,7 @@ hamt_node_collision_dump(PyHamtNode_Collision *node, goto error; } - if (_hamt_dump_format(writer, "%R: %R\n", key, val)) { + if (PyUnicodeWriter_Format(writer, "%R: %R\n", key, val) < 0) { goto error; } } @@ -1924,7 +1903,7 @@ hamt_node_array_dealloc(PyHamtNode_Array *self) #ifdef Py_DEBUG static int hamt_node_array_dump(PyHamtNode_Array *node, - _PyUnicodeWriter *writer, int level) + PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for Array nodes. */ @@ -1934,7 +1913,7 @@ hamt_node_array_dump(PyHamtNode_Array *node, goto error; } - if (_hamt_dump_format(writer, "ArrayNode(id=%p):\n", node)) { + if (PyUnicodeWriter_Format(writer, "ArrayNode(id=%p):\n", node) < 0) { goto error; } @@ -1947,7 +1926,7 @@ hamt_node_array_dump(PyHamtNode_Array *node, goto error; } - if (_hamt_dump_format(writer, "%zd::\n", i)) { + if (PyUnicodeWriter_Format(writer, "%zd::\n", i) < 0) { goto error; } @@ -1955,7 +1934,7 @@ hamt_node_array_dump(PyHamtNode_Array *node, goto error; } - if (_hamt_dump_format(writer, "\n")) { + if (PyUnicodeWriter_WriteUTF8(writer, "\n", 1) < 0) { goto error; } } @@ -2071,7 +2050,7 @@ hamt_node_find(PyHamtNode *node, #ifdef Py_DEBUG static int hamt_node_dump(PyHamtNode *node, - _PyUnicodeWriter *writer, int level) + PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for a node. @@ -2440,22 +2419,24 @@ _PyHamt_New(void) static PyObject * hamt_dump(PyHamtObject *self) { - _PyUnicodeWriter writer; - - _PyUnicodeWriter_Init(&writer); + PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); + if (writer == NULL) { + return NULL; + } - if (_hamt_dump_format(&writer, "HAMT(len=%zd):\n", self->h_count)) { + if (PyUnicodeWriter_Format(writer, "HAMT(len=%zd):\n", + self->h_count) < 0) { goto error; } - if (hamt_node_dump(self->h_root, &writer, 0)) { + if (hamt_node_dump(self->h_root, writer, 0)) { goto error; } - return _PyUnicodeWriter_Finish(&writer); + return PyUnicodeWriter_Finish(writer); error: - _PyUnicodeWriter_Dealloc(&writer); + PyUnicodeWriter_Discard(writer); return NULL; } #endif /* Py_DEBUG */ From fcef3fc9a593e2aa868d23cf2d91c57d8bf60ac6 Mon Sep 17 00:00:00 2001 From: foreignmeloman Date: Tue, 15 Oct 2024 14:26:19 +0400 Subject: [PATCH 180/247] =?UTF-8?q?gh-119535:=20Support=20=F0=9D=9C=8Bthon?= =?UTF-8?q?=20in=20Python=203.14=20venvs=20(#125035)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/venv/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index a00fa690fa0b88..a5d348ba4cf121 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -306,7 +306,7 @@ def setup_python(self, context): suffixes = ['python', 'python3', f'python3.{sys.version_info[1]}'] if sys.version_info[:2] == (3, 14): - suffixes.append('python𝜋') + suffixes.append('𝜋thon') for suffix in suffixes: path = os.path.join(binpath, suffix) if not os.path.exists(path): From cc5a225cdc2a5d4e035dd08d59cef39182c10a6c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 15 Oct 2024 13:29:43 +0200 Subject: [PATCH 181/247] gh-125041: test_zlib: For s390x HW acceleration, only skip checking the compressed bytes (#125042) --- Lib/test/support/__init__.py | 6 ++--- Lib/test/test_zlib.py | 25 ++++++++++++------- ...-10-07-14-13-38.gh-issue-125041.PKLWDf.rst | 3 +++ 3 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index d768bead7120c7..f05be2b6bdf496 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2625,9 +2625,9 @@ def exceeds_recursion_limit(): return get_c_recursion_limit() * 3 -#Windows doesn't have os.uname() but it doesn't support s390x. -skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x', - 'skipped on s390x') +# Windows doesn't have os.uname() but it doesn't support s390x. +is_s390x = hasattr(os, 'uname') and os.uname().machine == 's390x' +skip_on_s390x = unittest.skipIf(is_s390x, 'skipped on s390x') Py_TRACE_REFS = hasattr(sys, 'getobjects') diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index ef02c64f886f8a..8b4bb8750f8f5c 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -6,7 +6,7 @@ import pickle import random import sys -from test.support import bigmemtest, _1G, _4G, skip_on_s390x +from test.support import bigmemtest, _1G, _4G, is_s390x zlib = import_helper.import_module('zlib') @@ -33,8 +33,9 @@ def _zlib_runtime_version_tuple(zlib_version=zlib.ZLIB_RUNTIME_VERSION): ZLIB_RUNTIME_VERSION_TUPLE = _zlib_runtime_version_tuple() -# bpo-46623: On s390x, when a hardware accelerator is used, using different -# ways to compress data with zlib can produce different compressed data. +# bpo-46623: When a hardware accelerator is used (currently only on s390x), +# using different ways to compress data with zlib can produce different +# compressed data. # Simplified test_pair() code: # # def func1(data): @@ -57,8 +58,10 @@ def _zlib_runtime_version_tuple(zlib_version=zlib.ZLIB_RUNTIME_VERSION): # # zlib.decompress(func1(data)) == zlib.decompress(func2(data)) == data # -# Make the assumption that s390x always has an accelerator to simplify the skip -# condition. +# To simplify the skip condition, make the assumption that s390x always has an +# accelerator, and nothing else has it. +HW_ACCELERATED = is_s390x + class VersionTestCase(unittest.TestCase): @@ -223,12 +226,14 @@ def test_keywords(self): bufsize=zlib.DEF_BUF_SIZE), HAMLET_SCENE) - @skip_on_s390x def test_speech128(self): # compress more data data = HAMLET_SCENE * 128 x = zlib.compress(data) - self.assertEqual(zlib.compress(bytearray(data)), x) + # With hardware acceleration, the compressed bytes + # might not be identical. + if not HW_ACCELERATED: + self.assertEqual(zlib.compress(bytearray(data)), x) for ob in x, bytearray(x): self.assertEqual(zlib.decompress(ob), data) @@ -275,7 +280,6 @@ def test_64bit_compress(self, size): class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): # Test compression object - @skip_on_s390x def test_pair(self): # straightforward compress/decompress objects datasrc = HAMLET_SCENE * 128 @@ -286,7 +290,10 @@ def test_pair(self): x1 = co.compress(data) x2 = co.flush() self.assertRaises(zlib.error, co.flush) # second flush should not work - self.assertEqual(x1 + x2, datazip) + # With hardware acceleration, the compressed bytes might not + # be identical. + if not HW_ACCELERATED: + self.assertEqual(x1 + x2, datazip) for v1, v2 in ((x1, x2), (bytearray(x1), bytearray(x2))): dco = zlib.decompressobj() y1 = dco.decompress(v1 + v2) diff --git a/Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst b/Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst new file mode 100644 index 00000000000000..c7181eb9c1f3a9 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst @@ -0,0 +1,3 @@ +Re-enable skipped tests for :mod:`zlib` on the s390x architecture: only skip +checks of the compressed bytes, which can be different between zlib's +software implementation and the hardware-accelerated implementation. From c8a1818fb01937b66b93728c11d68c9f9af688a5 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 15 Oct 2024 16:12:32 +0300 Subject: [PATCH 182/247] gh-125517: Fix unreachable code warnings in `_testembed.c` (#125518) --- Doc/c-api/init_config.rst | 16 ++++++++++------ Programs/_testembed.c | 20 ++++++++++++-------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 66e845df2e6aa5..6194d7446c73e4 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -1825,14 +1825,18 @@ return ``-1`` on error: PyInitConfig_Free(config); return 0; - // Display the error message - const char *err_msg; error: - (void)PyInitConfig_GetError(config, &err_msg); - printf("PYTHON INIT ERROR: %s\n", err_msg); - PyInitConfig_Free(config); + { + // Display the error message + // This uncommon braces style is used, because you cannot make + // goto targets point to variable declarations. + const char *err_msg; + (void)PyInitConfig_GetError(config, &err_msg); + printf("PYTHON INIT ERROR: %s\n", err_msg); + PyInitConfig_Free(config); - return -1; + return -1; + } } diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 0fb45b2265e3c6..d15dd519dbf6af 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -1902,11 +1902,13 @@ static int test_initconfig_api(void) Py_Finalize(); return 0; - const char *err_msg; error: - (void)PyInitConfig_GetError(config, &err_msg); - printf("Python init failed: %s\n", err_msg); - exit(1); + { + const char *err_msg; + (void)PyInitConfig_GetError(config, &err_msg); + printf("Python init failed: %s\n", err_msg); + exit(1); + } } @@ -2050,11 +2052,13 @@ static int test_initconfig_module(void) Py_Finalize(); return 0; - const char *err_msg; error: - (void)PyInitConfig_GetError(config, &err_msg); - printf("Python init failed: %s\n", err_msg); - exit(1); + { + const char *err_msg; + (void)PyInitConfig_GetError(config, &err_msg); + printf("Python init failed: %s\n", err_msg); + exit(1); + } } From 55c4f4c30b49734ce35dc88139b8b4fdc94c66fd Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:11:02 +0100 Subject: [PATCH 183/247] gh-125514: fix bug in test_traceback utility. Specify exception types in except: clauses (#125516) --- Lib/test/test_traceback.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 455fea034198a6..77ef0c5b3c480d 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -150,7 +150,7 @@ def test_no_caret_with_no_debug_ranges_flag_python_traceback(self): import traceback try: x = 1 / 0 - except: + except ZeroDivisionError: traceback.print_exc() """) try: @@ -550,9 +550,10 @@ class PurePythonExceptionFormattingMixin: def get_exception(self, callable, slice_start=0, slice_end=-1): try: callable() - self.fail("No exception thrown.") - except: + except BaseException: return traceback.format_exc().splitlines()[slice_start:slice_end] + else: + self.fail("No exception thrown.") callable_line = get_exception.__code__.co_firstlineno + 2 @@ -2237,7 +2238,7 @@ def test_context_suppression(self): try: try: raise Exception - except: + except Exception: raise ZeroDivisionError from None except ZeroDivisionError as _: e = _ @@ -2589,9 +2590,9 @@ def exc(): try: try: raise EG("eg1", [ValueError(1), TypeError(2)]) - except: + except EG: raise EG("eg2", [ValueError(3), TypeError(4)]) - except: + except EG: raise ImportError(5) expected = ( @@ -2641,7 +2642,7 @@ def exc(): except Exception as e: exc = e raise EG("eg", [VE(1), exc, VE(4)]) - except: + except EG: raise EG("top", [VE(5)]) expected = (f' + Exception Group Traceback (most recent call last):\n' @@ -3454,7 +3455,7 @@ def test_long_context_chain(self): def f(): try: 1/0 - except: + except ZeroDivisionError: f() try: @@ -3558,7 +3559,7 @@ def test_comparison_params_variations(self): def raise_exc(): try: raise ValueError('bad value') - except: + except ValueError: raise def raise_with_locals(): From d3c82b9ccedd77fc302f5ab8ab0220b3372f574c Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Tue, 15 Oct 2024 17:42:16 +0300 Subject: [PATCH 184/247] gh-125512: Revert "gh-124872: Replace enter/exit events with "switched" (#124776)" (#125513) --- Doc/c-api/contextvars.rst | 14 +++-- Include/cpython/context.h | 17 ++++-- Lib/test/test_capi/test_watchers.py | 89 ++++++++++++++-------------- Modules/_testcapi/watchers.c | 79 ++++++++++++------------ Python/context.c | 31 ++++------ Tools/c-analyzer/cpython/ignored.tsv | 4 +- 6 files changed, 117 insertions(+), 117 deletions(-) diff --git a/Doc/c-api/contextvars.rst b/Doc/c-api/contextvars.rst index b7c6550ff34aac..8eba54a80dc80d 100644 --- a/Doc/c-api/contextvars.rst +++ b/Doc/c-api/contextvars.rst @@ -123,10 +123,16 @@ Context object management functions: Enumeration of possible context object watcher events: - - ``Py_CONTEXT_SWITCHED``: The :term:`current context` has switched to a - different context. The object passed to the watch callback is the - now-current :class:`contextvars.Context` object, or None if no context is - current. + - ``Py_CONTEXT_EVENT_ENTER``: A context has been entered, causing the + :term:`current context` to switch to it. The object passed to the watch + callback is the now-current :class:`contextvars.Context` object. Each + enter event will eventually have a corresponding exit event for the same + context object after any subsequently entered contexts have themselves been + exited. + - ``Py_CONTEXT_EVENT_EXIT``: A context is about to be exited, which will + cause the :term:`current context` to switch back to what it was before the + context was entered. The object passed to the watch callback is the + still-current :class:`contextvars.Context` object. .. versionadded:: 3.14 diff --git a/Include/cpython/context.h b/Include/cpython/context.h index 3a7a4b459c09ad..3c9be7873b9399 100644 --- a/Include/cpython/context.h +++ b/Include/cpython/context.h @@ -29,11 +29,20 @@ PyAPI_FUNC(int) PyContext_Exit(PyObject *); typedef enum { /* - * The current context has switched to a different context. The object - * passed to the watch callback is the now-current contextvars.Context - * object, or None if no context is current. + * A context has been entered, causing the "current context" to switch to + * it. The object passed to the watch callback is the now-current + * contextvars.Context object. Each enter event will eventually have a + * corresponding exit event for the same context object after any + * subsequently entered contexts have themselves been exited. */ - Py_CONTEXT_SWITCHED = 1, + Py_CONTEXT_EVENT_ENTER, + /* + * A context is about to be exited, which will cause the "current context" + * to switch back to what it was before the context was entered. The + * object passed to the watch callback is the still-current + * contextvars.Context object. + */ + Py_CONTEXT_EVENT_EXIT, } PyContextEvent; /* diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py index 4680d6765de122..f21d2627c6094b 100644 --- a/Lib/test/test_capi/test_watchers.py +++ b/Lib/test/test_capi/test_watchers.py @@ -577,62 +577,68 @@ class TestContextObjectWatchers(unittest.TestCase): def context_watcher(self, which_watcher): wid = _testcapi.add_context_watcher(which_watcher) try: - switches = _testcapi.get_context_switches(which_watcher) - except ValueError: - switches = None - try: - yield switches + yield wid finally: _testcapi.clear_context_watcher(wid) - def assert_event_counts(self, want_0, want_1): - self.assertEqual(len(_testcapi.get_context_switches(0)), want_0) - self.assertEqual(len(_testcapi.get_context_switches(1)), want_1) + def assert_event_counts(self, exp_enter_0, exp_exit_0, + exp_enter_1, exp_exit_1): + self.assertEqual( + exp_enter_0, _testcapi.get_context_watcher_num_enter_events(0)) + self.assertEqual( + exp_exit_0, _testcapi.get_context_watcher_num_exit_events(0)) + self.assertEqual( + exp_enter_1, _testcapi.get_context_watcher_num_enter_events(1)) + self.assertEqual( + exp_exit_1, _testcapi.get_context_watcher_num_exit_events(1)) def test_context_object_events_dispatched(self): # verify that all counts are zero before any watchers are registered - self.assert_event_counts(0, 0) + self.assert_event_counts(0, 0, 0, 0) # verify that all counts remain zero when a context object is # entered and exited with no watchers registered ctx = contextvars.copy_context() - ctx.run(self.assert_event_counts, 0, 0) - self.assert_event_counts(0, 0) + ctx.run(self.assert_event_counts, 0, 0, 0, 0) + self.assert_event_counts(0, 0, 0, 0) # verify counts are as expected when first watcher is registered with self.context_watcher(0): - self.assert_event_counts(0, 0) - ctx.run(self.assert_event_counts, 1, 0) - self.assert_event_counts(2, 0) + self.assert_event_counts(0, 0, 0, 0) + ctx.run(self.assert_event_counts, 1, 0, 0, 0) + self.assert_event_counts(1, 1, 0, 0) # again with second watcher registered with self.context_watcher(1): - self.assert_event_counts(2, 0) - ctx.run(self.assert_event_counts, 3, 1) - self.assert_event_counts(4, 2) + self.assert_event_counts(1, 1, 0, 0) + ctx.run(self.assert_event_counts, 2, 1, 1, 0) + self.assert_event_counts(2, 2, 1, 1) # verify counts are reset and don't change after both watchers are cleared - ctx.run(self.assert_event_counts, 0, 0) - self.assert_event_counts(0, 0) - - def test_callback_error(self): - ctx_outer = contextvars.copy_context() - ctx_inner = contextvars.copy_context() - unraisables = [] - - def _in_outer(): - with self.context_watcher(2): - with catch_unraisable_exception() as cm: - ctx_inner.run(lambda: unraisables.append(cm.unraisable)) - unraisables.append(cm.unraisable) - - ctx_outer.run(_in_outer) - self.assertEqual([x.err_msg for x in unraisables], - ["Exception ignored in Py_CONTEXT_SWITCHED " - f"watcher callback for {ctx!r}" - for ctx in [ctx_inner, ctx_outer]]) - self.assertEqual([str(x.exc_value) for x in unraisables], - ["boom!", "boom!"]) + ctx.run(self.assert_event_counts, 0, 0, 0, 0) + self.assert_event_counts(0, 0, 0, 0) + + def test_enter_error(self): + with self.context_watcher(2): + with catch_unraisable_exception() as cm: + ctx = contextvars.copy_context() + ctx.run(int, 0) + self.assertEqual( + cm.unraisable.err_msg, + "Exception ignored in " + f"Py_CONTEXT_EVENT_EXIT watcher callback for {ctx!r}" + ) + self.assertEqual(str(cm.unraisable.exc_value), "boom!") + + def test_exit_error(self): + ctx = contextvars.copy_context() + def _in_context(stack): + stack.enter_context(self.context_watcher(2)) + + with catch_unraisable_exception() as cm: + with ExitStack() as stack: + ctx.run(_in_context, stack) + self.assertEqual(str(cm.unraisable.exc_value), "boom!") def test_clear_out_of_range_watcher_id(self): with self.assertRaisesRegex(ValueError, r"Invalid context watcher ID -1"): @@ -648,12 +654,5 @@ def test_allocate_too_many_watchers(self): with self.assertRaisesRegex(RuntimeError, r"no more context watcher IDs available"): _testcapi.allocate_too_many_context_watchers() - def test_exit_base_context(self): - ctx = contextvars.Context() - _testcapi.clear_context_stack() - with self.context_watcher(0) as switches: - ctx.run(lambda: None) - self.assertEqual(switches, [ctx, None]) - if __name__ == "__main__": unittest.main() diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index 321d3aeffb6ad1..b4233d07134aea 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -626,12 +626,16 @@ allocate_too_many_func_watchers(PyObject *self, PyObject *args) // Test contexct object watchers #define NUM_CONTEXT_WATCHERS 2 static int context_watcher_ids[NUM_CONTEXT_WATCHERS] = {-1, -1}; -static PyObject *context_switches[NUM_CONTEXT_WATCHERS]; +static int num_context_object_enter_events[NUM_CONTEXT_WATCHERS] = {0, 0}; +static int num_context_object_exit_events[NUM_CONTEXT_WATCHERS] = {0, 0}; static int handle_context_watcher_event(int which_watcher, PyContextEvent event, PyObject *ctx) { - if (event == Py_CONTEXT_SWITCHED) { - PyList_Append(context_switches[which_watcher], ctx); + if (event == Py_CONTEXT_EVENT_ENTER) { + num_context_object_enter_events[which_watcher]++; + } + else if (event == Py_CONTEXT_EVENT_EXIT) { + num_context_object_exit_events[which_watcher]++; } else { return -1; @@ -663,28 +667,31 @@ error_context_event_handler(PyContextEvent event, PyObject *ctx) { static PyObject * add_context_watcher(PyObject *self, PyObject *which_watcher) { - static const PyContext_WatchCallback callbacks[] = { - &first_context_watcher_callback, - &second_context_watcher_callback, - &error_context_event_handler, - }; + int watcher_id; assert(PyLong_Check(which_watcher)); long which_l = PyLong_AsLong(which_watcher); - if (which_l < 0 || which_l >= (long)Py_ARRAY_LENGTH(callbacks)) { + if (which_l == 0) { + watcher_id = PyContext_AddWatcher(first_context_watcher_callback); + context_watcher_ids[0] = watcher_id; + num_context_object_enter_events[0] = 0; + num_context_object_exit_events[0] = 0; + } + else if (which_l == 1) { + watcher_id = PyContext_AddWatcher(second_context_watcher_callback); + context_watcher_ids[1] = watcher_id; + num_context_object_enter_events[1] = 0; + num_context_object_exit_events[1] = 0; + } + else if (which_l == 2) { + watcher_id = PyContext_AddWatcher(error_context_event_handler); + } + else { PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l); return NULL; } - int watcher_id = PyContext_AddWatcher(callbacks[which_l]); if (watcher_id < 0) { return NULL; } - if (which_l >= 0 && which_l < NUM_CONTEXT_WATCHERS) { - context_watcher_ids[which_l] = watcher_id; - Py_XSETREF(context_switches[which_l], PyList_New(0)); - if (context_switches[which_l] == NULL) { - return NULL; - } - } return PyLong_FromLong(watcher_id); } @@ -701,7 +708,8 @@ clear_context_watcher(PyObject *self, PyObject *watcher_id) for (int i = 0; i < NUM_CONTEXT_WATCHERS; i++) { if (watcher_id_l == context_watcher_ids[i]) { context_watcher_ids[i] = -1; - Py_CLEAR(context_switches[i]); + num_context_object_enter_events[i] = 0; + num_context_object_exit_events[i] = 0; } } } @@ -709,34 +717,21 @@ clear_context_watcher(PyObject *self, PyObject *watcher_id) } static PyObject * -clear_context_stack(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) +get_context_watcher_num_enter_events(PyObject *self, PyObject *watcher_id) { - PyThreadState *tstate = PyThreadState_Get(); - if (tstate->context == NULL) { - Py_RETURN_NONE; - } - if (((PyContext *)tstate->context)->ctx_prev != NULL) { - PyErr_SetString(PyExc_RuntimeError, - "must first exit all non-base contexts"); - return NULL; - } - Py_CLEAR(tstate->context); - Py_RETURN_NONE; + assert(PyLong_Check(watcher_id)); + long watcher_id_l = PyLong_AsLong(watcher_id); + assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); + return PyLong_FromLong(num_context_object_enter_events[watcher_id_l]); } static PyObject * -get_context_switches(PyObject *Py_UNUSED(self), PyObject *watcher_id) +get_context_watcher_num_exit_events(PyObject *self, PyObject *watcher_id) { assert(PyLong_Check(watcher_id)); long watcher_id_l = PyLong_AsLong(watcher_id); - if (watcher_id_l < 0 || watcher_id_l >= NUM_CONTEXT_WATCHERS) { - PyErr_Format(PyExc_ValueError, "invalid watcher %ld", watcher_id_l); - return NULL; - } - if (context_switches[watcher_id_l] == NULL) { - return PyList_New(0); - } - return Py_NewRef(context_switches[watcher_id_l]); + assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); + return PyLong_FromLong(num_context_object_exit_events[watcher_id_l]); } static PyObject * @@ -840,8 +835,10 @@ static PyMethodDef test_methods[] = { // Code object watchers. {"add_context_watcher", add_context_watcher, METH_O, NULL}, {"clear_context_watcher", clear_context_watcher, METH_O, NULL}, - {"clear_context_stack", clear_context_stack, METH_NOARGS, NULL}, - {"get_context_switches", get_context_switches, METH_O, NULL}, + {"get_context_watcher_num_enter_events", + get_context_watcher_num_enter_events, METH_O, NULL}, + {"get_context_watcher_num_exit_events", + get_context_watcher_num_exit_events, METH_O, NULL}, {"allocate_too_many_context_watchers", (PyCFunction) allocate_too_many_context_watchers, METH_NOARGS, NULL}, {NULL}, diff --git a/Python/context.c b/Python/context.c index 95aa82206270f9..8bc487a33c890b 100644 --- a/Python/context.c +++ b/Python/context.c @@ -102,8 +102,10 @@ PyContext_CopyCurrent(void) static const char * context_event_name(PyContextEvent event) { switch (event) { - case Py_CONTEXT_SWITCHED: - return "Py_CONTEXT_SWITCHED"; + case Py_CONTEXT_EVENT_ENTER: + return "Py_CONTEXT_EVENT_ENTER"; + case Py_CONTEXT_EVENT_EXIT: + return "Py_CONTEXT_EVENT_EXIT"; default: return "?"; } @@ -113,13 +115,6 @@ context_event_name(PyContextEvent event) { static void notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyObject *ctx) { - if (ctx == NULL) { - // This will happen after exiting the last context in the stack, which - // can occur if context_get was never called before entering a context - // (e.g., called `contextvars.Context().run()` on a fresh thread, as - // PyContext_Enter doesn't call context_get). - ctx = Py_None; - } assert(Py_REFCNT(ctx) > 0); PyInterpreterState *interp = ts->interp; assert(interp->_initialized); @@ -180,16 +175,6 @@ PyContext_ClearWatcher(int watcher_id) } -static inline void -context_switched(PyThreadState *ts) -{ - ts->context_ver++; - // ts->context is used instead of context_get() because context_get() might - // throw if ts->context is NULL. - notify_context_watchers(ts, Py_CONTEXT_SWITCHED, ts->context); -} - - static int _PyContext_Enter(PyThreadState *ts, PyObject *octx) { @@ -206,7 +191,9 @@ _PyContext_Enter(PyThreadState *ts, PyObject *octx) ctx->ctx_entered = 1; ts->context = Py_NewRef(ctx); - context_switched(ts); + ts->context_ver++; + + notify_context_watchers(ts, Py_CONTEXT_EVENT_ENTER, octx); return 0; } @@ -240,11 +227,13 @@ _PyContext_Exit(PyThreadState *ts, PyObject *octx) return -1; } + notify_context_watchers(ts, Py_CONTEXT_EVENT_EXIT, octx); Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev); + ts->context_ver++; ctx->ctx_prev = NULL; ctx->ctx_entered = 0; - context_switched(ts); + return 0; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 2605825d3d0078..e6c599a2ac4a46 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -455,8 +455,8 @@ Modules/_testcapi/watchers.c - pyfunc_watchers - Modules/_testcapi/watchers.c - func_watcher_ids - Modules/_testcapi/watchers.c - func_watcher_callbacks - Modules/_testcapi/watchers.c - context_watcher_ids - -Modules/_testcapi/watchers.c - context_switches - -Modules/_testcapi/watchers.c add_context_watcher callbacks - +Modules/_testcapi/watchers.c - num_context_object_enter_events - +Modules/_testcapi/watchers.c - num_context_object_exit_events - Modules/_testcapimodule.c - BasicStaticTypes - Modules/_testcapimodule.c - num_basic_static_types_used - Modules/_testcapimodule.c - ContainerNoGC_members - From 703227dd021491ceb9343f69fa48f4b6a05adbb3 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 15 Oct 2024 07:51:37 -0700 Subject: [PATCH 185/247] gh-125422: Don't set the caller's f_trace if it's botframe (#125427) --- Lib/bdb.py | 5 +++-- Lib/test/test_bdb.py | 13 +++++++++++++ Lib/test/test_pdb.py | 14 ++++++++++++++ .../2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst | 1 + 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst diff --git a/Lib/bdb.py b/Lib/bdb.py index 666f9714eb9b7a..9755d61dd2696c 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -350,9 +350,10 @@ def _set_caller_tracefunc(self, current_frame): # Issue #13183: pdb skips frames after hitting a breakpoint and running # step commands. # Restore the trace function in the caller (that may not have been set - # for performance reasons) when returning from the current frame. + # for performance reasons) when returning from the current frame, unless + # the caller is the botframe. caller_frame = current_frame.f_back - if caller_frame and not caller_frame.f_trace: + if caller_frame and not caller_frame.f_trace and caller_frame is not self.botframe: caller_frame.f_trace = self.trace_dispatch # Derived classes and clients can call the following methods diff --git a/Lib/test/test_bdb.py b/Lib/test/test_bdb.py index 10c58c04dfd25e..f15dae13eb384e 100644 --- a/Lib/test/test_bdb.py +++ b/Lib/test/test_bdb.py @@ -1217,6 +1217,19 @@ def main(): with TracerRun(self) as tracer: tracer.runcall(tfunc_import) + def test_next_to_botframe(self): + # gh-125422 + # Check that next command won't go to the bottom frame. + code = """ + lno = 2 + """ + self.expect_set = [ + ('line', 2, ''), ('step', ), + ('return', 2, ''), ('next', ), + ] + with TracerRun(self) as tracer: + tracer.run(compile(textwrap.dedent(code), '', 'exec')) + class TestRegressions(unittest.TestCase): def test_format_stack_entry_no_lineno(self): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 46eb00261042bc..3dc65fdfc03409 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3393,6 +3393,20 @@ def test_issue26053(self): self.assertRegex(res, "Restarting .* with arguments:\na b c") self.assertRegex(res, "Restarting .* with arguments:\nd e f") + def test_step_into_botframe(self): + # gh-125422 + # pdb should not be able to step into the botframe (bdb.py) + script = "x = 1" + commands = """ + step + step + step + quit + """ + stdout, _ = self.run_pdb_script(script, commands) + self.assertIn("The program finished", stdout) + self.assertNotIn("bdb.py", stdout) + def test_pdbrc_basic(self): script = textwrap.dedent(""" a = 1 diff --git a/Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst b/Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst new file mode 100644 index 00000000000000..c890ecec8beaf8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst @@ -0,0 +1 @@ +Fixed the bug where :mod:`pdb` and :mod:`bdb` can step into the bottom caller frame. From b903fc38d8ec74f61fb5ca8a3f5fd025915bceac Mon Sep 17 00:00:00 2001 From: Mikhail Efimov Date: Tue, 15 Oct 2024 18:38:19 +0300 Subject: [PATCH 186/247] gh-119786: fix typo in compiler.md (#125456) --- InternalDocs/compiler.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InternalDocs/compiler.md b/InternalDocs/compiler.md index f27e73b274511f..acef6def563154 100644 --- a/InternalDocs/compiler.md +++ b/InternalDocs/compiler.md @@ -515,7 +515,7 @@ Important files Creates C structs corresponding to the ASDL types. Also contains code for marshalling AST nodes (core ASDL types have marshalling code in [Python/asdl.c](https://github.com/python/cpython/blob/main/Python/asdl.c)). - "File automatically generated by + File automatically generated by [Parser/asdl_c.py](https://github.com/python/cpython/blob/main/Parser/asdl_c.py). This file must be committed separately after every grammar change is committed since the ``__version__`` value is set to the latest @@ -572,7 +572,7 @@ Important files * [Include/internal/pycore_ast.h](https://github.com/python/cpython/blob/main/Include/internal/pycore_ast.h) : Contains the actual definitions of the C structs as generated by [Python/Python-ast.c](https://github.com/python/cpython/blob/main/Python/Python-ast.c) - "Automatically generated by + Automatically generated by [Parser/asdl_c.py](https://github.com/python/cpython/blob/main/Parser/asdl_c.py). * [Include/internal/pycore_asdl.h](https://github.com/python/cpython/blob/main/Include/internal/pycore_asdl.h) From c6e8ff86b2bf8cf597622d416f8befae940366fa Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 15 Oct 2024 17:42:55 +0200 Subject: [PATCH 187/247] gh-125451: Skip concurrent.futures test_processes_terminate() (#125533) The test hangs randomly. It tries to serialize local lock and a local function which are not possible. --- Lib/test/test_concurrent_futures/test_shutdown.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/test_concurrent_futures/test_shutdown.py b/Lib/test/test_concurrent_futures/test_shutdown.py index 7a4065afd46fc8..ba3618614a9bf9 100644 --- a/Lib/test/test_concurrent_futures/test_shutdown.py +++ b/Lib/test/test_concurrent_futures/test_shutdown.py @@ -253,6 +253,9 @@ def test_cancel_futures_wait_false(self): class ProcessPoolShutdownTest(ExecutorShutdownTest): + # gh-125451: 'lock' cannot be serialized, the test is broken + # and hangs randomly + @unittest.skipIf(True, "broken test") def test_processes_terminate(self): def acquire_lock(lock): lock.acquire() From bb9604b62ae7f043594ffea9287f9213067cc7fb Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 15 Oct 2024 08:45:23 -0700 Subject: [PATCH 188/247] gh-100141: Allow pdb to deal with empty file (#125425) --- Lib/pdb.py | 3 +-- Lib/test/test_pdb.py | 10 ++++++++++ .../2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index d9aed24bfcd8e7..2b36b1e3fa7cbe 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -429,8 +429,7 @@ def user_call(self, frame, argument_list): def user_line(self, frame): """This function is called when we stop or break at this line.""" if self._wait_for_mainpyfile: - if (self.mainpyfile != self.canonic(frame.f_code.co_filename) - or frame.f_lineno <= 0): + if (self.mainpyfile != self.canonic(frame.f_code.co_filename)): return self._wait_for_mainpyfile = False self.bp_commands(frame) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 3dc65fdfc03409..474d31f1ae03d9 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3999,6 +3999,16 @@ def _create_fake_frozen_module(): # verify that pdb found the source of the "frozen" function self.assertIn('x = "Sentinel string for gh-93696"', stdout, "Sentinel statement not found") + def test_empty_file(self): + script = '' + commands = 'q\n' + # We check that pdb stopped at line 0, but anything reasonable + # is acceptable here, as long as it does not halt + stdout, _ = self.run_pdb_script(script, commands) + self.assertIn('main.py(0)', stdout) + stdout, _ = self.run_pdb_module(script, commands) + self.assertIn('__main__.py(0)', stdout) + def test_non_utf8_encoding(self): script_dir = os.path.join(os.path.dirname(__file__), 'encoded_modules') for filename in os.listdir(script_dir): diff --git a/Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst b/Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst new file mode 100644 index 00000000000000..c366b0ad4040d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst @@ -0,0 +1 @@ +Fixed the bug where :mod:`pdb` will be stuck in an infinite loop when debugging an empty file. From c9826c11db25e81b1a90c837f84074879f1b1126 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 15 Oct 2024 08:48:28 -0700 Subject: [PATCH 189/247] gh-89819: Add argument_default and conflict_handler to add_argument_group() docs (GH-125379) --- Doc/library/argparse.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index d58c75eef3e739..51ab8e29ff96d5 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1808,7 +1808,8 @@ FileType objects Argument groups ^^^^^^^^^^^^^^^ -.. method:: ArgumentParser.add_argument_group(title=None, description=None) +.. method:: ArgumentParser.add_argument_group(title=None, description=None, *, \ + [argument_default], [conflict_handler]) By default, :class:`ArgumentParser` groups command-line arguments into "positional arguments" and "options" when displaying help @@ -1853,6 +1854,11 @@ Argument groups --bar BAR bar help + The optional, keyword-only parameters argument_default_ and conflict_handler_ + allow for finer-grained control of the behavior of the argument group. These + parameters have the same meaning as in the :class:`ArgumentParser` constructor, + but apply specifically to the argument group rather than the entire parser. + Note that any arguments not in your user-defined groups will end up back in the usual "positional arguments" and "optional arguments" sections. From e97910cdb76c1f1dadfc4721b828611e4f4b6449 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:00:04 +0100 Subject: [PATCH 190/247] gh-125522 : add explicit exception types to bare excepts in tests (#125523) --- Lib/test/test_cmd_line_script.py | 2 +- Lib/test/test_coroutines.py | 2 +- Lib/test/test_file.py | 2 +- Lib/test/test_listcomps.py | 4 ++-- Lib/test/test_logging.py | 2 +- Lib/test/test_pdb.py | 4 ++-- Lib/test/test_peepholer.py | 2 +- Lib/test/test_raise.py | 28 +++++++++++++-------------- Lib/test/test_sys_setprofile.py | 14 +++++++------- Lib/test/test_unittest/test_result.py | 14 +++++++------- Lib/test/test_with.py | 2 +- 11 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 3a5a8abf81e43d..f30107225ff612 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -543,7 +543,7 @@ def test_pep_409_verbiage(self): script = textwrap.dedent("""\ try: raise ValueError - except: + except ValueError: raise NameError from None """) with os_helper.temp_dir() as script_dir: diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index a677301c62becc..e6d65e7d90abb1 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1185,7 +1185,7 @@ async def f(): async def g(): try: raise KeyError - except: + except KeyError: return await f() _, result = run_async(g()) diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py index 9df55278693531..1206032a93566e 100644 --- a/Lib/test/test_file.py +++ b/Lib/test/test_file.py @@ -126,7 +126,7 @@ def testMethods(self): # it must also return None if an exception was given try: 1/0 - except: + except ZeroDivisionError: self.assertEqual(self.f.__exit__(*sys.exc_info()), None) def testReadWhenWriting(self): diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 45644d6c092782..cffdeeacc5d73b 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -609,7 +609,7 @@ def test_comp_in_try_except(self): result = snapshot = None try: result = [{func}(value) for value in value] - except: + except ValueError: snapshot = value raise """ @@ -643,7 +643,7 @@ def test_exception_in_post_comp_call(self): value = [1, None] try: [v for v in value].sort() - except: + except TypeError: pass """ self._check_in_scopes(code, {"value": [1, None]}) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index d4ceb7c8dc0b41..e72f222e1c7eeb 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4877,7 +4877,7 @@ def test_formatting(self): r.addHandler(h) try: raise RuntimeError('deliberate mistake') - except: + except RuntimeError: logging.exception('failed', stack_info=True) r.removeHandler(h) h.close() diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 474d31f1ae03d9..084b7cd4cad219 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1081,7 +1081,7 @@ def test_convenience_variables(): ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() ... try: ... raise Exception('test') - ... except: + ... except Exception: ... pass ... return 1 @@ -1153,7 +1153,7 @@ def test_convenience_variables(): Exception('test') (Pdb) next > (5)util_function() - -> except: + -> except Exception: (Pdb) $_exception *** KeyError: '_exception' (Pdb) return diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index dd3eaeb39e7fe3..b143f3d27a1537 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -766,7 +766,7 @@ def test_load_fast_unknown_after_error_2(self): def f(): try: 1 / 0 - except: + except ZeroDivisionError: print(a, b, c, d, e, f, g) a = b = c = d = e = f = g = 1 self.assertInBytecode(f, 'LOAD_FAST_CHECK') diff --git a/Lib/test/test_raise.py b/Lib/test/test_raise.py index 6d26a61bee4292..dcf0753bc828f3 100644 --- a/Lib/test/test_raise.py +++ b/Lib/test/test_raise.py @@ -48,7 +48,7 @@ def test_except_reraise(self): def reraise(): try: raise TypeError("foo") - except: + except TypeError: try: raise KeyError("caught") except KeyError: @@ -60,7 +60,7 @@ def test_finally_reraise(self): def reraise(): try: raise TypeError("foo") - except: + except TypeError: try: raise KeyError("caught") finally: @@ -73,7 +73,7 @@ def nested_reraise(): def reraise(): try: raise TypeError("foo") - except: + except TypeError: nested_reraise() self.assertRaises(TypeError, reraise) @@ -81,7 +81,7 @@ def test_raise_from_None(self): try: try: raise TypeError("foo") - except: + except TypeError: raise ValueError() from None except ValueError as e: self.assertIsInstance(e.__context__, TypeError) @@ -91,7 +91,7 @@ def test_with_reraise1(self): def reraise(): try: raise TypeError("foo") - except: + except TypeError: with Context(): pass raise @@ -101,7 +101,7 @@ def test_with_reraise2(self): def reraise(): try: raise TypeError("foo") - except: + except TypeError: with Context(): raise KeyError("caught") raise @@ -111,7 +111,7 @@ def test_yield_reraise(self): def reraise(): try: raise TypeError("foo") - except: + except TypeError: yield 1 raise g = reraise() @@ -314,7 +314,7 @@ def test_instance_context_instance_raise(self): try: try: raise context - except: + except IndexError: raise OSError() except OSError as e: self.assertIs(e.__context__, context) @@ -326,7 +326,7 @@ def test_class_context_instance_raise(self): try: try: raise context - except: + except IndexError: raise OSError() except OSError as e: self.assertIsNot(e.__context__, context) @@ -339,7 +339,7 @@ def test_class_context_class_raise(self): try: try: raise context - except: + except IndexError: raise OSError except OSError as e: self.assertIsNot(e.__context__, context) @@ -351,7 +351,7 @@ def test_c_exception_context(self): try: try: 1/0 - except: + except ZeroDivisionError: raise OSError except OSError as e: self.assertIsInstance(e.__context__, ZeroDivisionError) @@ -362,7 +362,7 @@ def test_c_exception_raise(self): try: try: 1/0 - except: + except ZeroDivisionError: xyzzy except NameError as e: self.assertIsInstance(e.__context__, ZeroDivisionError) @@ -459,7 +459,7 @@ def f(): try: try: raise ValueError - except: + except ValueError: del g raise KeyError except Exception as e: @@ -475,7 +475,7 @@ class C: def __del__(self): try: 1/0 - except: + except ZeroDivisionError: raise def f(): diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index b2e8e8a15b67ea..311a4d2cafe88d 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -124,7 +124,7 @@ def f(p): def test_caught_exception(self): def f(p): try: 1/0 - except: pass + except ZeroDivisionError: pass f_ident = ident(f) self.check_events(f, [(1, 'call', f_ident), (1, 'return', f_ident), @@ -133,7 +133,7 @@ def f(p): def test_caught_nested_exception(self): def f(p): try: 1/0 - except: pass + except ZeroDivisionError: pass f_ident = ident(f) self.check_events(f, [(1, 'call', f_ident), (1, 'return', f_ident), @@ -156,9 +156,9 @@ def f(p): def g(p): try: f(p) - except: + except ZeroDivisionError: try: f(p) - except: pass + except ZeroDivisionError: pass f_ident = ident(f) g_ident = ident(g) self.check_events(g, [(1, 'call', g_ident), @@ -187,7 +187,7 @@ def g(p): def test_raise_twice(self): def f(p): try: 1/0 - except: 1/0 + except ZeroDivisionError: 1/0 f_ident = ident(f) self.check_events(f, [(1, 'call', f_ident), (1, 'return', f_ident), @@ -196,7 +196,7 @@ def f(p): def test_raise_reraise(self): def f(p): try: 1/0 - except: raise + except ZeroDivisionError: raise f_ident = ident(f) self.check_events(f, [(1, 'call', f_ident), (1, 'return', f_ident), @@ -320,7 +320,7 @@ def f(p): def test_caught_exception(self): def f(p): try: 1/0 - except: pass + except ZeroDivisionError: pass f_ident = ident(f) self.check_events(f, [(1, 'call', f_ident), (1, 'return', f_ident), diff --git a/Lib/test/test_unittest/test_result.py b/Lib/test/test_unittest/test_result.py index 15e3f62ef66a4b..4e5ec54e9c892a 100644 --- a/Lib/test/test_unittest/test_result.py +++ b/Lib/test/test_unittest/test_result.py @@ -186,7 +186,7 @@ def test_1(self): test = Foo('test_1') try: test.fail("foo") - except: + except AssertionError: exc_info_tuple = sys.exc_info() result = unittest.TestResult() @@ -214,7 +214,7 @@ def test_1(self): def get_exc_info(): try: test.fail("foo") - except: + except AssertionError: return sys.exc_info() exc_info_tuple = get_exc_info() @@ -241,9 +241,9 @@ def get_exc_info(): try: try: test.fail("foo") - except: + except AssertionError: raise ValueError(42) - except: + except ValueError: return sys.exc_info() exc_info_tuple = get_exc_info() @@ -271,7 +271,7 @@ def get_exc_info(): loop.__cause__ = loop loop.__context__ = loop raise loop - except: + except Exception: return sys.exc_info() exc_info_tuple = get_exc_info() @@ -300,7 +300,7 @@ def get_exc_info(): ex1.__cause__ = ex2 ex2.__context__ = ex1 raise C - except: + except Exception: return sys.exc_info() exc_info_tuple = get_exc_info() @@ -345,7 +345,7 @@ def test_1(self): test = Foo('test_1') try: raise TypeError() - except: + except TypeError: exc_info_tuple = sys.exc_info() result = unittest.TestResult() diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py index 839cdec68d573e..e3e2de09496728 100644 --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -719,7 +719,7 @@ def testExceptionInExprList(self): try: with self.Dummy() as a, self.InitRaises(): pass - except: + except RuntimeError: pass self.assertTrue(a.enter_called) self.assertTrue(a.exit_called) From 54c6fcbefd33a8d8bf8c004cf1aad3be3d37b933 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 15 Oct 2024 12:09:35 -0400 Subject: [PATCH 191/247] gh-124375: Avoid calling `_PyMem_ProcessDelayed` on other thread states (#124459) This fixes a crash when running the PyO3 test suite on the free-threaded build. The `qsbr` field is initialized after the `PyThreadState` is added to the interpreter's linked list -- it might still be NULL. Instead, we "steal" the queue of to-be-freed memory blocks. This is always initialized (possibly empty) and protected by the stop the world pause. --- ...4-10-15-15-29-41.gh-issue-124375.wNrWVa.rst | 1 + Python/gc_free_threading.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst new file mode 100644 index 00000000000000..4bd17a6e683bc7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst @@ -0,0 +1 @@ +Fix a crash in the free threading build when the GC runs concurrently with a new thread starting. diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 38564d9d9b0058..3814cd46e2b440 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -420,18 +420,24 @@ merge_queued_objects(_PyThreadStateImpl *tstate, struct collection_state *state) static void process_delayed_frees(PyInterpreterState *interp) { - // In STW status, we can observe the latest write sequence by - // advancing the write sequence immediately. + // While we are in a "stop the world" pause, we can observe the latest + // write sequence by advancing the write sequence immediately. _Py_qsbr_advance(&interp->qsbr); _PyThreadStateImpl *current_tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); _Py_qsbr_quiescent_state(current_tstate->qsbr); + + // Merge the queues from other threads into our own queue so that we can + // process all of the pending delayed free requests at once. HEAD_LOCK(&_PyRuntime); - PyThreadState *tstate = interp->threads.head; - while (tstate != NULL) { - _PyMem_ProcessDelayed(tstate); - tstate = (PyThreadState *)tstate->next; + for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) { + _PyThreadStateImpl *other = (_PyThreadStateImpl *)p; + if (other != current_tstate) { + llist_concat(¤t_tstate->mem_free_queue, &other->mem_free_queue); + } } HEAD_UNLOCK(&_PyRuntime); + + _PyMem_ProcessDelayed((PyThreadState *)current_tstate); } // Subtract an incoming reference from the computed "gc_refs" refcount. From aac89b54c5ee03c4d64fbdfbb6ea3001e26aa83a Mon Sep 17 00:00:00 2001 From: Mikhail Efimov Date: Tue, 15 Oct 2024 19:17:10 +0300 Subject: [PATCH 192/247] gh-125206: Bug in ctypes with old libffi is fixed (#125322) Workaround for old libffi versions is added. Module ctypes now supports C11 double complex only with libffi >= 3.3.0. Co-authored-by: Sergey B Kirpichev --- Lib/test/test_ctypes/test_libc.py | 2 +- ...-10-11-18-03-05.gh-issue-125206.pWRRK6.rst | 2 + Modules/_ctypes/_ctypes.c | 2 +- Modules/_ctypes/_ctypes_test.c | 6 +- Modules/_ctypes/callproc.c | 4 +- Modules/_ctypes/cfield.c | 8 +-- Modules/_ctypes/ctypes.h | 6 +- configure | 64 +++++++++++++++++++ configure.ac | 40 ++++++++++++ pyconfig.h.in | 3 + 10 files changed, 121 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index cab3cc9f46003a..df7dbc0ae264a0 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -23,7 +23,7 @@ def test_sqrt(self): self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), - "requires C11 complex type") + "requires C11 complex type and libffi >= 3.3.0") def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex diff --git a/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst b/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst new file mode 100644 index 00000000000000..ef7975ebcb376b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst @@ -0,0 +1,2 @@ +Workaround for old libffi versions is added. Module ctypes supports +:c:expr:`double complex` only with libffi >= 3.3.0. Patch by Mikhail Efimov. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 8435ee4090b9e5..d6a5b75a03d3fe 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1747,7 +1747,7 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCEFfuzZqQPXOv?g"; #else static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 5142bb81cf685c..7bac592fd38fb9 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,9 +13,7 @@ #include -#include // FFI_TARGET_HAS_COMPLEX_TYPE - -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) # include "../_complex.h" // csqrt() # undef I // for _ctypes_test_generated.c.h #endif @@ -449,7 +447,7 @@ EXPORT(double) my_sqrt(double a) return sqrt(a); } -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index fd89d9c67b3fc0..5ac9cf16681645 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -105,7 +105,7 @@ module _ctypes #include "pycore_global_objects.h"// _Py_ID() #include "pycore_traceback.h" // _PyTraceback_Add() -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) #include "../_complex.h" // complex #endif @@ -655,7 +655,7 @@ union result { double d; float f; void *p; -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) double complex C; float complex E; long double complex F; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 53a946e750b866..3220852c8398e0 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -14,7 +14,7 @@ #include #include "ctypes.h" -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) # include "../_complex.h" // complex #endif @@ -972,7 +972,7 @@ d_get(void *ptr, Py_ssize_t size) return PyFloat_FromDouble(val); } -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { @@ -1545,7 +1545,7 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) { 'C', C_set, C_get, NULL}, { 'E', E_set, E_get, NULL}, { 'F', F_set, F_get, NULL}, @@ -1600,7 +1600,7 @@ _ctypes_init_fielddesc(void) case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'c': fd->pffi_type = &ffi_type_schar; break; case 'd': fd->pffi_type = &ffi_type_double; break; -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) case 'C': fd->pffi_type = &ffi_type_complex_double; break; case 'E': fd->pffi_type = &ffi_type_complex_float; break; case 'F': fd->pffi_type = &ffi_type_complex_longdouble; break; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 738dcd1aaf8a01..7e0804054cded4 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -2,12 +2,10 @@ # include #endif -#include // FFI_TARGET_HAS_COMPLEX_TYPE - #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) # include "../_complex.h" // complex #endif @@ -388,7 +386,7 @@ struct tagPyCArgObject { double d; float f; void *p; -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) +#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) double complex C; float complex E; long double complex F; diff --git a/configure b/configure index be119f108a060b..17c70d25f9e70c 100755 --- a/configure +++ b/configure @@ -15050,6 +15050,70 @@ LIBS=$save_LIBS +fi + +# Check for libffi with real complex double support. +# This is a workaround, since FFI_TARGET_HAS_COMPLEX_TYPE was defined in libffi v3.2.1, +# but real support was provided only in libffi v3.3.0. +# See https://github.com/python/cpython/issues/125206 for more details. +# +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking libffi has complex type support" >&5 +printf %s "checking libffi has complex type support... " >&6; } +if test ${ac_cv_ffi_complex_double_supported+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_cc="$CC" +CC="$CC -lffi" +if test "$cross_compiling" = yes +then : + ac_cv_ffi_complex_double_supported=no +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +int z_is_expected(double complex z) +{ + const double complex expected = CMPLX(1.25, -0.5); + return z == expected; +} +int main(void) +{ + double complex z = 1.25 - 0.5 * I; + ffi_type *args[1] = {&ffi_type_complex_double}; + void *values[1] = {&z}; + ffi_cif cif; + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_sint, args) != FFI_OK) + { + return 2; + } + ffi_arg rc; + ffi_call(&cif, FFI_FN(z_is_expected), &rc, values); + return !rc; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + ac_cv_ffi_complex_double_supported=yes +else $as_nop + ac_cv_ffi_complex_double_supported=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +CC="$ac_save_cc" +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_ffi_complex_double_supported" >&5 +printf "%s\n" "$ac_cv_ffi_complex_double_supported" >&6; } +if test "$ac_cv_ffi_complex_double_supported" = "yes"; then + +printf "%s\n" "#define Py_FFI_SUPPORT_C_COMPLEX 1" >>confdefs.h + fi # Check for use of the system libmpdec library diff --git a/configure.ac b/configure.ac index 582851695e400f..56daa8b0f79bc0 100644 --- a/configure.ac +++ b/configure.ac @@ -4089,6 +4089,46 @@ AS_VAR_IF([have_libffi], [yes], [ ]) ]) +# Check for libffi with real complex double support. +# This is a workaround, since FFI_TARGET_HAS_COMPLEX_TYPE was defined in libffi v3.2.1, +# but real support was provided only in libffi v3.3.0. +# See https://github.com/python/cpython/issues/125206 for more details. +# +AC_CACHE_CHECK([libffi has complex type support], [ac_cv_ffi_complex_double_supported], +[ac_save_cc="$CC" +CC="$CC -lffi" +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +int z_is_expected(double complex z) +{ + const double complex expected = CMPLX(1.25, -0.5); + return z == expected; +} +int main(void) +{ + double complex z = 1.25 - 0.5 * I; + ffi_type *args[1] = {&ffi_type_complex_double}; + void *values[1] = {&z}; + ffi_cif cif; + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_sint, args) != FFI_OK) + { + return 2; + } + ffi_arg rc; + ffi_call(&cif, FFI_FN(z_is_expected), &rc, values); + return !rc; +} +]])], [ac_cv_ffi_complex_double_supported=yes], +[ac_cv_ffi_complex_double_supported=no], +[ac_cv_ffi_complex_double_supported=no]) +CC="$ac_save_cc"]) +if test "$ac_cv_ffi_complex_double_supported" = "yes"; then + AC_DEFINE([Py_FFI_SUPPORT_C_COMPLEX], [1], + [Defined if _Complex C type can be used with libffi.]) +fi + # Check for use of the system libmpdec library AC_MSG_CHECKING([for --with-system-libmpdec]) AC_ARG_WITH( diff --git a/pyconfig.h.in b/pyconfig.h.in index 1947d8ee14f83e..fb9ab1e78dc7e1 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1685,6 +1685,9 @@ /* Defined if Python is built as a shared library. */ #undef Py_ENABLE_SHARED +/* Defined if _Complex C type can be used with libffi. */ +#undef Py_FFI_SUPPORT_C_COMPLEX + /* Define if you want to disable the GIL */ #undef Py_GIL_DISABLED From 206de4155b01f6285c5551d2224391fa1fa0ac14 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Tue, 15 Oct 2024 11:47:20 -0700 Subject: [PATCH 193/247] gh-92953: Improve nextpool/prevpool comment. (gh-125545) The meaning of these links depends on which list the pool is part of. They are only the same size class if on the "usedpools" list. --- Include/internal/pycore_obmalloc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_obmalloc.h b/Include/internal/pycore_obmalloc.h index 9140d8f08f0af1..a7ba8f340737aa 100644 --- a/Include/internal/pycore_obmalloc.h +++ b/Include/internal/pycore_obmalloc.h @@ -255,8 +255,8 @@ struct pool_header { union { pymem_block *_padding; uint count; } ref; /* number of allocated blocks */ pymem_block *freeblock; /* pool's free list head */ - struct pool_header *nextpool; /* next pool of this size class */ - struct pool_header *prevpool; /* previous pool "" */ + struct pool_header *nextpool; /* see "Pool table" for meaning */ + struct pool_header *prevpool; /* " */ uint arenaindex; /* index into arenas of base adr */ uint szidx; /* block size class index */ uint nextoffset; /* bytes to virgin block */ From 3ea488aac44887a7cdb30be69580c81a0ca6afe2 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 15 Oct 2024 15:06:41 -0400 Subject: [PATCH 194/247] gh-124218: Use per-thread refcounts for code objects (#125216) Use per-thread refcounting for the reference from function objects to their corresponding code object. This can be a source of contention when frequently creating nested functions. Deferred refcounting alone isn't a great fit here because these references are on the heap and may be modified by other libraries. --- Include/cpython/code.h | 1 + Include/cpython/object.h | 2 +- Include/internal/pycore_object.h | 84 +++++++++++++++++++----------- Include/internal/pycore_uniqueid.h | 6 +-- Objects/codeobject.c | 6 ++- Objects/funcobject.c | 8 +-- Objects/typeobject.c | 4 +- Python/gc_free_threading.c | 13 ++--- Python/pylifecycle.c | 2 +- Python/pystate.c | 2 +- Python/uniqueid.c | 67 +++++++++++++++--------- 11 files changed, 119 insertions(+), 76 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 03622698113ee7..af9149b9c38e62 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -132,6 +132,7 @@ typedef struct { _PyCoCached *_co_cached; /* cached co_* attributes */ \ uintptr_t _co_instrumentation_version; /* current instrumentation version */ \ _PyCoMonitoringData *_co_monitoring; /* Monitoring data */ \ + Py_ssize_t _co_unique_id; /* ID used for per-thread refcounting */ \ int _co_firsttraceable; /* index of first traceable instruction */ \ /* Scratch space for extra data relating to the code object. \ Type is a void* to keep the format private in codeobject.c to force \ diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 9d092749b90096..f0f61796cd3ec8 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -272,7 +272,7 @@ typedef struct _heaptypeobject { void *ht_token; // Storage for the "Py_tp_token" slot struct _specialization_cache _spec_cache; // For use by the specializer. #ifdef Py_GIL_DISABLED - Py_ssize_t unique_id; // ID used for thread-local refcounting + Py_ssize_t unique_id; // ID used for per-thread refcounting #endif /* here are optional user slots, followed by the members. */ } PyHeapTypeObject; diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 8832692d03c29e..ad1a7d7e120519 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -14,7 +14,7 @@ extern "C" { #include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_PTR_RELAXED #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_uniqueid.h" // _PyType_IncrefSlow +#include "pycore_uniqueid.h" // _PyObject_ThreadIncrefSlow() // This value is added to `ob_ref_shared` for objects that use deferred // reference counting so that they are not immediately deallocated when the @@ -291,7 +291,31 @@ extern bool _PyRefchain_IsTraced(PyInterpreterState *interp, PyObject *obj); #ifndef Py_GIL_DISABLED # define _Py_INCREF_TYPE Py_INCREF # define _Py_DECREF_TYPE Py_DECREF +# define _Py_INCREF_CODE Py_INCREF +# define _Py_DECREF_CODE Py_DECREF #else +static inline void +_Py_THREAD_INCREF_OBJECT(PyObject *obj, Py_ssize_t unique_id) +{ + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); + + // Unsigned comparison so that `unique_id=-1`, which indicates that + // per-thread refcounting has been disabled on this object, is handled by + // the "else". + if ((size_t)unique_id < (size_t)tstate->refcounts.size) { +# ifdef Py_REF_DEBUG + _Py_INCREF_IncRefTotal(); +# endif + _Py_INCREF_STAT_INC(); + tstate->refcounts.values[unique_id]++; + } + else { + // The slow path resizes the per-thread refcount array if necessary. + // It handles the unique_id=-1 case to keep the inlinable function smaller. + _PyObject_ThreadIncrefSlow(obj, unique_id); + } +} + static inline void _Py_INCREF_TYPE(PyTypeObject *type) { @@ -308,29 +332,38 @@ _Py_INCREF_TYPE(PyTypeObject *type) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Warray-bounds" #endif + _Py_THREAD_INCREF_OBJECT((PyObject *)type, ((PyHeapTypeObject *)type)->unique_id); +#if defined(__GNUC__) && __GNUC__ >= 11 +# pragma GCC diagnostic pop +#endif +} + +static inline void +_Py_INCREF_CODE(PyCodeObject *co) +{ + _Py_THREAD_INCREF_OBJECT((PyObject *)co, co->_co_unique_id); +} +static inline void +_Py_THREAD_DECREF_OBJECT(PyObject *obj, Py_ssize_t unique_id) +{ _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); - PyHeapTypeObject *ht = (PyHeapTypeObject *)type; // Unsigned comparison so that `unique_id=-1`, which indicates that - // per-thread refcounting has been disabled on this type, is handled by + // per-thread refcounting has been disabled on this object, is handled by // the "else". - if ((size_t)ht->unique_id < (size_t)tstate->refcounts.size) { + if ((size_t)unique_id < (size_t)tstate->refcounts.size) { # ifdef Py_REF_DEBUG - _Py_INCREF_IncRefTotal(); + _Py_DECREF_DecRefTotal(); # endif - _Py_INCREF_STAT_INC(); - tstate->refcounts.values[ht->unique_id]++; + _Py_DECREF_STAT_INC(); + tstate->refcounts.values[unique_id]--; } else { - // The slow path resizes the thread-local refcount array if necessary. - // It handles the unique_id=-1 case to keep the inlinable function smaller. - _PyType_IncrefSlow(ht); + // Directly decref the object if the id is not assigned or if + // per-thread refcounting has been disabled on this object. + Py_DECREF(obj); } - -#if defined(__GNUC__) && __GNUC__ >= 11 -# pragma GCC diagnostic pop -#endif } static inline void @@ -341,25 +374,14 @@ _Py_DECREF_TYPE(PyTypeObject *type) _Py_DECREF_IMMORTAL_STAT_INC(); return; } - - _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); PyHeapTypeObject *ht = (PyHeapTypeObject *)type; + _Py_THREAD_DECREF_OBJECT((PyObject *)type, ht->unique_id); +} - // Unsigned comparison so that `unique_id=-1`, which indicates that - // per-thread refcounting has been disabled on this type, is handled by - // the "else". - if ((size_t)ht->unique_id < (size_t)tstate->refcounts.size) { -# ifdef Py_REF_DEBUG - _Py_DECREF_DecRefTotal(); -# endif - _Py_DECREF_STAT_INC(); - tstate->refcounts.values[ht->unique_id]--; - } - else { - // Directly decref the type if the type id is not assigned or if - // per-thread refcounting has been disabled on this type. - Py_DECREF(type); - } +static inline void +_Py_DECREF_CODE(PyCodeObject *co) +{ + _Py_THREAD_DECREF_OBJECT((PyObject *)co, co->_co_unique_id); } #endif diff --git a/Include/internal/pycore_uniqueid.h b/Include/internal/pycore_uniqueid.h index 8f3b4418408cf8..ad5dd38ea08483 100644 --- a/Include/internal/pycore_uniqueid.h +++ b/Include/internal/pycore_uniqueid.h @@ -49,7 +49,7 @@ struct _Py_unique_id_pool { extern Py_ssize_t _PyObject_AssignUniqueId(PyObject *obj); // Releases the allocated id back to the pool. -extern void _PyObject_ReleaseUniqueId(Py_ssize_t unique_id); +extern void _PyObject_DisablePerThreadRefcounting(PyObject *obj); // Merges the per-thread reference counts into the corresponding objects. extern void _PyObject_MergePerThreadRefcounts(_PyThreadStateImpl *tstate); @@ -61,8 +61,8 @@ extern void _PyObject_FinalizePerThreadRefcounts(_PyThreadStateImpl *tstate); // Frees the interpreter's pool of type ids. extern void _PyObject_FinalizeUniqueIdPool(PyInterpreterState *interp); -// Increfs the type, resizing the per-thread refcount array if necessary. -PyAPI_FUNC(void) _PyType_IncrefSlow(PyHeapTypeObject *type); +// Increfs the object, resizing the thread-local refcount array if necessary. +PyAPI_FUNC(void) _PyObject_ThreadIncrefSlow(PyObject *obj, Py_ssize_t unique_id); #endif /* Py_GIL_DISABLED */ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index de80f6cca2904f..9419cfc0048541 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -14,6 +14,7 @@ #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_setobject.h" // _PySet_NextEntry() #include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "pycore_uniqueid.h" // _PyObject_AssignUniqueId() #include "clinic/codeobject.c.h" static const char * @@ -676,7 +677,7 @@ _PyCode_New(struct _PyCodeConstructor *con) } init_code(co, con); #ifdef Py_GIL_DISABLED - _PyObject_SetDeferredRefcount((PyObject *)co); + co->_co_unique_id = _PyObject_AssignUniqueId((PyObject *)co); _PyObject_GC_TRACK(co); #endif Py_XDECREF(replacement_locations); @@ -1864,6 +1865,9 @@ code_dealloc(PyCodeObject *co) Py_XDECREF(co->co_qualname); Py_XDECREF(co->co_linetable); Py_XDECREF(co->co_exceptiontable); +#ifdef Py_GIL_DISABLED + assert(co->_co_unique_id == -1); +#endif if (co->_co_cached != NULL) { Py_XDECREF(co->_co_cached->_co_code); Py_XDECREF(co->_co_cached->_co_cellvars); diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 855d1a2eeca819..6119a96b4aae76 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -116,7 +116,8 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr) op->func_builtins = Py_NewRef(constr->fc_builtins); op->func_name = Py_NewRef(constr->fc_name); op->func_qualname = Py_NewRef(constr->fc_qualname); - op->func_code = Py_NewRef(constr->fc_code); + _Py_INCREF_CODE((PyCodeObject *)constr->fc_code); + op->func_code = constr->fc_code; op->func_defaults = Py_XNewRef(constr->fc_defaults); op->func_kwdefaults = Py_XNewRef(constr->fc_kwdefaults); op->func_closure = Py_XNewRef(constr->fc_closure); @@ -146,7 +147,8 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname PyThreadState *tstate = _PyThreadState_GET(); - PyCodeObject *code_obj = (PyCodeObject *)Py_NewRef(code); + PyCodeObject *code_obj = (PyCodeObject *)code; + _Py_INCREF_CODE(code_obj); assert(code_obj->co_name != NULL); PyObject *name = Py_NewRef(code_obj->co_name); @@ -1094,7 +1096,7 @@ func_dealloc(PyObject *self) } (void)func_clear((PyObject*)op); // These aren't cleared by func_clear(). - Py_DECREF(op->func_code); + _Py_DECREF_CODE((PyCodeObject *)op->func_code); Py_DECREF(op->func_name); Py_DECREF(op->func_qualname); PyObject_GC_Del(op); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6ca4406ec0ea2d..4d843824e1eb00 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5025,7 +5025,7 @@ PyType_FromMetaclass( type->tp_dictoffset = dictoffset; #ifdef Py_GIL_DISABLED - // Assign a type id to enable thread-local refcounting + // Assign a unique id to enable per-thread refcounting res->unique_id = _PyObject_AssignUniqueId((PyObject *)res); #endif @@ -6043,7 +6043,7 @@ type_dealloc(PyObject *self) Py_XDECREF(et->ht_module); PyMem_Free(et->_ht_tpname); #ifdef Py_GIL_DISABLED - _PyObject_ReleaseUniqueId(et->unique_id); + assert(et->unique_id == -1); #endif et->ht_token = NULL; Py_TYPE(type)->tp_free((PyObject *)type); diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 3814cd46e2b440..8558d4555a9a3a 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -15,7 +15,7 @@ #include "pycore_tstate.h" // _PyThreadStateImpl #include "pycore_weakref.h" // _PyWeakref_ClearRef() #include "pydtrace.h" -#include "pycore_uniqueid.h" // _PyType_MergeThreadLocalRefcounts +#include "pycore_uniqueid.h" // _PyObject_MergeThreadLocalRefcounts() #ifdef Py_GIL_DISABLED @@ -215,15 +215,10 @@ disable_deferred_refcounting(PyObject *op) op->ob_gc_bits &= ~_PyGC_BITS_DEFERRED; op->ob_ref_shared -= _Py_REF_SHARED(_Py_REF_DEFERRED, 0); merge_refcount(op, 0); - } - // Heap types also use per-thread refcounting -- disable it here. - if (PyType_Check(op)) { - if (PyType_HasFeature((PyTypeObject *)op, Py_TPFLAGS_HEAPTYPE)) { - PyHeapTypeObject *ht = (PyHeapTypeObject *)op; - _PyObject_ReleaseUniqueId(ht->unique_id); - ht->unique_id = -1; - } + // Heap types and code objects also use per-thread refcounting, which + // should also be disabled when we turn off deferred refcounting. + _PyObject_DisablePerThreadRefcounting(op); } // Generators and frame objects may contain deferred references to other diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ebeee4f41d795d..5fb9c4f7c719fe 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -28,7 +28,7 @@ #include "pycore_sliceobject.h" // _PySlice_Fini() #include "pycore_sysmodule.h" // _PySys_ClearAuditHooks() #include "pycore_traceback.h" // _Py_DumpTracebackThreads() -#include "pycore_uniqueid.h" // _PyType_FinalizeIdPool() +#include "pycore_uniqueid.h" // _PyObject_FinalizeUniqueIdPool() #include "pycore_typeobject.h" // _PyTypes_InitTypes() #include "pycore_typevarobject.h" // _Py_clear_generic_types() #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() diff --git a/Python/pystate.c b/Python/pystate.c index 5d94b7714bd607..e3812cba41d9c2 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -20,7 +20,7 @@ #include "pycore_runtime_init.h" // _PyRuntimeState_INIT #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_obmalloc.h" // _PyMem_obmalloc_state_on_heap() -#include "pycore_uniqueid.h" // _PyType_FinalizeThreadLocalRefcounts() +#include "pycore_uniqueid.h" // _PyObject_FinalizePerThreadRefcounts() /* -------------------------------------------------------------------------- CAUTION diff --git a/Python/uniqueid.c b/Python/uniqueid.c index 9a9ee2f39467b0..0cbb35c6cd2f8b 100644 --- a/Python/uniqueid.c +++ b/Python/uniqueid.c @@ -98,36 +98,60 @@ _PyObject_AssignUniqueId(PyObject *obj) return unique_id; } -void -_PyObject_ReleaseUniqueId(Py_ssize_t unique_id) +static void +release_unique_id(Py_ssize_t unique_id) { PyInterpreterState *interp = _PyInterpreterState_GET(); struct _Py_unique_id_pool *pool = &interp->unique_ids; - if (unique_id < 0) { - // The id is not assigned - return; - } - LOCK_POOL(pool); + assert(unique_id >= 0 && unique_id < pool->size); _Py_unique_id_entry *entry = &pool->table[unique_id]; entry->next = pool->freelist; pool->freelist = entry; UNLOCK_POOL(pool); } +static Py_ssize_t +clear_unique_id(PyObject *obj) +{ + Py_ssize_t id = -1; + if (PyType_Check(obj)) { + if (PyType_HasFeature((PyTypeObject *)obj, Py_TPFLAGS_HEAPTYPE)) { + PyHeapTypeObject *ht = (PyHeapTypeObject *)obj; + id = ht->unique_id; + ht->unique_id = -1; + } + } + else if (PyCode_Check(obj)) { + PyCodeObject *co = (PyCodeObject *)obj; + id = co->_co_unique_id; + co->_co_unique_id = -1; + } + return id; +} + +void +_PyObject_DisablePerThreadRefcounting(PyObject *obj) +{ + Py_ssize_t id = clear_unique_id(obj); + if (id >= 0) { + release_unique_id(id); + } +} + void -_PyType_IncrefSlow(PyHeapTypeObject *type) +_PyObject_ThreadIncrefSlow(PyObject *obj, Py_ssize_t unique_id) { _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); - if (type->unique_id < 0 || resize_local_refcounts(tstate) < 0) { - // just incref the type directly. - Py_INCREF(type); + if (unique_id < 0 || resize_local_refcounts(tstate) < 0) { + // just incref the object directly. + Py_INCREF(obj); return; } - assert(type->unique_id < tstate->refcounts.size); - tstate->refcounts.values[type->unique_id]++; + assert(unique_id < tstate->refcounts.size); + tstate->refcounts.values[unique_id]++; #ifdef Py_REF_DEBUG _Py_IncRefTotal((PyThreadState *)tstate); #endif @@ -179,20 +203,15 @@ _PyObject_FinalizeUniqueIdPool(PyInterpreterState *interp) pool->freelist = next; } - // Now everything non-NULL is a type. Set the type's id to -1 in case it - // outlives the interpreter. + // Now everything non-NULL is a object. Clear their unique ids as the + // object outlives the interpreter. for (Py_ssize_t i = 0; i < pool->size; i++) { PyObject *obj = pool->table[i].obj; pool->table[i].obj = NULL; - if (obj == NULL) { - continue; - } - if (PyType_Check(obj)) { - assert(PyType_HasFeature((PyTypeObject *)obj, Py_TPFLAGS_HEAPTYPE)); - ((PyHeapTypeObject *)obj)->unique_id = -1; - } - else { - Py_UNREACHABLE(); + if (obj != NULL) { + Py_ssize_t id = clear_unique_id(obj); + (void)id; + assert(id == i); } } PyMem_Free(pool->table); From 9c2bb7d551a695f35db953a671a2ddca89426bef Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 15 Oct 2024 12:30:28 -0700 Subject: [PATCH 195/247] gh-125115: Pass unknown pdb command line args to script instead of fail (#125424) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/pdb.py | 30 +++++++++++++++---- Lib/test/test_pdb.py | 21 ++++++++++++- ...-10-14-02-07-44.gh-issue-125115.IOf3ON.rst | 1 + 3 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-14-02-07-44.gh-issue-125115.IOf3ON.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 2b36b1e3fa7cbe..3e5e6088fdcc7e 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -82,6 +82,7 @@ import inspect import textwrap import tokenize +import itertools import traceback import linecache import _colorize @@ -2433,8 +2434,6 @@ def main(): parser.add_argument('-c', '--command', action='append', default=[], metavar='command', dest='commands', help='pdb commands to execute as if given in a .pdbrc file') parser.add_argument('-m', metavar='module', dest='module') - parser.add_argument('args', nargs='*', - help="when -m is not specified, the first arg is the script to debug") if len(sys.argv) == 1: # If no arguments were given (python -m pdb), print the whole help message. @@ -2442,21 +2441,40 @@ def main(): parser.print_help() sys.exit(2) - opts = parser.parse_args() + opts, args = parser.parse_known_args() + + if opts.module: + # If a module is being debugged, we consider the arguments after "-m module" to + # be potential arguments to the module itself. We need to parse the arguments + # before "-m" to check if there is any invalid argument. + # e.g. "python -m pdb -m foo --spam" means passing "--spam" to "foo" + # "python -m pdb --spam -m foo" means passing "--spam" to "pdb" and is invalid + idx = sys.argv.index('-m') + args_to_pdb = sys.argv[1:idx] + # This will raise an error if there are invalid arguments + parser.parse_args(args_to_pdb) + else: + # If a script is being debugged, then pdb expects the script name as the first argument. + # Anything before the script is considered an argument to pdb itself, which would + # be invalid because it's not parsed by argparse. + invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args)) + if invalid_args: + parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") + sys.exit(2) if opts.module: file = opts.module target = _ModuleTarget(file) else: - if not opts.args: + if not args: parser.error("no module or script to run") - file = opts.args.pop(0) + file = args.pop(0) if file.endswith('.pyz'): target = _ZipTarget(file) else: target = _ScriptTarget(file) - sys.argv[:] = [file] + opts.args # Hide "pdb.py" and pdb options from argument list + sys.argv[:] = [file] + args # Hide "pdb.py" and pdb options from argument list # Note on saving/restoring sys.argv: it's a good idea when sys.argv was # modified by the script being debugged. It's a bad idea when it was diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 084b7cd4cad219..456effc010954a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3089,6 +3089,7 @@ def _run_pdb(self, pdb_args, commands, def run_pdb_script(self, script, commands, expected_returncode=0, extra_env=None, + script_args=None, pdbrc=None, remove_home=False): """Run 'script' lines with pdb and the pdb 'commands'.""" @@ -3106,7 +3107,9 @@ def run_pdb_script(self, script, commands, if remove_home: homesave = os.environ.pop('HOME', None) try: - stdout, stderr = self._run_pdb([filename], commands, expected_returncode, extra_env) + if script_args is None: + script_args = [] + stdout, stderr = self._run_pdb([filename] + script_args, commands, expected_returncode, extra_env) finally: if homesave is not None: os.environ['HOME'] = homesave @@ -3559,6 +3562,22 @@ def test_run_module_with_args(self): stdout, _ = self._run_pdb(["-m", "calendar", "1"], commands) self.assertIn("December", stdout) + stdout, _ = self._run_pdb(["-m", "calendar", "--type", "text"], commands) + self.assertIn("December", stdout) + + def test_run_script_with_args(self): + script = """ + import sys + print(sys.argv[1:]) + """ + commands = """ + continue + quit + """ + + stdout, stderr = self.run_pdb_script(script, commands, script_args=["--bar", "foo"]) + self.assertIn("['--bar', 'foo']", stdout) + def test_breakpoint(self): script = """ if __name__ == '__main__': diff --git a/Misc/NEWS.d/next/Library/2024-10-14-02-07-44.gh-issue-125115.IOf3ON.rst b/Misc/NEWS.d/next/Library/2024-10-14-02-07-44.gh-issue-125115.IOf3ON.rst new file mode 100644 index 00000000000000..3583d537a6ec61 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-14-02-07-44.gh-issue-125115.IOf3ON.rst @@ -0,0 +1 @@ +Fixed a bug in :mod:`pdb` where arguments starting with ``-`` can't be passed to the debugged script. From 8cdaca8b25e3354530d66cbccc622e0e914e8e8a Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 15 Oct 2024 22:29:35 +0300 Subject: [PATCH 196/247] Python 3.14.0a1 --- Doc/c-api/init.rst | 6 +- Doc/c-api/long.rst | 2 +- Doc/c-api/unicode.rst | 2 +- Doc/library/ast.rst | 2 +- Doc/library/ctypes.rst | 2 +- Doc/library/dis.rst | 4 +- Doc/library/pathlib.rst | 4 +- Doc/library/symtable.rst | 8 +- Include/patchlevel.h | 4 +- Lib/pydoc_data/topics.py | 1669 +++-- Misc/NEWS.d/3.14.0a1.rst | 6604 +++++++++++++++++ ...-05-11-15-11-30.gh-issue-118943.VI_MnY.rst | 3 - ...-05-13-15-57-58.gh-issue-118836.7yN1iB.rst | 2 - ...-05-17-19-53-27.gh-issue-119132.wepPgM.rst | 2 - ...-05-19-22-54-55.gh-issue-115119.DwMwev.rst | 1 - ...-05-22-13-18-02.gh-issue-119400.WEt83v.rst | 2 - ...-05-29-17-40-50.gh-issue-119729.k0xJ5U.rst | 5 - ...-06-02-13-23-26.gh-issue-113565.8xBlId.rst | 2 - ...-06-09-15-54-22.gh-issue-120291.IpfHzE.rst | 1 - ...-06-11-00-38-05.gh-issue-120326.JHSDF1.rst | 2 - ...-06-18-15-28-25.gh-issue-118943.aie7nn.rst | 3 - ...-06-18-15-32-36.gh-issue-120688.tjIPLD.rst | 3 - ...-06-19-21-05-15.gh-issue-120602.UyDARz.rst | 2 - ...-06-21-09-24-03.gh-issue-120671.Z8sBQB.rst | 1 - ...-06-27-18-03-20.gh-issue-121082.w3AfRx.rst | 1 - ...-07-02-12-42-25.gh-issue-120831.i3eIjg.rst | 1 - ...-07-02-20-16-09.gh-issue-121103.TMef9j.rst | 3 - ...-07-08-01-11-54.gh-issue-121467.3qWRQj.rst | 1 - ...-07-08-14-01-17.gh-issue-121487.ekHmpR.rst | 1 - ...-07-14-01-29-47.gh-issue-121731.RMPGP3.rst | 1 - ...-07-16-12-29-54.gh-issue-120371.E7x858.rst | 2 - ...-07-18-07-53-07.gh-issue-120522.dg3o5A.rst | 2 - ...-07-19-10-14-31.gh-issue-121996.IEb2sz.rst | 2 - ...-08-02-12-59-15.gh-issue-118943.vZQtET.rst | 1 - ...-08-07-00-20-18.gh-issue-116622.U9cxHM.rst | 2 - ...-08-12-15-48-49.gh-issue-122578.YJ3xEa.rst | 1 - ...-08-14-19-17-34.gh-issue-121634.eOMfHG.rst | 1 - ...-08-24-19-09-31.gh-issue-123297.fdtXoe.rst | 2 - ...-09-04-12-01-43.gh-issue-123418.ynzspB.rst | 1 - ...-09-13-17-48-37.gh-issue-124043.Bruxpq.rst | 2 - ...-09-16-09-42-05.gh-issue-124102.Ow254j.rst | 2 - ...-09-23-11-27-25.gh-issue-123990.d6HrYC.rst | 1 - ...-10-13-21-11-30.gh-issue-125269.BC-fdo.rst | 2 - .../2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst | 2 - ...2-08-05-19-41-20.gh-issue-87135.SCNBYj.rst | 15 - ...2-10-01-09-56-27.gh-issue-97588.Gvg54o.rst | 2 - ...-03-10-14-55-51.gh-issue-116560.x2mZaO.rst | 1 - ...-04-10-16-48-04.gh-issue-117511.RZtBRK.rst | 1 - ...-05-08-20-13-00.gh-issue-118789.m88uUa.rst | 2 - ...-05-08-21-57-50.gh-issue-118789.Ni4UQx.rst | 2 - ...-05-08-23-14-06.gh-issue-116984.5sgcDo.rst | 3 - ...-05-10-15-43-14.gh-issue-118771.5KVglT.rst | 3 - ...-05-20-10-35-22.gh-issue-111389.a6axBk.rst | 2 - ...-05-21-11-35-11.gh-issue-119247.U6n6mh.rst | 4 - ...-05-21-18-28-44.gh-issue-119333.OTsYVX.rst | 2 - ...-05-21-19-41-41.gh-issue-119344.QKvzQb.rst | 1 - ...-05-22-17-50-48.gh-issue-119336.ff3qnS.rst | 1 - ...-05-29-09-21-37.gh-issue-119613.J2xfrC.rst | 2 - ...-05-29-21-05-59.gh-issue-119585.Sn7JL3.rst | 5 - ...-05-30-12-51-21.gh-issue-119775.CBq9IG.rst | 2 - ...-06-04-10-58-20.gh-issue-119613.qOr9GF.rst | 2 - ...-06-07-22-12-30.gh-issue-119182.yt8Ar7.rst | 16 - ...-06-08-08-33-40.gh-issue-119771.Oip2dL.rst | 2 - ...4-06-11-21-38-32.gh-issue-70278.WDE4zM.rst | 4 - ...-06-16-22-58-47.gh-issue-120600.TJdf0w.rst | 2 - ...-06-19-17-27-22.gh-issue-120389.GSZeHF.rst | 13 - ...-06-19-21-27-42.gh-issue-120642.UlKClN.rst | 10 - ...-06-21-16-41-21.gh-issue-120858.Z5_-Mn.rst | 3 - ...-06-26-11-29-01.gh-issue-120642.H7P9qK.rst | 3 - ...-07-02-11-03-40.gh-issue-112136.f3fiY8.rst | 3 - ...-07-04-13-23-27.gh-issue-113601.K3RLqp.rst | 2 - ...-07-04-15-41-10.gh-issue-113993.cLSiWV.rst | 12 - ...-07-21-17-40-07.gh-issue-121489.SUMFCr.rst | 1 - ...-07-30-23-48-26.gh-issue-116622.yTTtil.rst | 3 - ...4-07-09-15-55-20.gh-issue-89364.yYYroI.rst | 3 - ...-07-12-13-40-59.gh-issue-121645.96QvD3.rst | 2 - ...-07-27-00-28-35.gh-issue-105201.0-xUWq.rst | 2 - ...-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst | 2 - ...-08-09-13-12-20.gh-issue-122854.-1OgvU.rst | 2 - ...-08-26-13-01-20.gh-issue-100554.0ku85o.rst | 4 - ...-08-29-15-05-19.gh-issue-123465.eqwNWq.rst | 4 - ...-08-29-15-55-55.gh-issue-107954.pr2O50.rst | 8 - ...-08-30-14-02-17.gh-issue-107954.TPvj4u.rst | 18 - ...-09-10-16-54-27.gh-issue-123909.CTGxDR.rst | 3 - ...-09-12-16-16-24.gh-issue-123880.2-8vcj.rst | 2 - ...-09-16-16-21-39.gh-issue-124127.LB8DBU.rst | 3 - ...-09-17-05-23-35.gh-issue-124153.L8TWmx.rst | 2 - ...-09-18-18-40-30.gh-issue-124160.Zy-VKi.rst | 2 - ...-09-24-20-34-21.gh-issue-124296.S4QoS1.rst | 3 - ...-09-25-11-44-02.gh-issue-124502.qWuDjT.rst | 2 - ...-10-03-14-06-08.gh-issue-123961.uwJQTY.rst | 3 - .../2018-10-09-15-14-53.bpo-24766.c_C1Wc.rst | 1 - ...2-07-22-15-56-35.gh-issue-95144.FZYWX-.rst | 2 - ...3-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst | 1 - ...-01-15-18-11-48.gh-issue-113190.OwQX64.rst | 1 - ...-01-15-21-51-26.gh-issue-114091.VOtSJl.rst | 1 - ...-03-19-22-21-22.gh-issue-116022.iyHENN.rst | 1 - ...-03-25-15-07-01.gh-issue-117195.OWakgD.rst | 2 - ...-04-08-13-49-02.gh-issue-117558.9lSEpR.rst | 2 - ...-04-27-18-36-46.gh-issue-115801.SVeHSy.rst | 1 - ...-05-01-05-09-16.gh-issue-117139.t41w_D.rst | 5 - ...-05-07-16-57-56.gh-issue-118561.wNMKVd.rst | 2 - ...-05-08-09-44-15.gh-issue-118767.iFF5F5.rst | 2 - ...-05-09-02-37-25.gh-issue-118750.7aLfT-.rst | 1 - ...-05-09-19-47-12.gh-issue-117657.Vn0Yey.rst | 1 - ...-05-10-19-54-18.gh-issue-118921.O4ztZG.rst | 1 - ...-05-11-21-44-17.gh-issue-118844.q2H_km.rst | 1 - ...-05-15-12-15-58.gh-issue-119057.P3G9G2.rst | 4 - ...-05-16-23-02-03.gh-issue-119049.qpd_S-.rst | 2 - ...-05-20-10-10-51.gh-issue-119180.35xqpu.rst | 2 - ...-05-20-14-57-39.gh-issue-118692.Qadm7F.rst | 1 - ...-05-21-09-46-51.gh-issue-119011.WOe3bu.rst | 2 - ...-05-21-11-27-14.gh-issue-119213.nxjxrt.rst | 3 - ...-05-21-12-17-02.gh-issue-119180.UNDUb9.rst | 2 - ...-05-22-06-22-47.gh-issue-119180.vZMiXm.rst | 1 - ...-05-22-12-49-03.gh-issue-119372.PXig1R.rst | 2 - ...-05-23-06-34-14.gh-issue-119395.z-Hsqb.rst | 2 - ...-05-23-06-34-45.gh-issue-119311.2DBwKR.rst | 2 - ...-05-23-20-17-37.gh-issue-119258.wZFIpt.rst | 3 - ...-05-24-21-04-00.gh-issue-119525.zLFLf1.rst | 2 - ...-05-24-21-16-52.gh-issue-119369.qBThho.rst | 2 - ...-05-25-12-52-25.gh-issue-119560.wSlm8q.rst | 3 - ...-05-25-13-51-48.gh-issue-111999.L0q1gh.rst | 1 - ...-05-25-16-45-27.gh-issue-119548.pqF9Y6.rst | 1 - ...-05-27-19-13-49.gh-issue-109218.-sdDg0.rst | 3 - ...-05-28-22-49-56.gh-issue-119689.VwLFD5.rst | 1 - ...-05-29-18-53-43.gh-issue-119740.zP2JNM.rst | 2 - ...-05-30-04-11-36.gh-issue-118934.fbDqve.rst | 1 - ...-05-30-23-01-00.gh-issue-119821.jPGfvt.rst | 2 - ...-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst | 3 - ...-05-31-12-06-11.gh-issue-119842.tCGVsv.rst | 1 - ...-06-02-06-12-35.gh-issue-119879.Jit951.rst | 1 - ...-06-03-13-25-04.gh-issue-119724.EH1dkA.rst | 3 - ...-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst | 4 - ...-06-05-08-39-40.gh-issue-120080.DJFK11.rst | 2 - ...-06-05-10-32-44.gh-issue-120097.9S2klk.rst | 2 - ...4-06-05-18-29-18.gh-issue-93691.6OautB.rst | 1 - ...-06-07-16-09-04.gh-issue-120225.kuYf9t.rst | 1 - ...-06-07-22-54-15.gh-issue-119726.D9EE-o.rst | 1 - ...-06-09-19-13-38.gh-issue-119666.S0G4rZ.rst | 1 - ...-06-10-10-42-48.gh-issue-120298.napREA.rst | 2 - ...-06-10-15-07-16.gh-issue-120198.WW_pjO.rst | 1 - ...4-06-10-22-30-26.gh-issue-93691.68WOTS.rst | 2 - ...-06-11-12-47-54.gh-issue-120346.hhn_6X.rst | 2 - ...-06-11-17-56-12.gh-issue-120221.si9hM9.rst | 2 - ...-06-12-13-47-25.gh-issue-120397.n-I_cc.rst | 2 - ...-06-12-18-23-15.gh-issue-120380.edtqjq.rst | 3 - ...-06-12-18-50-29.gh-issue-120367.LmXx2y.rst | 2 - ...-06-13-12-17-52.gh-issue-120384.w1UBGl.rst | 3 - ...-06-14-07-52-00.gh-issue-120485.yy4K4b.rst | 1 - ...-06-14-22-02-25.gh-issue-113993.MiA0vX.rst | 5 - ...-06-17-12-20-20.gh-issue-120507.94lz2J.rst | 3 - ...-06-18-21-34-30.gh-issue-120367.zDwffP.rst | 1 - ...-06-18-22-41-05.gh-issue-120722.rS7tkE.rst | 2 - ...-06-19-01-58-54.gh-issue-120437.nCkIoI.rst | 1 - ...-06-19-11-10-50.gh-issue-119462.DpcqSe.rst | 4 - ...-06-19-19-54-35.gh-issue-120754.uF29sj.rst | 1 - ...4-06-19-21-34-21.gh-issue-98442.cqhjkN.rst | 2 - ...-06-24-08-39-23.gh-issue-116017.-Bw2UY.rst | 3 - ...-06-25-16-26-44.gh-issue-119726.WqvHxB.rst | 2 - ...-06-26-13-42-36.gh-issue-113433.xKAtLB.rst | 2 - ...-06-26-14-09-31.gh-issue-120838.nFeTL9.rst | 2 - ...-06-28-10-02-58.gh-issue-121115.EeSLfc.rst | 3 - ...-06-28-18-34-49.gh-issue-119726.Fjv_Ab.rst | 2 - ...-06-28-23-17-22.gh-issue-121381.i2xL7P.rst | 2 - ...-06-29-10-46-14.gh-issue-121130.Rj66Xs.rst | 2 - ...-06-30-03-48-10.gh-issue-121149.lLBMKe.rst | 2 - ...-07-04-23-38-30.gh-issue-121368.m3EF9E.rst | 3 - ...-07-05-11-29-27.gh-issue-121288.lYKYYP.rst | 5 - ...-07-08-02-24-55.gh-issue-121439.jDHod3.rst | 1 - ...-07-08-10-31-08.gh-issue-121012.M5hHk-.rst | 2 - ...-07-08-17-15-14.gh-issue-121497.I8hMDC.rst | 2 - ...-07-09-13-53-18.gh-issue-121499.rpp7il.rst | 2 - ...-07-10-02-02-32.gh-issue-121562.8beIMi.rst | 2 - ...-07-10-15-43-54.gh-issue-117482.5WYaXR.rst | 2 - ...-07-12-18-18-44.gh-issue-121297.67VE7b.rst | 4 - ...-07-13-12-27-31.gh-issue-121657.wgOYLw.rst | 2 - ...-07-15-16-26-32.gh-issue-121794.fhBtiQ.rst | 2 - ...-07-15-20-41-06.gh-issue-121814.oR2ixR.rst | 1 - ...-07-16-15-11-51.gh-issue-121795.xkIHrI.rst | 1 - ...-07-16-18-23-22.gh-issue-121860.-FTauD.rst | 1 - ...4-07-19-09-38-01.gh-issue-99108.qzM6gl.rst | 10 - ...-07-19-15-28-05.gh-issue-122026.sta2Ca.rst | 2 - ...-07-21-01-23-54.gh-issue-122029.gKv-e2.rst | 1 - ...-07-23-11-57-36.gh-issue-122160.HSnrAP.rst | 1 - ...-07-23-23-59-04.gh-issue-122208.z8KHsY.rst | 1 - ...-07-24-17-11-51.gh-issue-122234.VxsP_F.rst | 4 - ...-07-24-22-39-07.gh-issue-122245.LVa9v8.rst | 4 - ...-07-26-14-05-51.gh-issue-122300.SVIF-l.rst | 2 - ...-07-30-11-41-35.gh-issue-122445.Rq0bjS.rst | 1 - ...-08-05-19-04-06.gh-issue-116622.3LWUzE.rst | 1 - ...-08-18-18-25-54.gh-issue-123123.0ZcaEB.rst | 2 - ...-08-20-11-09-16.gh-issue-123048.2TISpv.rst | 2 - ...-08-20-12-29-52.gh-issue-123142.3PXiNb.rst | 2 - ...-08-21-15-22-53.gh-issue-121804.r5K3PS.rst | 2 - ...-08-23-13-08-27.gh-issue-123229.aHm-dw.rst | 2 - ...-08-23-15-59-54.gh-issue-123177.OLcaC5.rst | 2 - ...-08-25-10-54-22.gh-issue-122982.KLD91q.rst | 1 - ...-08-26-00-58-26.gh-issue-123321.ApxcnE.rst | 2 - ...-08-27-13-16-40.gh-issue-123344.56Or78.rst | 1 - ...-09-23-23-06-19.gh-issue-124285.mahGTg.rst | 2 - ...-10-03-22-26-39.gh-issue-124871.tAMF47.rst | 2 - ...-07-13-09-51-44.gh-issue-121609.jWsE5t.rst | 1 - ...-07-15-20-03-29.gh-issue-121295.w53ucI.rst | 2 - ...-07-18-21-19-04.gh-issue-121999.8IBbTK.rst | 2 - ...-07-25-01-45-21.gh-issue-122239.7zh-sW.rst | 3 - ...-07-26-13-56-32.gh-issue-120906.qBh2I9.rst | 1 - ...-07-29-10-55-46.gh-issue-116090.p1MhU0.rst | 2 - ...-07-29-19-20-25.gh-issue-122417.NVgs0a.rst | 4 - ...-08-01-19-13-58.gh-issue-122527.eztso6.rst | 4 - ...-08-05-19-28-12.gh-issue-122697.17MvYl.rst | 2 - ...-08-08-16-02-28.gh-issue-118093.m6Mrvy.rst | 1 - ...-08-10-12-44-03.gh-issue-122888.TUyu9r.rst | 2 - ...-08-12-11-19-37.gh-issue-122907.q68096.rst | 3 - ...-08-12-11-45-47.gh-issue-122821.WnAzTK.rst | 3 - ...-08-14-11-38-56.gh-issue-118093.3BywDP.rst | 5 - ...-08-15-19-28-43.gh-issue-123022.m3EF9E.rst | 2 - ...-08-17-17-26-25.gh-issue-123083.9xWLJ-.rst | 1 - ...-08-19-15-13-13.gh-issue-118093.dLZ8qS.rst | 3 - ...-08-21-08-53-00.gh-issue-115776.9A7Dv_.rst | 2 - ...-08-23-11-26-54.gh-issue-122298.ZMyln4.rst | 3 - ...-08-23-18-31-10.gh-issue-123275.DprIrj.rst | 1 - ...-08-23-21-20-34.gh-issue-123271.xeVViR.rst | 1 - ...-08-25-18-27-49.gh-issue-123177.yLuyqE.rst | 2 - ...-08-27-21-44-14.gh-issue-116017.ZY3yBY.rst | 2 - ...-08-28-22-42-51.gh-issue-123440.yOFB0N.rst | 1 - ...-08-29-13-18-18.gh-issue-123446.KWDrgq.rst | 2 - ...-08-29-19-46-07.gh-issue-123484.rjUn_F.rst | 2 - ...-09-01-00-02-05.gh-issue-123545.8nQNbL.rst | 1 - ...-09-01-12-08-39.gh-issue-123562.aJPKVu.rst | 2 - ...-09-02-17-32-15.gh-issue-119034.HYh5Vj.rst | 2 - ...-09-02-20-36-45.gh-issue-123339.QcmpSs.rst | 3 - ...-09-02-20-39-10.gh-issue-123614.26TMHp.rst | 2 - ...-09-03-13-34-35.gh-issue-123572.uuqoYV.rst | 2 - ...-09-06-14-13-01.gh-issue-119310.WQxyDF.rst | 3 - ...-09-06-19-23-44.gh-issue-120221.giJEDT.rst | 2 - ...4-09-10-13-27-16.gh-issue-77894.ZC-Olu.rst | 4 - ...-09-10-20-25-00.gh-issue-123923.A7uxqa.rst | 4 - ...-09-11-15-48-36.gh-issue-123958.5VW2r0.rst | 1 - ...-09-12-21-53-26.gh-issue-124022.fQzUiW.rst | 1 - ...-09-13-02-25-06.gh-issue-124027.to_9DY.rst | 2 - ...-09-17-22-06-01.gh-issue-124188.aFqNAB.rst | 2 - ...-09-19-13-17-31.gh-issue-122878.4iFpsB.rst | 1 - ...-09-19-16-57-34.gh-issue-119726.DseseK.rst | 2 - ...4-09-23-13-25-27.gh-issue-65961.LDqXV2.rst | 1 - ...-09-23-15-23-14.gh-issue-123856.yrgJ9m.rst | 2 - ...-09-25-11-53-22.gh-issue-124442.EXC1Ve.rst | 2 - ...-09-25-14-45-56.gh-issue-124513.ywiXtr.rst | 2 - ...-09-26-12-19-13.gh-issue-124547.P_SHfU.rst | 3 - ...-09-26-13-25-01.gh-issue-119180.k_JCX0.rst | 2 - ...-09-26-17-55-34.gh-issue-116510.dhn8w8.rst | 3 - ...-09-26-18-21-06.gh-issue-116510.FacUWO.rst | 5 - ...-09-27-17-18-53.gh-issue-124642.OCjhBJ.rst | 1 - ...-09-30-16-39-37.gh-issue-118093.J2A3gz.rst | 2 - ...-10-03-14-39-41.gh-issue-123378.dCxANf.rst | 3 - ...-10-05-23-53-06.gh-issue-125008.ETANpd.rst | 2 - ...-10-07-23-33-18.gh-issue-125039.MKTyNI.rst | 1 - ...-10-10-12-04-56.gh-issue-125174._8h6T7.rst | 4 - ...-10-10-14-47-13.gh-issue-125221.nfSQzT.rst | 2 - ...-10-15-15-29-41.gh-issue-124375.wNrWVa.rst | 1 - .../2018-07-04-20-35-25.bpo-34008.bqecIb.rst | 8 - ...-06-03-22-06-26.gh-issue-119574.Ik9kOO.rst | 1 - ...-06-05-12-36-18.gh-issue-120012.f14DbQ.rst | 3 - ...-07-14-11-48-10.gh-issue-121749.nxHoTk.rst | 1 - ...-07-14-12-25-53.gh-issue-117765.YFMOUv.rst | 1 - ...-07-19-12-22-48.gh-issue-121277.wF_zKd.rst | 2 - ...4-08-01-17-18-21.gh-issue-70870.fZnBM9.rst | 3 - ...-09-11-16-52-08.gh-issue-123976.jhOfNR.rst | 1 - ...-09-19-19-33-25.gh-issue-116622.M65UZ6.rst | 1 - ...-09-24-11-52-36.gh-issue-124457.yrCjSV.rst | 2 - ...-09-27-16-47-48.gh-issue-124720.nVSTVb.rst | 2 - ...-10-07-00-31-17.gh-issue-125018.yKnymn.rst | 4 - ...-10-10-02-56-24.gh-issue-124872.0mDDOq.rst | 3 - ...-06-05-14-54-24.gh-issue-120104.j_thj4.rst | 1 - ...-06-16-21-42-45.gh-issue-120083.nczuyv.rst | 1 - ...4-07-16-16-57-03.gh-issue-78889.U7ghFD.rst | 2 - ...-07-30-18-02-55.gh-issue-122482.TerE0g.rst | 2 - ...-09-21-23-12-18.gh-issue-112938.OeiDru.rst | 1 - ...-10-04-15-34-34.gh-issue-122392.V8K3w2.rst | 2 - .../2018-12-04-07-36-27.bpo-14074.fMLKCu.rst | 2 - ...9-08-27-01-16-50.gh-issue-67693.4NIAiy.rst | 2 - .../2020-03-28-21-00-54.bpo-15987.aBL8XS.rst | 2 - .../2020-12-22-18-08-12.bpo-41843.q9Nh2r.rst | 2 - .../2021-08-24-19-37-46.bpo-44864.KzxaDh.rst | 1 - .../2022-03-10-16-47-57.bpo-45767.ywmyo1.rst | 3 - ...-03-30-18-19-53.gh-issue-103134.bHrn91.rst | 6 - ...3-04-10-00-04-37.gh-issue-87106.UyBnPQ.rst | 3 - ...-04-24-05-34-23.gh-issue-103194.GwBwWL.rst | 4 - ...3-04-26-22-24-17.gh-issue-92081.V8xMot.rst | 1 - ...-04-28-09-54-15.gh-issue-103956.EyLDPS.rst | 1 - ...-06-16-14-52-00.gh-issue-102450.MfeR6A.rst | 2 - ...-06-17-09-07-06.gh-issue-105623.5G06od.rst | 2 - ...-09-19-17-56-24.gh-issue-109109.WJvvX2.rst | 5 - ...-12-12-15-19-58.gh-issue-108172.KyDPuG.rst | 1 - ...-12-14-13-43-27.gh-issue-113008.jWYn8T.rst | 1 - ...-01-12-08-51-03.gh-issue-113978.MqTgB0.rst | 1 - ...-01-14-11-43-31.gh-issue-113878.dmEIN3.rst | 9 - ...-01-18-21-44-23.gh-issue-114264.DBKn29.rst | 1 - ...-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst | 1 - ...-02-27-10-22-15.gh-issue-115937.0cVNur.rst | 3 - ...-03-19-21-41-31.gh-issue-106531.Mgd--6.rst | 6 - ...-04-19-05-58-50.gh-issue-117766.J3xepp.rst | 1 - ...-04-19-14-59-53.gh-issue-118033.amS4Gw.rst | 2 - ...-04-24-16-23-04.gh-issue-110190.TGd5qx.rst | 2 - ...-04-28-19-51-00.gh-issue-118263.Gaap3S.rst | 1 - ...-05-01-22-24-05.gh-issue-110863.GjYBbq.rst | 2 - ...-05-06-17-39-52.gh-issue-118673.sTXBit.rst | 1 - ...-05-07-17-38-53.gh-issue-118714.XXKpVZ.rst | 2 - ...-05-08-09-21-49.gh-issue-118772.c16E8X.rst | 2 - ...-05-08-18-33-07.gh-issue-118507.OCQsAY.rst | 2 - ...4-05-08-18-59-19.gh-issue-78707._Lz1sw.rst | 3 - ...-05-08-19-47-34.gh-issue-101357.e4R_9x.rst | 5 - ...4-05-08-20-41-48.gh-issue-74033.YebHZj.rst | 1 - ...-05-08-21-13-56.gh-issue-118760.mdmH3T.rst | 1 - ...-05-08-21-30-33.gh-issue-118760.XvyMHn.rst | 1 - ...-05-08-23-16-50.gh-issue-118798.Q_ybqP.rst | 2 - ...-05-09-00-52-30.gh-issue-118803.Wv3AvU.rst | 3 - ...-05-09-01-05-52.gh-issue-118805.N7dm07.rst | 3 - ...-05-09-02-43-37.gh-issue-101588.30bNAr.rst | 2 - ...-05-09-08-46-12.gh-issue-118851.aPAoJw.rst | 2 - ...-05-09-11-50-26.gh-issue-118824.-jBJQC.rst | 3 - ...-05-09-12-33-25.gh-issue-118827.JrzHz1.rst | 3 - ...-05-09-21-36-11.gh-issue-118868.uckxxP.rst | 2 - ...-05-10-05-24-32.gh-issue-118895.wUm5r2.rst | 2 - ...-05-10-22-36-01.gh-issue-118928.IW7Ukv.rst | 2 - ...-05-10-22-59-01.gh-issue-118924.9nyvSH.rst | 2 - ...4-05-11-20-23-45.gh-issue-82805.F9bz4J.rst | 5 - ...4-05-12-21-38-42.gh-issue-58933.0kgU2l.rst | 1 - ...4-05-15-01-36-08.gh-issue-73991.CGknDf.rst | 1 - ...-05-16-17-31-46.gh-issue-118643.hAWH4C.rst | 2 - ...-05-17-17-32-12.gh-issue-119113.kEv1Ll.rst | 2 - ...-05-19-12-25-36.gh-issue-119105.VcR4ig.rst | 1 - ...-05-19-13-05-59.gh-issue-119121.P1gnh1.rst | 2 - ...-05-19-18-49-04.gh-issue-119174.5GTv7d.rst | 3 - ...-05-20-13-48-37.gh-issue-119189.dhJVs5.rst | 3 - ...-05-20-20-30-57.gh-issue-111201.DAA5lC.rst | 1 - ...-05-21-19-10-30.gh-issue-115225.eRmfJH.rst | 1 - ...-05-21-20-13-23.gh-issue-118911.iG8nMq.rst | 5 - ...-05-21-23-39-22.gh-issue-118830.YTqvEo.rst | 1 - ...-05-22-21-20-43.gh-issue-118894.xHdxR_.rst | 1 - ...-05-23-11-52-36.gh-issue-117398.2FG1Mk.rst | 3 - ...-05-23-15-48-17.gh-issue-119461.82KqUW.rst | 1 - ...-05-23-22-29-59.gh-issue-119443.KAGz6S.rst | 2 - ...-05-24-04-05-37.gh-issue-119105.aDSRFn.rst | 1 - ...4-05-24-11-47-08.gh-issue-69214.Grl6zF.rst | 3 - ...-05-24-14-32-24.gh-issue-119506.-nMNqq.rst | 1 - ...-05-24-21-54-55.gh-issue-113892.JKDFqq.rst | 3 - ...-05-25-00-54-26.gh-issue-119127.LpPvag.rst | 2 - ...-05-25-07-25-07.gh-issue-117865.1A0Xpi.rst | 2 - ...-05-25-10-40-38.gh-issue-118908.XcZiq4.rst | 2 - ...-05-25-20-15-26.gh-issue-119555.mvHbEL.rst | 2 - ...-05-25-20-20-42.gh-issue-119562.DyplWc.rst | 3 - ...-05-26-21-28-11.gh-issue-119588.wlLBK5.rst | 1 - ...-05-26-22-22-51.gh-issue-119594.fnQNM8.rst | 1 - ...4-05-28-00-56-59.gh-issue-89727._bxoL3.rst | 3 - ...-05-28-12-15-03.gh-issue-119118.FMKz1F.rst | 2 - ...4-05-29-12-42-40.gh-issue-93963.cb1oJS.rst | 2 - ...4-05-29-20-42-17.gh-issue-89727.5lPTTW.rst | 3 - ...-05-29-21-50-05.gh-issue-119577.S3BlKJ.rst | 4 - ...4-05-30-21-37-05.gh-issue-89727.D6S9ig.rst | 2 - ...-05-31-12-57-31.gh-issue-119770.NCtels.rst | 1 - ...-05-31-13-56-21.gh-issue-119838.H6XHlE.rst | 3 - ...-05-31-21-17-43.gh-issue-119824.CQlxWV.rst | 1 - ...-06-01-16-58-43.gh-issue-117398.kR0RW7.rst | 2 - ...4-06-02-13-35-11.gh-issue-81936.ETeW9x.rst | 3 - ...-06-02-15-09-17.gh-issue-118835.KUAuz6.rst | 1 - ...-06-03-11-18-16.gh-issue-117142.kWTXQo.rst | 2 - ...4-06-04-08-57-02.gh-issue-65454.o9j4wF.rst | 1 - ...-06-04-12-23-01.gh-issue-119819.WKKrYh.rst | 2 - ...-06-04-14-54-46.gh-issue-120029._1YdTf.rst | 2 - ...-06-04-18-53-10.gh-issue-120057.RSD9_Z.rst | 4 - ...-06-04-19-03-25.gh-issue-112672.K2XfZH.rst | 1 - ...-06-04-19-49-16.gh-issue-120056.5aqozw.rst | 3 - ...-06-05-08-02-46.gh-issue-120108.4U9BL8.rst | 2 - ...-06-05-11-03-10.gh-issue-120029.QBsw47.rst | 4 - ...-06-05-11-39-21.gh-issue-119933.ooJXQV.rst | 3 - ...-06-05-16-30-28.gh-issue-120121.9dz8i7.rst | 1 - ...-06-06-12-07-57.gh-issue-119698.rRrprk.rst | 2 - ...-06-06-17-24-43.gh-issue-120161.DahNXV.rst | 2 - ...-06-07-02-00-31.gh-issue-120157.HnWcF9.rst | 1 - ...-06-07-10-10-32.gh-issue-117983.NeMR9n.rst | 2 - ...4-06-07-11-23-31.gh-issue-71587.IjFajE.rst | 2 - ...-06-07-13-21-11.gh-issue-120211.Rws_gf.rst | 1 - ...-06-08-03-29-01.gh-issue-120254.h682ke.rst | 1 - ...-06-08-09-45-31.gh-issue-120244.8o9Dzr.rst | 1 - ...-06-08-14-36-40.gh-issue-120268.MNpd1q.rst | 2 - ...-06-08-15-15-29.gh-issue-114053.WQLAFG.rst | 4 - ...-06-08-15-46-35.gh-issue-114053.Ub2XgJ.rst | 4 - ...4-06-08-17-41-11.gh-issue-82017.WpSTGi.rst | 2 - ...-06-09-19-53-11.gh-issue-120289.s4HXR0.rst | 2 - ...-06-10-14-00-40.gh-issue-119600.jJMf4C.rst | 2 - ...-06-11-07-17-25.gh-issue-119180.iH-2zy.rst | 4 - ...-06-11-16-34-41.gh-issue-120343.hdiXeU.rst | 1 - ...4-06-12-10-00-31.gh-issue-90425.5CfkKG.rst | 2 - ...-06-12-11-54-05.gh-issue-120381.O-BNLs.rst | 2 - ...-06-12-15-07-58.gh-issue-120388.VuTQMT.rst | 3 - ...-06-14-20-05-25.gh-issue-120495.OxgZKB.rst | 1 - ...-06-15-12-04-46.gh-issue-120541.d3cc5y.rst | 2 - ...-06-15-23-38-36.gh-issue-120284.HwsAtY.rst | 2 - ...-06-16-21-33-56.gh-issue-120606.kugbwR.rst | 1 - ...-06-17-20-04-13.gh-issue-120633.kZC5wt.rst | 1 - ...-06-18-14-45-38.gh-issue-118710.5GZZPX.rst | 1 - ...-06-18-19-18-10.gh-issue-120683.xmRez7.rst | 4 - ...-06-19-13-20-01.gh-issue-111259.Wki5PV.rst | 3 - ...-06-19-15-06-58.gh-issue-120732.OvYV9b.rst | 2 - ...-06-19-15-43-04.gh-issue-120743.CMMl2P.rst | 3 - ...4-06-19-19-53-42.gh-issue-41431.gnkUc5.rst | 2 - ...-06-19-23-08-25.gh-issue-120780.0Omopb.rst | 1 - ...-06-20-01-31-24.gh-issue-120769.PfiMrc.rst | 1 - ...-06-21-06-37-46.gh-issue-120713.WBbQx4.rst | 2 - ...-06-21-12-00-16.gh-issue-120782.LOE8tj.rst | 1 - ...-06-21-14-32-56.gh-issue-120811.eBmVTV.rst | 1 - ...-06-22-17-01-56.gh-issue-120678.Ik8dCg.rst | 3 - ...-06-22-22-23-56.gh-issue-101830.1BAoxH.rst | 2 - ...-06-22-22-52-24.gh-issue-120888.sd8I3N.rst | 1 - ...4-06-23-07-23-08.gh-issue-61103.ca_U_l.rst | 5 - ...-06-23-11-21-27.gh-issue-120910.t0QXdB.rst | 2 - ...-06-23-17-50-40.gh-issue-119614.vwPGLB.rst | 2 - ...-06-26-03-04-24.gh-issue-121018.clVSc4.rst | 3 - ...-06-26-10-13-40.gh-issue-121025.M-XXlV.rst | 2 - ...-06-26-17-00-39.gh-issue-117784.inCtAV.rst | 1 - ...-06-27-12-27-52.gh-issue-121027.D4K1OX.rst | 1 - ...-06-27-13-47-14.gh-issue-121027.jh55EC.rst | 2 - ...4-06-29-05-08-59.gh-issue-87744.rpF6Jw.rst | 1 - ...-06-29-15-21-12.gh-issue-121141.4evD6q.rst | 1 - ...-06-29-15-23-26.gh-issue-121151.HeLEvq.rst | 2 - ...-06-29-19-30-15.gh-issue-121163.SJKDFq.rst | 2 - ...-07-01-11-23-18.gh-issue-121210.cD0zfn.rst | 2 - ...-07-02-11-34-06.gh-issue-121245.sSkDAr.rst | 2 - ...-07-03-07-25-21.gh-issue-121332.Iz6FEq.rst | 4 - ...-07-03-10-11-53.gh-issue-121313.D7gARW.rst | 1 - ...-07-03-14-23-04.gh-issue-119004.L5MoUu.rst | 2 - ...4-07-04-17-36-03.gh-issue-59110.IlI9Fz.rst | 2 - ...-07-06-12-37-10.gh-issue-121423.vnxrl4.rst | 2 - ...-07-06-16-08-39.gh-issue-119169.o0YymL.rst | 1 - ...-07-06-23-39-38.gh-issue-121450.vGqb3c.rst | 4 - ...-07-08-03-45-34.gh-issue-121474.NsvrUN.rst | 2 - ...-07-09-12-23-32.gh-issue-121486.Iultjh.rst | 3 - ...-07-10-08-13-34.gh-issue-121249.W9Gd09.rst | 3 - ...-07-13-06-23-24.gh-issue-121245.RfOgf4.rst | 3 - ...4-07-14-06-24-02.gh-issue-57141.C3jhDh.rst | 2 - ...-07-14-11-18-28.gh-issue-120930.Kuo4L0.rst | 2 - ...-07-15-19-25-25.gh-issue-121798.GmuBDu.rst | 2 - ...-07-15-19-34-56.gh-issue-121797.qDqj59.rst | 2 - ...-07-16-20-49-07.gh-issue-121804.gYN-In.rst | 2 - ...-07-17-09-23-03.gh-issue-121889.6se9jS.rst | 1 - ...-07-17-09-44-35.gh-issue-119698.WlygzR.rst | 3 - ...-07-17-12-55-22.gh-issue-121268.41RmjR.rst | 1 - ...4-07-21-02-00-46.gh-issue-73991.pLxdtJ.rst | 1 - ...-07-21-10-45-24.gh-issue-122081.dNrYMq.rst | 2 - ...-07-21-18-03-30.gh-issue-122088.vi2bP-.rst | 3 - ...-07-22-08-14-04.gh-issue-113785.6B_KNB.rst | 1 - ...-07-22-08-57-28.gh-issue-120754.Eo5puP.rst | 1 - ...4-07-23-09-14-44.gh-issue-82951.-F5p5A.rst | 3 - ...-07-23-10-59-38.gh-issue-121723.iJEf7e.rst | 3 - ...-07-23-12-38-14.gh-issue-122145.sTO8nX.rst | 3 - ...-07-23-13-07-12.gh-issue-122129.PwbC8q.rst | 1 - ...-07-23-15-11-13.gh-issue-122163.4wRUuM.rst | 2 - ...-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst | 2 - ...-07-23-17-13-10.gh-issue-119180.5PZELo.rst | 2 - ...-07-23-22-26-00.gh-issue-119180.B2IVT8.rst | 7 - ...-07-24-08-48-22.gh-issue-122213.o3pdgA.rst | 2 - ...-07-25-15-41-14.gh-issue-105733.o3koJA.rst | 2 - ...-07-26-21-21-13.gh-issue-122332.fvw88r.rst | 2 - ...-07-27-16-10-41.gh-issue-121650.nf6oc9.rst | 5 - ...-07-29-10-24-48.gh-issue-122311.xChV1b.rst | 1 - ...-07-29-16-47-08.gh-issue-122400.fM0YSv.rst | 3 - ...-07-30-04-27-55.gh-issue-122272.6Wwa1V.rst | 2 - ...4-07-30-14-46-16.gh-issue-87320.-Yk1wb.rst | 3 - ...-07-30-15-57-07.gh-issue-122459.AYIoeN.rst | 2 - ...-07-30-21-29-30.gh-issue-122334.LeoE1x.rst | 1 - ...4-07-31-14-55-41.gh-issue-82378.eZvYmR.rst | 2 - ...-07-31-15-08-42.gh-issue-116622.aKxIQA.rst | 2 - ...-07-31-20-43-21.gh-issue-122478.sCU2Le.rst | 3 - ...-08-03-06-51-08.gh-issue-122637.gpas8J.rst | 1 - ...-08-04-14-07-18.gh-issue-118814.uiyks1.rst | 1 - ...-08-06-07-24-00.gh-issue-118974.qamsCQ.rst | 2 - ...-08-06-10-36-55.gh-issue-118761.q_x_1A.rst | 2 - ...-08-06-18-07-19.gh-issue-122744.kCzNDI.rst | 1 - ...-08-07-11-57-41.gh-issue-122311.LDExnJ.rst | 5 - ...-08-07-14-12-19.gh-issue-105376.QbGPdE.rst | 3 - ...-08-07-17-41-16.gh-issue-116263.EcXir0.rst | 2 - ...-08-10-10-21-44.gh-issue-122858.ZC1rJD.rst | 2 - ...-08-10-14-16-59.gh-issue-122873.XlHaUn.rst | 3 - ...-08-11-14-08-04.gh-issue-122905.7tDsxA.rst | 1 - ...-08-11-14-23-07.gh-issue-122903.xktZta.rst | 2 - ...-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst | 2 - ...-08-15-09-45-34.gh-issue-121735._1q0qf.rst | 3 - ...-08-16-16-53-52.gh-issue-123049.izx_fH.rst | 2 - ...-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst | 1 - ...-08-17-08-17-20.gh-issue-123085.7Io2yH.rst | 3 - ...-08-18-08-25-32.gh-issue-123084.rf8izX.rst | 4 - ...-08-19-17-37-18.gh-issue-122909.kP12SK.rst | 3 - ...-08-20-14-22-49.gh-issue-123165.vOZZOA.rst | 1 - ...4-08-20-18-02-27.gh-issue-85110.8_iDQy.rst | 2 - ...-08-22-09-37-48.gh-issue-123213.owmXnP.rst | 3 - ...-08-22-11-25-19.gh-issue-122546.BSmeE7.rst | 2 - ...-08-22-20-10-13.gh-issue-123243.Kifj1L.rst | 1 - ...-08-23-15-49-10.gh-issue-116810.QLBUU8.rst | 4 - ...4-08-23-22-01-30.gh-issue-76960.vsANPu.rst | 5 - ...-08-24-00-03-01.gh-issue-123240.uFPG3l.rst | 1 - ...-08-24-06-05-41.gh-issue-123228.jR_5O5.rst | 3 - ...4-08-25-16-59-20.gh-issue-73991.1w8u3K.rst | 2 - ...-08-26-13-45-20.gh-issue-123270.gXHvNJ.rst | 3 - ...-08-26-18-48-13.gh-issue-119518.QFYH9q.rst | 2 - ...-08-26-19-36-00.gh-issue-123340.mQKI1H.rst | 1 - ...-08-27-10-30-37.gh-issue-123341.5e-fjt.rst | 1 - ...-08-27-12-11-00.gh-issue-123363.gKuJp6.rst | 2 - ...-08-27-12-38-42.gh-issue-123089.vA7iFR.rst | 1 - ...-08-28-13-03-36.gh-issue-123409.lW0YF-.rst | 2 - ...-08-28-20-08-19.gh-issue-123448.tItJlp.rst | 2 - ...-08-29-09-27-12.gh-issue-123446._I_mMr.rst | 3 - ...-08-29-14-51-36.gh-issue-123430.M7wXl9.rst | 1 - ...-08-30-09-01-35.gh-issue-123504.lJ9_BB.rst | 1 - ...-08-31-12-34-44.gh-issue-123374.3kE7rb.rst | 1 - ...-09-02-20-34-04.gh-issue-123339.czgcSu.rst | 4 - ...-09-04-18-23-43.gh-issue-123657.Oks4So.rst | 2 - ...-09-06-00-00-43.gh-issue-122765.tx4hsr.rst | 1 - ...-09-06-01-35-11.gh-issue-123756.Ozbhke.rst | 1 - ...4-09-06-10-17-54.gh-issue-84808.ION67Z.rst | 3 - ...-09-10-11-26-14.gh-issue-123892.2gzIrz.rst | 1 - ...-09-11-13-33-19.gh-issue-123935.fRZ_56.rst | 2 - ...-09-11-19-05-32.gh-issue-123945.jLwybB.rst | 1 - ...-09-11-19-12-23.gh-issue-123968.OwHON_.rst | 1 - ...-09-12-10-55-19.gh-issue-124016.ncs0hd.rst | 1 - ...-09-13-10-34-19.gh-issue-123934.yMe7mL.rst | 2 - ...-09-16-12-31-48.gh-issue-123978.z3smEu.rst | 1 - ...-09-17-18-06-42.gh-issue-124171.PHCvRJ.rst | 3 - ...-09-18-17-45-52.gh-issue-124212.n6kIby.rst | 1 - ...4-09-19-00-09-48.gh-issue-84559.IrxvQe.rst | 5 - ...4-09-19-03-46-59.gh-issue-87041.9Ox7Bv.rst | 1 - ...4-09-19-10-36-18.gh-issue-81691.Hyhp_U.rst | 3 - ...-09-19-11-47-39.gh-issue-124248.g7rufd.rst | 2 - ...-09-19-16-00-22.gh-issue-111513.6jHm02.rst | 1 - ...-09-19-20-15-00.gh-issue-124217.j0KlQB.rst | 1 - ...4-09-20-12-23-11.gh-issue-53780.mrV1zi.rst | 1 - ...-09-20-18-23-19.gh-issue-100980.8nVAB6.rst | 3 - ...4-09-21-19-02-37.gh-issue-59317.OAhNZZ.rst | 2 - ...4-09-21-22-32-21.gh-issue-72795.naLmkX.rst | 4 - ...4-09-21-23-56-41.gh-issue-63143.YKu-LQ.rst | 3 - ...-09-23-17-33-47.gh-issue-104860.O86OSc.rst | 2 - ...4-09-23-18-26-17.gh-issue-90562.Yj566G.rst | 3 - ...-09-24-00-01-24.gh-issue-124400.0XCgfe.rst | 1 - ...-09-24-12-34-48.gh-issue-124345.s3vKql.rst | 2 - ...-09-24-13-32-16.gh-issue-124176.6hmOPz.rst | 4 - ...-09-24-19-32-14.gh-issue-123014.zVcfkZ.rst | 3 - ...-09-24-21-15-27.gh-issue-123017.dSAr2f.rst | 2 - ...-09-24-22-38-51.gh-issue-123884.iEPTK4.rst | 4 - ...4-09-25-10-25-57.gh-issue-53834.uyIckw.rst | 4 - ...-09-25-12-14-58.gh-issue-124498.Ozxs55.rst | 2 - ...-09-25-18-07-51.gh-issue-120378.NlBSz_.rst | 2 - ...4-09-25-18-08-29.gh-issue-80259.kO5Tw7.rst | 2 - ...-09-25-18-34-48.gh-issue-124538.nXZk4R.rst | 1 - ...-09-25-22-06-52.gh-issue-124552.1nQKNM.rst | 1 - ...-09-26-00-35-24.gh-issue-116750.X1aMHI.rst | 1 - ...4-09-26-09-18-09.gh-issue-61181.dwjmch.rst | 2 - ...-09-26-13-43-39.gh-issue-124594.peYhsP.rst | 1 - ...4-09-26-22-14-12.gh-issue-58573.hozbm9.rst | 2 - ...-09-27-06-39-32.gh-issue-101552.xYkzag.rst | 4 - ...-09-27-15-16-04.gh-issue-116850.dBkR0-.rst | 2 - ...4-09-30-19-59-28.gh-issue-66436.4gYN_n.rst | 4 - ...-09-30-20-46-32.gh-issue-124787.3FnJnP.rst | 4 - ...-10-01-02-31-13.gh-issue-124693.qzbXKB.rst | 1 - ...-10-01-12-43-42.gh-issue-124835.SVyp3K.rst | 3 - ...4-10-01-13-11-53.gh-issue-85935.CTwJUy.rst | 4 - ...-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst | 1 - ...-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst | 1 - ...4-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst | 4 - ...-10-02-15-05-45.gh-issue-124653.tqsTu9.rst | 2 - ...4-10-02-16-35-07.gh-issue-65865.S2D4wq.rst | 3 - ...-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst | 2 - ...4-10-02-22-53-48.gh-issue-90102.4qX52R.rst | 3 - ...-10-03-05-00-25.gh-issue-117151.Prdw_W.rst | 3 - ...-10-03-17-13-22.gh-issue-124944.YyLAzf.rst | 1 - ...-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst | 2 - ...4-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst | 5 - ...-10-04-08-46-00.gh-issue-124958.rea9-x.rst | 1 - ...4-10-04-12-43-03.gh-issue-69998.DVqOXX.rst | 3 - ...-10-05-15-49-53.gh-issue-124960.Bol9hT.rst | 1 - ...-10-08-12-09-09.gh-issue-124969._VBQLq.rst | 3 - ...-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst | 5 - ...-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst | 4 - ...-10-09-07-09-00.gh-issue-125118.J9rQ1S.rst | 1 - ...4-10-09-21-42-43.gh-issue-61011.pQXZb1.rst | 4 - ...-10-10-18-33-31.gh-issue-125235.0kOB5I.rst | 2 - ...-10-10-19-57-35.gh-issue-125254.RtZxXS.rst | 1 - ...-10-10-20-39-57.gh-issue-125243.eUbbtu.rst | 2 - ...-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst | 2 - ...4-10-11-16-19-46.gh-issue-89967.vhWUOR.rst | 1 - ...-10-11-18-03-05.gh-issue-125206.pWRRK6.rst | 2 - ...4-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst | 2 - ...-10-14-02-27-03.gh-issue-100141.NuAcwa.rst | 1 - ...-10-14-04-44-12.gh-issue-125422.MlVuC6.rst | 1 - ...-05-01-20-57-09.gh-issue-118486.K44KJG.rst | 4 - ...-05-08-21-59-38.gh-issue-118773.7dFRJY.rst | 2 - ...-06-25-04-42-43.gh-issue-112301.god4IC.rst | 2 - ...-07-02-13-39-20.gh-issue-121285.hrl-yI.rst | 2 - ...-07-08-23-39-04.gh-issue-112301.TD8G01.rst | 2 - ...-07-18-13-17-47.gh-issue-121957.QemKLU.rst | 3 - ...-07-22-13-11-28.gh-issue-122133.0mPeta.rst | 5 - ...-07-24-05-18-25.gh-issue-112301.lfINgZ.rst | 2 - ...-08-06-00-06-23.gh-issue-112301.4k4lw6.rst | 2 - ...-08-07-10-42-13.gh-issue-122792.oiTMo9.rst | 3 - ...-08-14-19-43-57.gh-issue-112301.IQUcOy.rst | 1 - ...-09-04-12-41-35.gh-issue-123678.N41y9n.rst | 1 - ...-10-09-20-08-13.gh-issue-125140.YgNWRB.rst | 1 - ...-08-03-17-26-55.gh-issue-107562.ZnbscS.rst | 3 - ...-05-04-22-56-41.gh-issue-101525.LHK166.rst | 2 - ...-05-18-10-59-27.gh-issue-119050.g4qiH7.rst | 2 - ...-05-20-18-06-31.gh-issue-119273.hf-yhX.rst | 3 - ...-05-29-15-28-08.gh-issue-119727.dVkaZM.rst | 2 - ...-06-20-12-51-26.gh-issue-120801.lMVXC9.rst | 2 - ...-07-01-09-04-32.gh-issue-121188.XbuTVa.rst | 3 - ...-07-01-16-15-06.gh-issue-121200.4Pc-gc.rst | 3 - ...-07-03-14-41-00.gh-issue-121160.LEtiTd.rst | 2 - ...-07-04-15-10-29.gh-issue-121084.qxcd5d.rst | 3 - ...4-07-13-11-04-44.gh-issue-99242.aGxnwz.rst | 3 - ...4-07-13-11-48-20.gh-issue-59022.fYNbQ8.rst | 1 - ...-07-13-21-55-58.gh-issue-112301.YJS1dl.rst | 2 - ...-07-17-08-25-06.gh-issue-121921.HW8CIS.rst | 2 - ...-09-17-22-21-58.gh-issue-124190.3fWhiX.rst | 1 - ...-09-18-18-39-21.gh-issue-124213.AQq_xg.rst | 3 - ...-09-25-12-39-34.gh-issue-124378.Ywwgia.rst | 1 - ...-10-07-14-13-38.gh-issue-125041.PKLWDf.rst | 3 - ...-09-04-10-07-51.gh-issue-123418.1eIFZb.rst | 2 - ...2-04-20-18-32-30.gh-issue-79846.Vggv3f.rst | 2 - ...-04-24-05-16-32.gh-issue-118209.Ryyzlz.rst | 2 - ...-04-24-22-50-33.gh-issue-117505.gcTb_p.rst | 1 - ...-05-22-19-43-29.gh-issue-119070._enton.rst | 3 - ...-05-25-18-43-10.gh-issue-111201.SLPJIx.rst | 1 - ...-05-29-11-06-12.gh-issue-119690.8q6e1p.rst | 1 - ...-05-30-17-39-25.gh-issue-119679.mZC87w.rst | 1 - ...-07-19-21-50-54.gh-issue-100256.GDrKba.rst | 1 - ...-08-01-10-55-15.gh-issue-122573.4-UCFY.rst | 1 - ...-08-29-16-13-45.gh-issue-123476.m2DFS4.rst | 1 - ...-09-04-09-59-18.gh-issue-123418.QaMC12.rst | 1 - ...-09-10-19-23-00.gh-issue-123915.yZMEDO.rst | 1 - ...-09-20-11-18-50.gh-issue-124254.iPin-L.rst | 1 - ...-09-24-19-04-56.gh-issue-124448.srVT3d.rst | 1 - ...-09-27-13-40-25.gh-issue-124609.WaKk8G.rst | 1 - ...-09-27-15-07-30.gh-issue-124487.7LrwHC.rst | 1 - ...-09-04-11-55-29.gh-issue-123418.8P4bmN.rst | 1 - ...-09-07-12-14-54.gh-issue-123797.yFDeug.rst | 1 - ...-09-24-10-48-46.gh-issue-124448.bFMrS6.rst | 1 - README.rst | 2 +- 645 files changed, 7739 insertions(+), 1993 deletions(-) create mode 100644 Misc/NEWS.d/3.14.0a1.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-05-11-15-11-30.gh-issue-118943.VI_MnY.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-05-13-15-57-58.gh-issue-118836.7yN1iB.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-05-17-19-53-27.gh-issue-119132.wepPgM.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-05-19-22-54-55.gh-issue-115119.DwMwev.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-05-29-17-40-50.gh-issue-119729.k0xJ5U.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-02-13-23-26.gh-issue-113565.8xBlId.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-09-15-54-22.gh-issue-120291.IpfHzE.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-11-00-38-05.gh-issue-120326.JHSDF1.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-18-15-28-25.gh-issue-118943.aie7nn.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-18-15-32-36.gh-issue-120688.tjIPLD.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-19-21-05-15.gh-issue-120602.UyDARz.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-21-09-24-03.gh-issue-120671.Z8sBQB.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-02-12-42-25.gh-issue-120831.i3eIjg.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-02-20-16-09.gh-issue-121103.TMef9j.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-08-01-11-54.gh-issue-121467.3qWRQj.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-08-14-01-17.gh-issue-121487.ekHmpR.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-14-01-29-47.gh-issue-121731.RMPGP3.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-16-12-29-54.gh-issue-120371.E7x858.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-07-19-10-14-31.gh-issue-121996.IEb2sz.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-08-02-12-59-15.gh-issue-118943.vZQtET.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-08-07-00-20-18.gh-issue-116622.U9cxHM.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-08-12-15-48-49.gh-issue-122578.YJ3xEa.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-08-14-19-17-34.gh-issue-121634.eOMfHG.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-08-24-19-09-31.gh-issue-123297.fdtXoe.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-09-04-12-01-43.gh-issue-123418.ynzspB.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-09-13-17-48-37.gh-issue-124043.Bruxpq.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-09-16-09-42-05.gh-issue-124102.Ow254j.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-09-23-11-27-25.gh-issue-123990.d6HrYC.rst delete mode 100644 Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst delete mode 100644 Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst delete mode 100644 Misc/NEWS.d/next/C API/2022-08-05-19-41-20.gh-issue-87135.SCNBYj.rst delete mode 100644 Misc/NEWS.d/next/C API/2022-10-01-09-56-27.gh-issue-97588.Gvg54o.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-04-10-16-48-04.gh-issue-117511.RZtBRK.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-08-20-13-00.gh-issue-118789.m88uUa.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-08-21-57-50.gh-issue-118789.Ni4UQx.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-08-23-14-06.gh-issue-116984.5sgcDo.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-10-15-43-14.gh-issue-118771.5KVglT.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-20-10-35-22.gh-issue-111389.a6axBk.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-21-11-35-11.gh-issue-119247.U6n6mh.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-21-18-28-44.gh-issue-119333.OTsYVX.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-21-19-41-41.gh-issue-119344.QKvzQb.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-22-17-50-48.gh-issue-119336.ff3qnS.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-29-09-21-37.gh-issue-119613.J2xfrC.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-29-21-05-59.gh-issue-119585.Sn7JL3.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-05-30-12-51-21.gh-issue-119775.CBq9IG.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-04-10-58-20.gh-issue-119613.qOr9GF.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-07-22-12-30.gh-issue-119182.yt8Ar7.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-08-08-33-40.gh-issue-119771.Oip2dL.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-11-21-38-32.gh-issue-70278.WDE4zM.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-16-22-58-47.gh-issue-120600.TJdf0w.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-19-17-27-22.gh-issue-120389.GSZeHF.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-19-21-27-42.gh-issue-120642.UlKClN.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-21-16-41-21.gh-issue-120858.Z5_-Mn.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-06-26-11-29-01.gh-issue-120642.H7P9qK.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-07-02-11-03-40.gh-issue-112136.f3fiY8.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-07-04-15-41-10.gh-issue-113993.cLSiWV.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-07-21-17-40-07.gh-issue-121489.SUMFCr.rst delete mode 100644 Misc/NEWS.d/next/C API/2024-07-30-23-48-26.gh-issue-116622.yTTtil.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-07-12-13-40-59.gh-issue-121645.96QvD3.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-07-27-00-28-35.gh-issue-105201.0-xUWq.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-08-09-13-12-20.gh-issue-122854.-1OgvU.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-08-26-13-01-20.gh-issue-100554.0ku85o.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-08-29-15-05-19.gh-issue-123465.eqwNWq.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-08-29-15-55-55.gh-issue-107954.pr2O50.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-08-30-14-02-17.gh-issue-107954.TPvj4u.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-09-12-16-16-24.gh-issue-123880.2-8vcj.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-09-16-16-21-39.gh-issue-124127.LB8DBU.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-09-17-05-23-35.gh-issue-124153.L8TWmx.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-09-18-18-40-30.gh-issue-124160.Zy-VKi.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-09-24-20-34-21.gh-issue-124296.S4QoS1.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst delete mode 100644 Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-10-09-15-14-53.bpo-24766.c_C1Wc.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-07-22-15-56-35.gh-issue-95144.FZYWX-.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-01-15-18-11-48.gh-issue-113190.OwQX64.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-01-15-21-51-26.gh-issue-114091.VOtSJl.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-03-19-22-21-22.gh-issue-116022.iyHENN.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-03-25-15-07-01.gh-issue-117195.OWakgD.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-08-13-49-02.gh-issue-117558.9lSEpR.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-27-18-36-46.gh-issue-115801.SVeHSy.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-01-05-09-16.gh-issue-117139.t41w_D.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-07-16-57-56.gh-issue-118561.wNMKVd.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-08-09-44-15.gh-issue-118767.iFF5F5.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-09-02-37-25.gh-issue-118750.7aLfT-.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-09-19-47-12.gh-issue-117657.Vn0Yey.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-10-19-54-18.gh-issue-118921.O4ztZG.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-11-21-44-17.gh-issue-118844.q2H_km.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-15-12-15-58.gh-issue-119057.P3G9G2.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-16-23-02-03.gh-issue-119049.qpd_S-.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-20-10-10-51.gh-issue-119180.35xqpu.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-20-14-57-39.gh-issue-118692.Qadm7F.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-21-09-46-51.gh-issue-119011.WOe3bu.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-21-11-27-14.gh-issue-119213.nxjxrt.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-21-12-17-02.gh-issue-119180.UNDUb9.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-22-06-22-47.gh-issue-119180.vZMiXm.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-22-12-49-03.gh-issue-119372.PXig1R.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-14.gh-issue-119395.z-Hsqb.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-45.gh-issue-119311.2DBwKR.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-23-20-17-37.gh-issue-119258.wZFIpt.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-04-00.gh-issue-119525.zLFLf1.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-16-52.gh-issue-119369.qBThho.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-25-12-52-25.gh-issue-119560.wSlm8q.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-25-13-51-48.gh-issue-111999.L0q1gh.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-25-16-45-27.gh-issue-119548.pqF9Y6.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-27-19-13-49.gh-issue-109218.-sdDg0.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-28-22-49-56.gh-issue-119689.VwLFD5.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-30-04-11-36.gh-issue-118934.fbDqve.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-30-23-01-00.gh-issue-119821.jPGfvt.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-05-31-12-06-11.gh-issue-119842.tCGVsv.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-02-06-12-35.gh-issue-119879.Jit951.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-25-04.gh-issue-119724.EH1dkA.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-05-08-39-40.gh-issue-120080.DJFK11.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-05-10-32-44.gh-issue-120097.9S2klk.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-07-16-09-04.gh-issue-120225.kuYf9t.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-07-22-54-15.gh-issue-119726.D9EE-o.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-09-19-13-38.gh-issue-119666.S0G4rZ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-10-22-30-26.gh-issue-93691.68WOTS.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-11-12-47-54.gh-issue-120346.hhn_6X.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-11-17-56-12.gh-issue-120221.si9hM9.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-12-13-47-25.gh-issue-120397.n-I_cc.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-23-15.gh-issue-120380.edtqjq.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-14-07-52-00.gh-issue-120485.yy4K4b.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-14-22-02-25.gh-issue-113993.MiA0vX.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-17-12-20-20.gh-issue-120507.94lz2J.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-18-21-34-30.gh-issue-120367.zDwffP.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-18-22-41-05.gh-issue-120722.rS7tkE.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-19-11-10-50.gh-issue-119462.DpcqSe.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-19-19-54-35.gh-issue-120754.uF29sj.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-19-21-34-21.gh-issue-98442.cqhjkN.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-24-08-39-23.gh-issue-116017.-Bw2UY.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-25-16-26-44.gh-issue-119726.WqvHxB.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-26-13-42-36.gh-issue-113433.xKAtLB.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-26-14-09-31.gh-issue-120838.nFeTL9.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-28-10-02-58.gh-issue-121115.EeSLfc.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-28-18-34-49.gh-issue-119726.Fjv_Ab.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-29-10-46-14.gh-issue-121130.Rj66Xs.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-06-30-03-48-10.gh-issue-121149.lLBMKe.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-04-23-38-30.gh-issue-121368.m3EF9E.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-05-11-29-27.gh-issue-121288.lYKYYP.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-08-02-24-55.gh-issue-121439.jDHod3.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-08-10-31-08.gh-issue-121012.M5hHk-.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-08-17-15-14.gh-issue-121497.I8hMDC.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-09-13-53-18.gh-issue-121499.rpp7il.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-10-02-02-32.gh-issue-121562.8beIMi.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-13-12-27-31.gh-issue-121657.wgOYLw.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-15-16-26-32.gh-issue-121794.fhBtiQ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-15-20-41-06.gh-issue-121814.oR2ixR.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-16-15-11-51.gh-issue-121795.xkIHrI.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-19-09-38-01.gh-issue-99108.qzM6gl.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-19-15-28-05.gh-issue-122026.sta2Ca.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-23-11-57-36.gh-issue-122160.HSnrAP.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-23-23-59-04.gh-issue-122208.z8KHsY.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-24-22-39-07.gh-issue-122245.LVa9v8.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-26-14-05-51.gh-issue-122300.SVIF-l.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-30-11-41-35.gh-issue-122445.Rq0bjS.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-05-19-04-06.gh-issue-116622.3LWUzE.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-18-18-25-54.gh-issue-123123.0ZcaEB.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-20-11-09-16.gh-issue-123048.2TISpv.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-20-12-29-52.gh-issue-123142.3PXiNb.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-21-15-22-53.gh-issue-121804.r5K3PS.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-23-13-08-27.gh-issue-123229.aHm-dw.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-23-15-59-54.gh-issue-123177.OLcaC5.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-25-10-54-22.gh-issue-122982.KLD91q.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-26-00-58-26.gh-issue-123321.ApxcnE.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-08-27-13-16-40.gh-issue-123344.56Or78.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-09-23-23-06-19.gh-issue-124285.mahGTg.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-18-21-19-04.gh-issue-121999.8IBbTK.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-13-56-32.gh-issue-120906.qBh2I9.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-10-55-46.gh-issue-116090.p1MhU0.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-19-20-25.gh-issue-122417.NVgs0a.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-01-19-13-58.gh-issue-122527.eztso6.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-05-19-28-12.gh-issue-122697.17MvYl.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-08-16-02-28.gh-issue-118093.m6Mrvy.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-10-12-44-03.gh-issue-122888.TUyu9r.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-19-37.gh-issue-122907.q68096.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-45-47.gh-issue-122821.WnAzTK.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-14-11-38-56.gh-issue-118093.3BywDP.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-15-19-28-43.gh-issue-123022.m3EF9E.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-17-17-26-25.gh-issue-123083.9xWLJ-.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-19-15-13-13.gh-issue-118093.dLZ8qS.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-21-08-53-00.gh-issue-115776.9A7Dv_.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-11-26-54.gh-issue-122298.ZMyln4.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-18-31-10.gh-issue-123275.DprIrj.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-21-20-34.gh-issue-123271.xeVViR.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-25-18-27-49.gh-issue-123177.yLuyqE.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-27-21-44-14.gh-issue-116017.ZY3yBY.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-28-22-42-51.gh-issue-123440.yOFB0N.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-13-18-18.gh-issue-123446.KWDrgq.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-19-46-07.gh-issue-123484.rjUn_F.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-00-02-05.gh-issue-123545.8nQNbL.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-12-08-39.gh-issue-123562.aJPKVu.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-17-32-15.gh-issue-119034.HYh5Vj.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-36-45.gh-issue-123339.QcmpSs.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-39-10.gh-issue-123614.26TMHp.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-03-13-34-35.gh-issue-123572.uuqoYV.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-14-13-01.gh-issue-119310.WQxyDF.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-19-23-44.gh-issue-120221.giJEDT.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-13-27-16.gh-issue-77894.ZC-Olu.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-20-25-00.gh-issue-123923.A7uxqa.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-11-15-48-36.gh-issue-123958.5VW2r0.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-12-21-53-26.gh-issue-124022.fQzUiW.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-13-02-25-06.gh-issue-124027.to_9DY.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-17-22-06-01.gh-issue-124188.aFqNAB.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-13-17-31.gh-issue-122878.4iFpsB.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-16-57-34.gh-issue-119726.DseseK.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-13-25-27.gh-issue-65961.LDqXV2.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-15-23-14.gh-issue-123856.yrgJ9m.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-11-53-22.gh-issue-124442.EXC1Ve.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-14-45-56.gh-issue-124513.ywiXtr.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-13-25-01.gh-issue-119180.k_JCX0.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-17-55-34.gh-issue-116510.dhn8w8.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-27-17-18-53.gh-issue-124642.OCjhBJ.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-16-39-37.gh-issue-118093.J2A3gz.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-06-03-22-06-26.gh-issue-119574.Ik9kOO.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-06-05-12-36-18.gh-issue-120012.f14DbQ.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-07-14-11-48-10.gh-issue-121749.nxHoTk.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-07-14-12-25-53.gh-issue-117765.YFMOUv.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-07-19-12-22-48.gh-issue-121277.wF_zKd.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-09-11-16-52-08.gh-issue-123976.jhOfNR.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-09-19-19-33-25.gh-issue-116622.M65UZ6.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-09-24-11-52-36.gh-issue-124457.yrCjSV.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-09-27-16-47-48.gh-issue-124720.nVSTVb.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2024-06-05-14-54-24.gh-issue-120104.j_thj4.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2024-06-16-21-42-45.gh-issue-120083.nczuyv.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2024-07-30-18-02-55.gh-issue-122482.TerE0g.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2024-09-21-23-12-18.gh-issue-112938.OeiDru.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst delete mode 100644 Misc/NEWS.d/next/Library/2018-12-04-07-36-27.bpo-14074.fMLKCu.rst delete mode 100644 Misc/NEWS.d/next/Library/2019-08-27-01-16-50.gh-issue-67693.4NIAiy.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-03-28-21-00-54.bpo-15987.aBL8XS.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-12-22-18-08-12.bpo-41843.q9Nh2r.rst delete mode 100644 Misc/NEWS.d/next/Library/2021-08-24-19-37-46.bpo-44864.KzxaDh.rst delete mode 100644 Misc/NEWS.d/next/Library/2022-03-10-16-47-57.bpo-45767.ywmyo1.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-03-30-18-19-53.gh-issue-103134.bHrn91.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-04-10-00-04-37.gh-issue-87106.UyBnPQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-04-24-05-34-23.gh-issue-103194.GwBwWL.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-04-26-22-24-17.gh-issue-92081.V8xMot.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-04-28-09-54-15.gh-issue-103956.EyLDPS.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-16-14-52-00.gh-issue-102450.MfeR6A.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-17-09-07-06.gh-issue-105623.5G06od.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-12-12-15-19-58.gh-issue-108172.KyDPuG.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-01-12-08-51-03.gh-issue-113978.MqTgB0.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-01-14-11-43-31.gh-issue-113878.dmEIN3.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-01-18-21-44-23.gh-issue-114264.DBKn29.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-03-19-21-41-31.gh-issue-106531.Mgd--6.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-04-19-14-59-53.gh-issue-118033.amS4Gw.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-04-24-16-23-04.gh-issue-110190.TGd5qx.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-04-28-19-51-00.gh-issue-118263.Gaap3S.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-06-17-39-52.gh-issue-118673.sTXBit.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-07-17-38-53.gh-issue-118714.XXKpVZ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-18-33-07.gh-issue-118507.OCQsAY.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-18-59-19.gh-issue-78707._Lz1sw.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-19-47-34.gh-issue-101357.e4R_9x.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-20-41-48.gh-issue-74033.YebHZj.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-21-13-56.gh-issue-118760.mdmH3T.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-21-30-33.gh-issue-118760.XvyMHn.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-08-23-16-50.gh-issue-118798.Q_ybqP.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-09-00-52-30.gh-issue-118803.Wv3AvU.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-09-01-05-52.gh-issue-118805.N7dm07.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-09-02-43-37.gh-issue-101588.30bNAr.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-09-08-46-12.gh-issue-118851.aPAoJw.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-09-11-50-26.gh-issue-118824.-jBJQC.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-09-12-33-25.gh-issue-118827.JrzHz1.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-09-21-36-11.gh-issue-118868.uckxxP.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-10-22-36-01.gh-issue-118928.IW7Ukv.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-10-22-59-01.gh-issue-118924.9nyvSH.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-11-20-23-45.gh-issue-82805.F9bz4J.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-15-01-36-08.gh-issue-73991.CGknDf.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-16-17-31-46.gh-issue-118643.hAWH4C.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-17-17-32-12.gh-issue-119113.kEv1Ll.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-19-12-25-36.gh-issue-119105.VcR4ig.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-19-18-49-04.gh-issue-119174.5GTv7d.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-20-20-30-57.gh-issue-111201.DAA5lC.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-21-19-10-30.gh-issue-115225.eRmfJH.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-21-20-13-23.gh-issue-118911.iG8nMq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-21-23-39-22.gh-issue-118830.YTqvEo.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-22-21-20-43.gh-issue-118894.xHdxR_.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-23-11-52-36.gh-issue-117398.2FG1Mk.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-23-15-48-17.gh-issue-119461.82KqUW.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-23-22-29-59.gh-issue-119443.KAGz6S.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-24-04-05-37.gh-issue-119105.aDSRFn.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-24-11-47-08.gh-issue-69214.Grl6zF.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-24-14-32-24.gh-issue-119506.-nMNqq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-24-21-54-55.gh-issue-113892.JKDFqq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-25-00-54-26.gh-issue-119127.LpPvag.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-25-07-25-07.gh-issue-117865.1A0Xpi.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-25-10-40-38.gh-issue-118908.XcZiq4.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-25-20-15-26.gh-issue-119555.mvHbEL.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-26-21-28-11.gh-issue-119588.wlLBK5.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-26-22-22-51.gh-issue-119594.fnQNM8.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-28-00-56-59.gh-issue-89727._bxoL3.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-28-12-15-03.gh-issue-119118.FMKz1F.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-29-12-42-40.gh-issue-93963.cb1oJS.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-29-20-42-17.gh-issue-89727.5lPTTW.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-29-21-50-05.gh-issue-119577.S3BlKJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-30-21-37-05.gh-issue-89727.D6S9ig.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-31-13-56-21.gh-issue-119838.H6XHlE.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-01-16-58-43.gh-issue-117398.kR0RW7.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-02-13-35-11.gh-issue-81936.ETeW9x.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-02-15-09-17.gh-issue-118835.KUAuz6.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-03-11-18-16.gh-issue-117142.kWTXQo.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-04-08-57-02.gh-issue-65454.o9j4wF.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-04-12-23-01.gh-issue-119819.WKKrYh.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-04-14-54-46.gh-issue-120029._1YdTf.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-04-18-53-10.gh-issue-120057.RSD9_Z.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-04-19-03-25.gh-issue-112672.K2XfZH.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-04-19-49-16.gh-issue-120056.5aqozw.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-05-08-02-46.gh-issue-120108.4U9BL8.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-05-11-03-10.gh-issue-120029.QBsw47.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-05-16-30-28.gh-issue-120121.9dz8i7.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-06-12-07-57.gh-issue-119698.rRrprk.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-06-17-24-43.gh-issue-120161.DahNXV.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-07-02-00-31.gh-issue-120157.HnWcF9.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-07-10-10-32.gh-issue-117983.NeMR9n.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-07-11-23-31.gh-issue-71587.IjFajE.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-07-13-21-11.gh-issue-120211.Rws_gf.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-08-03-29-01.gh-issue-120254.h682ke.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-08-09-45-31.gh-issue-120244.8o9Dzr.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-08-14-36-40.gh-issue-120268.MNpd1q.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-08-15-15-29.gh-issue-114053.WQLAFG.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-08-15-46-35.gh-issue-114053.Ub2XgJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-08-17-41-11.gh-issue-82017.WpSTGi.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-09-19-53-11.gh-issue-120289.s4HXR0.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-10-14-00-40.gh-issue-119600.jJMf4C.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-11-07-17-25.gh-issue-119180.iH-2zy.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-11-16-34-41.gh-issue-120343.hdiXeU.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-12-10-00-31.gh-issue-90425.5CfkKG.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-12-11-54-05.gh-issue-120381.O-BNLs.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-12-15-07-58.gh-issue-120388.VuTQMT.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-14-20-05-25.gh-issue-120495.OxgZKB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-15-12-04-46.gh-issue-120541.d3cc5y.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-15-23-38-36.gh-issue-120284.HwsAtY.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-16-21-33-56.gh-issue-120606.kugbwR.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-17-20-04-13.gh-issue-120633.kZC5wt.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-18-14-45-38.gh-issue-118710.5GZZPX.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-18-19-18-10.gh-issue-120683.xmRez7.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-19-13-20-01.gh-issue-111259.Wki5PV.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-19-15-06-58.gh-issue-120732.OvYV9b.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-19-15-43-04.gh-issue-120743.CMMl2P.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-19-19-53-42.gh-issue-41431.gnkUc5.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-21-06-37-46.gh-issue-120713.WBbQx4.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-21-12-00-16.gh-issue-120782.LOE8tj.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-21-14-32-56.gh-issue-120811.eBmVTV.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-22-17-01-56.gh-issue-120678.Ik8dCg.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-22-22-23-56.gh-issue-101830.1BAoxH.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-22-22-52-24.gh-issue-120888.sd8I3N.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-23-11-21-27.gh-issue-120910.t0QXdB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-23-17-50-40.gh-issue-119614.vwPGLB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-26-03-04-24.gh-issue-121018.clVSc4.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-26-10-13-40.gh-issue-121025.M-XXlV.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-27-12-27-52.gh-issue-121027.D4K1OX.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-27-13-47-14.gh-issue-121027.jh55EC.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-29-05-08-59.gh-issue-87744.rpF6Jw.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-29-15-21-12.gh-issue-121141.4evD6q.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-29-15-23-26.gh-issue-121151.HeLEvq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-06-29-19-30-15.gh-issue-121163.SJKDFq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-01-11-23-18.gh-issue-121210.cD0zfn.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-02-11-34-06.gh-issue-121245.sSkDAr.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-03-07-25-21.gh-issue-121332.Iz6FEq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-03-10-11-53.gh-issue-121313.D7gARW.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-03-14-23-04.gh-issue-119004.L5MoUu.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-04-17-36-03.gh-issue-59110.IlI9Fz.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-06-12-37-10.gh-issue-121423.vnxrl4.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-06-16-08-39.gh-issue-119169.o0YymL.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-08-03-45-34.gh-issue-121474.NsvrUN.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-14-06-24-02.gh-issue-57141.C3jhDh.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-14-11-18-28.gh-issue-120930.Kuo4L0.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-16-20-49-07.gh-issue-121804.gYN-In.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-17-09-23-03.gh-issue-121889.6se9jS.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-17-09-44-35.gh-issue-119698.WlygzR.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-17-12-55-22.gh-issue-121268.41RmjR.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-21-02-00-46.gh-issue-73991.pLxdtJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-21-10-45-24.gh-issue-122081.dNrYMq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-21-18-03-30.gh-issue-122088.vi2bP-.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-22-08-14-04.gh-issue-113785.6B_KNB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-22-08-57-28.gh-issue-120754.Eo5puP.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-09-14-44.gh-issue-82951.-F5p5A.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-10-59-38.gh-issue-121723.iJEf7e.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-13-07-12.gh-issue-122129.PwbC8q.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-15-11-13.gh-issue-122163.4wRUuM.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-17-13-10.gh-issue-119180.5PZELo.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-23-22-26-00.gh-issue-119180.B2IVT8.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-24-08-48-22.gh-issue-122213.o3pdgA.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-25-15-41-14.gh-issue-105733.o3koJA.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-26-21-21-13.gh-issue-122332.fvw88r.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-29-10-24-48.gh-issue-122311.xChV1b.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-29-16-47-08.gh-issue-122400.fM0YSv.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-30-04-27-55.gh-issue-122272.6Wwa1V.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-30-14-46-16.gh-issue-87320.-Yk1wb.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-30-15-57-07.gh-issue-122459.AYIoeN.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-30-21-29-30.gh-issue-122334.LeoE1x.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-31-15-08-42.gh-issue-116622.aKxIQA.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-07-31-20-43-21.gh-issue-122478.sCU2Le.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-03-06-51-08.gh-issue-122637.gpas8J.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-04-14-07-18.gh-issue-118814.uiyks1.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-06-07-24-00.gh-issue-118974.qamsCQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-06-18-07-19.gh-issue-122744.kCzNDI.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-07-11-57-41.gh-issue-122311.LDExnJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-07-14-12-19.gh-issue-105376.QbGPdE.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-07-17-41-16.gh-issue-116263.EcXir0.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-10-10-21-44.gh-issue-122858.ZC1rJD.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-10-14-16-59.gh-issue-122873.XlHaUn.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-11-14-23-07.gh-issue-122903.xktZta.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-15-09-45-34.gh-issue-121735._1q0qf.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-17-08-17-20.gh-issue-123085.7Io2yH.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-19-17-37-18.gh-issue-122909.kP12SK.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-20-14-22-49.gh-issue-123165.vOZZOA.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-20-18-02-27.gh-issue-85110.8_iDQy.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-22-11-25-19.gh-issue-122546.BSmeE7.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-22-20-10-13.gh-issue-123243.Kifj1L.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-23-15-49-10.gh-issue-116810.QLBUU8.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-23-22-01-30.gh-issue-76960.vsANPu.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-24-00-03-01.gh-issue-123240.uFPG3l.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-24-06-05-41.gh-issue-123228.jR_5O5.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-25-16-59-20.gh-issue-73991.1w8u3K.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-26-13-45-20.gh-issue-123270.gXHvNJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-26-18-48-13.gh-issue-119518.QFYH9q.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-26-19-36-00.gh-issue-123340.mQKI1H.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-27-10-30-37.gh-issue-123341.5e-fjt.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-27-12-11-00.gh-issue-123363.gKuJp6.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-27-12-38-42.gh-issue-123089.vA7iFR.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-28-13-03-36.gh-issue-123409.lW0YF-.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-28-20-08-19.gh-issue-123448.tItJlp.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-29-09-27-12.gh-issue-123446._I_mMr.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-29-14-51-36.gh-issue-123430.M7wXl9.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-30-09-01-35.gh-issue-123504.lJ9_BB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-08-31-12-34-44.gh-issue-123374.3kE7rb.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-02-20-34-04.gh-issue-123339.czgcSu.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-04-18-23-43.gh-issue-123657.Oks4So.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-06-00-00-43.gh-issue-122765.tx4hsr.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-06-01-35-11.gh-issue-123756.Ozbhke.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-06-10-17-54.gh-issue-84808.ION67Z.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-10-11-26-14.gh-issue-123892.2gzIrz.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-11-13-33-19.gh-issue-123935.fRZ_56.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-11-19-05-32.gh-issue-123945.jLwybB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-11-19-12-23.gh-issue-123968.OwHON_.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-12-10-55-19.gh-issue-124016.ncs0hd.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-13-10-34-19.gh-issue-123934.yMe7mL.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-16-12-31-48.gh-issue-123978.z3smEu.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-17-18-06-42.gh-issue-124171.PHCvRJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-18-17-45-52.gh-issue-124212.n6kIby.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-19-00-09-48.gh-issue-84559.IrxvQe.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-19-03-46-59.gh-issue-87041.9Ox7Bv.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-19-10-36-18.gh-issue-81691.Hyhp_U.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-19-16-00-22.gh-issue-111513.6jHm02.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-19-20-15-00.gh-issue-124217.j0KlQB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-20-12-23-11.gh-issue-53780.mrV1zi.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-20-18-23-19.gh-issue-100980.8nVAB6.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-21-19-02-37.gh-issue-59317.OAhNZZ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-21-22-32-21.gh-issue-72795.naLmkX.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-21-23-56-41.gh-issue-63143.YKu-LQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-23-17-33-47.gh-issue-104860.O86OSc.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-23-18-26-17.gh-issue-90562.Yj566G.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-24-00-01-24.gh-issue-124400.0XCgfe.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-24-12-34-48.gh-issue-124345.s3vKql.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-24-13-32-16.gh-issue-124176.6hmOPz.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-24-19-32-14.gh-issue-123014.zVcfkZ.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-24-21-15-27.gh-issue-123017.dSAr2f.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-24-22-38-51.gh-issue-123884.iEPTK4.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-25-10-25-57.gh-issue-53834.uyIckw.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-25-12-14-58.gh-issue-124498.Ozxs55.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-25-18-08-29.gh-issue-80259.kO5Tw7.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-26-00-35-24.gh-issue-116750.X1aMHI.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-26-09-18-09.gh-issue-61181.dwjmch.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-26-13-43-39.gh-issue-124594.peYhsP.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-26-22-14-12.gh-issue-58573.hozbm9.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-27-15-16-04.gh-issue-116850.dBkR0-.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-30-19-59-28.gh-issue-66436.4gYN_n.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-01-12-43-42.gh-issue-124835.SVyp3K.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-09-07-09-00.gh-issue-125118.J9rQ1S.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst delete mode 100644 Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-05-01-20-57-09.gh-issue-118486.K44KJG.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-06-25-04-42-43.gh-issue-112301.god4IC.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-07-08-23-39-04.gh-issue-112301.TD8G01.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-07-18-13-17-47.gh-issue-121957.QemKLU.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-07-22-13-11-28.gh-issue-122133.0mPeta.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-07-24-05-18-25.gh-issue-112301.lfINgZ.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-08-06-00-06-23.gh-issue-112301.4k4lw6.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-08-07-10-42-13.gh-issue-122792.oiTMo9.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-08-14-19-43-57.gh-issue-112301.IQUcOy.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-09-04-12-41-35.gh-issue-123678.N41y9n.rst delete mode 100644 Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-05-04-22-56-41.gh-issue-101525.LHK166.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-05-18-10-59-27.gh-issue-119050.g4qiH7.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-05-20-18-06-31.gh-issue-119273.hf-yhX.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-06-20-12-51-26.gh-issue-120801.lMVXC9.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-01-09-04-32.gh-issue-121188.XbuTVa.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-01-16-15-06.gh-issue-121200.4Pc-gc.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-03-14-41-00.gh-issue-121160.LEtiTd.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-04-15-10-29.gh-issue-121084.qxcd5d.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-13-11-04-44.gh-issue-99242.aGxnwz.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-13-11-48-20.gh-issue-59022.fYNbQ8.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-13-21-55-58.gh-issue-112301.YJS1dl.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-07-17-08-25-06.gh-issue-121921.HW8CIS.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-09-17-22-21-58.gh-issue-124190.3fWhiX.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-09-18-18-39-21.gh-issue-124213.AQq_xg.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-09-25-12-39-34.gh-issue-124378.Ywwgia.rst delete mode 100644 Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2024-09-04-10-07-51.gh-issue-123418.1eIFZb.rst delete mode 100644 Misc/NEWS.d/next/Windows/2022-04-20-18-32-30.gh-issue-79846.Vggv3f.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-04-24-05-16-32.gh-issue-118209.Ryyzlz.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-04-24-22-50-33.gh-issue-117505.gcTb_p.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-05-22-19-43-29.gh-issue-119070._enton.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-05-25-18-43-10.gh-issue-111201.SLPJIx.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-05-29-11-06-12.gh-issue-119690.8q6e1p.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-05-30-17-39-25.gh-issue-119679.mZC87w.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-07-19-21-50-54.gh-issue-100256.GDrKba.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-08-01-10-55-15.gh-issue-122573.4-UCFY.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-08-29-16-13-45.gh-issue-123476.m2DFS4.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-09-04-09-59-18.gh-issue-123418.QaMC12.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-09-10-19-23-00.gh-issue-123915.yZMEDO.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-09-20-11-18-50.gh-issue-124254.iPin-L.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-09-24-19-04-56.gh-issue-124448.srVT3d.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-09-27-13-40-25.gh-issue-124609.WaKk8G.rst delete mode 100644 Misc/NEWS.d/next/Windows/2024-09-27-15-07-30.gh-issue-124487.7LrwHC.rst delete mode 100644 Misc/NEWS.d/next/macOS/2024-09-04-11-55-29.gh-issue-123418.8P4bmN.rst delete mode 100644 Misc/NEWS.d/next/macOS/2024-09-07-12-14-54.gh-issue-123797.yFDeug.rst delete mode 100644 Misc/NEWS.d/next/macOS/2024-09-24-10-48-46.gh-issue-124448.bFMrS6.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 8e0cf7bb0fc088..ffc5b4223ba589 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1195,7 +1195,7 @@ code, or when embedding the Python interpreter: created by Python. Refer to :ref:`cautions-regarding-runtime-finalization` for more details. - .. versionchanged:: next + .. versionchanged:: 3.14 Hangs the current thread, rather than terminating it, if called while the interpreter is finalizing. @@ -1257,7 +1257,7 @@ with sub-interpreters: created by Python. Refer to :ref:`cautions-regarding-runtime-finalization` for more details. - .. versionchanged:: next + .. versionchanged:: 3.14 Hangs the current thread, rather than terminating it, if called while the interpreter is finalizing. @@ -1547,7 +1547,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`. :c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`, and terminate the current thread if called while the interpreter is finalizing. - .. versionchanged:: next + .. versionchanged:: 3.14 Hangs the current thread, rather than terminating it, if called while the interpreter is finalizing. diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 02ef8aa7846468..6d3463fe25a614 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -579,7 +579,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. On failure, return -1 with an exception set. This function always succeeds if *obj* is a :c:type:`PyLongObject` or its subtype. - .. versionadded:: next + .. versionadded:: 3.14 .. c:function:: PyObject* PyLong_GetInfo(void) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 4daf9e9fdbf2f1..59bd7661965d93 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1575,7 +1575,7 @@ PyUnicodeWriter The :c:type:`PyUnicodeWriter` API can be used to create a Python :class:`str` object. -.. versionadded:: next +.. versionadded:: 3.14 .. c:type:: PyUnicodeWriter diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 3d2df035a85c21..22d8c87cb58e78 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -2491,7 +2491,7 @@ effects on the compilation of a program: differ in whitespace or similar details. Attributes include line numbers and column offsets. - .. versionadded:: next + .. versionadded:: 3.14 .. _ast-cli: diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index d76b8d4809c078..d49959b4eb7da2 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2303,7 +2303,7 @@ These are the fundamental ctypes data types: Represents the C :c:expr:`double complex` datatype, if available. The constructor accepts an optional :class:`complex` initializer. - .. versionadded:: next + .. versionadded:: 3.14 .. class:: c_float_complex diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1d084a8bf38d98..a2e44e09ffc925 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -959,7 +959,7 @@ iterations of the loop. list of constants supported by this instruction. Used by the :keyword:`assert` statement to load :exc:`AssertionError`. - .. versionadded:: next + .. versionadded:: 3.14 .. opcode:: LOAD_BUILD_CLASS @@ -1827,7 +1827,7 @@ iterations of the loop. If ``type(STACK[-1]).__xxx__`` is not a method, leave ``STACK[-1].__xxx__; NULL`` on the stack. - .. versionadded:: next + .. versionadded:: 3.14 **Pseudo-instructions** diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 30d0d385d0539c..4380122eb1be7d 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -1563,7 +1563,7 @@ Copying, moving and deleting This argument has no effect when copying files on Windows (where metadata is always preserved). - .. versionadded:: next + .. versionadded:: 3.14 .. method:: Path.copy_into(target_dir, *, follow_symlinks=True, \ @@ -1574,7 +1574,7 @@ Copying, moving and deleting :meth:`Path.copy`. Returns a new :class:`!Path` instance pointing to the copy. - .. versionadded:: next + .. versionadded:: 3.14 .. method:: Path.rename(target) diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index 56cd6b8afaa73e..54e19af4bd69a6 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -256,7 +256,7 @@ Examining Symbol Tables Return ``True`` if the symbol is a type parameter. - .. versionadded:: next + .. versionadded:: 3.14 .. method:: is_global() @@ -303,7 +303,7 @@ Examining Symbol Tables be free from the perspective of ``C.method``, thereby allowing the latter to return *1* at runtime and not *2*. - .. versionadded:: next + .. versionadded:: 3.14 .. method:: is_assigned() @@ -313,13 +313,13 @@ Examining Symbol Tables Return ``True`` if the symbol is a comprehension iteration variable. - .. versionadded:: next + .. versionadded:: 3.14 .. method:: is_comp_cell() Return ``True`` if the symbol is a cell in an inlined comprehension. - .. versionadded:: next + .. versionadded:: 3.14 .. method:: is_namespace() diff --git a/Include/patchlevel.h b/Include/patchlevel.h index d63af11dbd220a..c7a9496a35ed92 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 14 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 0 +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.14.0a0" +#define PY_VERSION "3.14.0a1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index ae56c136608472..165d3853f95e29 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Wed May 8 11:11:17 2024 +# Autogenerated by Sphinx on Tue Oct 15 22:34:02 2024 # as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' @@ -308,10 +308,10 @@ 'target.\n' 'The target is only evaluated once.\n' '\n' - 'An augmented assignment expression like "x += 1" can be ' - 'rewritten as\n' - '"x = x + 1" to achieve a similar, but not exactly equal ' - 'effect. In the\n' + 'An augmented assignment statement like "x += 1" can be ' + 'rewritten as "x\n' + '= x + 1" to achieve a similar, but not exactly equal effect. ' + 'In the\n' 'augmented version, "x" is only evaluated once. Also, when ' 'possible,\n' 'the actual operation is performed *in-place*, meaning that ' @@ -362,21 +362,21 @@ 'a single\n' 'target is allowed.\n' '\n' - 'For simple names as assignment targets, if in class or module ' - 'scope,\n' - 'the annotations are evaluated and stored in a special class or ' - 'module\n' - 'attribute "__annotations__" that is a dictionary mapping from ' - 'variable\n' - 'names (mangled if private) to evaluated annotations. This ' - 'attribute is\n' - 'writable and is automatically created at the start of class or ' - 'module\n' - 'body execution, if annotations are found statically.\n' - '\n' - 'For expressions as assignment targets, the annotations are ' + 'The assignment target is considered “simple” if it consists of ' + 'a\n' + 'single name that is not enclosed in parentheses. For simple ' + 'assignment\n' + 'targets, if in class or module scope, the annotations are ' + 'gathered in\n' + 'a lazily evaluated annotation scope. The annotations can be ' 'evaluated\n' - 'if in class or module scope, but not stored.\n' + 'using the "__annotations__" attribute of a class or module, or ' + 'using\n' + 'the facilities in the "annotationlib" module.\n' + '\n' + 'If the assignment target is not simple (an attribute, ' + 'subscript node,\n' + 'or parenthesized name), the annotation is never evaluated.\n' '\n' 'If a name is annotated in a function scope, then this name is ' 'local\n' @@ -386,12 +386,13 @@ '\n' 'If the right hand side is present, an annotated assignment ' 'performs\n' - 'the actual assignment before evaluating annotations (where\n' - 'applicable). If the right hand side is not present for an ' - 'expression\n' - 'target, then the interpreter evaluates the target except for ' - 'the last\n' - '"__setitem__()" or "__setattr__()" call.\n' + 'the actual assignment as if there was no annotation present. ' + 'If the\n' + 'right hand side is not present for an expression target, then ' + 'the\n' + 'interpreter evaluates the target except for the last ' + '"__setitem__()"\n' + 'or "__setattr__()" call.\n' '\n' 'See also:\n' '\n' @@ -415,7 +416,13 @@ 'Previously,\n' 'some expressions (like un-parenthesized tuple expressions) ' 'caused a\n' - 'syntax error.\n', + 'syntax error.\n' + '\n' + 'Changed in version 3.14: Annotations are now lazily evaluated ' + 'in a\n' + 'separate annotation scope. If the assignment target is not ' + 'simple,\n' + 'annotations are never evaluated.\n', 'assignment-expressions': 'Assignment expressions\n' '**********************\n' '\n' @@ -593,31 +600,67 @@ 'evaluate it\n' 'raises a "NameError" exception.\n' '\n' - '**Private name mangling:** When an identifier that ' - 'textually occurs in\n' - 'a class definition begins with two or more underscore ' - 'characters and\n' - 'does not end in two or more underscores, it is ' - 'considered a *private\n' - 'name* of that class. Private names are transformed to a ' - 'longer form\n' - 'before code is generated for them. The transformation ' - 'inserts the\n' - 'class name, with leading underscores removed and a ' - 'single underscore\n' - 'inserted, in front of the name. For example, the ' - 'identifier "__spam"\n' - 'occurring in a class named "Ham" will be transformed to ' - '"_Ham__spam".\n' - 'This transformation is independent of the syntactical ' + '\n' + 'Private name mangling\n' + '=====================\n' + '\n' + 'When an identifier that textually occurs in a class ' + 'definition begins\n' + 'with two or more underscore characters and does not end ' + 'in two or more\n' + 'underscores, it is considered a *private name* of that ' + 'class.\n' + '\n' + 'See also: The class specifications.\n' + '\n' + 'More precisely, private names are transformed to a ' + 'longer form before\n' + 'code is generated for them. If the transformed name is ' + 'longer than\n' + '255 characters, implementation-defined truncation may ' + 'happen.\n' + '\n' + 'The transformation is independent of the syntactical ' 'context in which\n' - 'the identifier is used. If the transformed name is ' - 'extremely long\n' - '(longer than 255 characters), implementation defined ' - 'truncation may\n' - 'happen. If the class name consists only of underscores, ' - 'no\n' - 'transformation is done.\n', + 'the identifier is used but only the following private ' + 'identifiers are\n' + 'mangled:\n' + '\n' + '* Any name used as the name of a variable that is ' + 'assigned or read or\n' + ' any name of an attribute being accessed.\n' + '\n' + ' The "__name__" attribute of nested functions, classes, ' + 'and type\n' + ' aliases is however not mangled.\n' + '\n' + '* The name of imported modules, e.g., "__spam" in ' + '"import __spam". If\n' + ' the module is part of a package (i.e., its name ' + 'contains a dot), the\n' + ' name is *not* mangled, e.g., the "__foo" in "import ' + '__foo.bar" is\n' + ' not mangled.\n' + '\n' + '* The name of an imported member, e.g., "__f" in "from ' + 'spam import\n' + ' __f".\n' + '\n' + 'The transformation rule is defined as follows:\n' + '\n' + '* The class name, with leading underscores removed and a ' + 'single\n' + ' leading underscore inserted, is inserted in front of ' + 'the identifier,\n' + ' e.g., the identifier "__spam" occurring in a class ' + 'named "Foo",\n' + ' "_Foo" or "__Foo" is transformed to "_Foo__spam".\n' + '\n' + '* If the class name consists only of underscores, the ' + 'transformation\n' + ' is the identity, e.g., the identifier "__spam" ' + 'occurring in a class\n' + ' named "_" or "__" is left as is.\n', 'atom-literals': 'Literals\n' '********\n' '\n' @@ -630,10 +673,10 @@ '\n' 'Evaluation of a literal yields an object of the given type ' '(string,\n' - 'bytes, integer, floating point number, complex number) with ' + 'bytes, integer, floating-point number, complex number) with ' 'the given\n' 'value. The value may be approximated in the case of ' - 'floating point\n' + 'floating-point\n' 'and imaginary (complex) literals. See section Literals for ' 'details.\n' '\n' @@ -1091,11 +1134,13 @@ 'to the class\n' ' where it is defined. *__slots__* declared in parents ' 'are available\n' - ' in child classes. However, child subclasses will get a ' - '"__dict__"\n' - ' and *__weakref__* unless they also define *__slots__* ' - '(which should\n' - ' only contain names of any *additional* slots).\n' + ' in child classes. However, instances of a child ' + 'subclass will get a\n' + ' "__dict__" and *__weakref__* unless the subclass also ' + 'defines\n' + ' *__slots__* (which should only contain names of any ' + '*additional*\n' + ' slots).\n' '\n' '* If a class defines a slot also defined in a base ' 'class, the instance\n' @@ -1201,10 +1246,10 @@ 'target.\n' 'The target is only evaluated once.\n' '\n' - 'An augmented assignment expression like "x += 1" can be ' - 'rewritten as\n' - '"x = x + 1" to achieve a similar, but not exactly equal effect. ' - 'In the\n' + 'An augmented assignment statement like "x += 1" can be ' + 'rewritten as "x\n' + '= x + 1" to achieve a similar, but not exactly equal effect. In ' + 'the\n' 'augmented version, "x" is only evaluated once. Also, when ' 'possible,\n' 'the actual operation is performed *in-place*, meaning that ' @@ -1277,6 +1322,10 @@ 'The "@" (at) operator is intended to be used for matrix\n' 'multiplication. No builtin Python types implement this operator.\n' '\n' + 'This operation can be customized using the special "__matmul__()" ' + 'and\n' + '"__rmatmul__()" methods.\n' + '\n' 'Added in version 3.5.\n' '\n' 'The "/" (division) and "//" (floor division) operators yield the\n' @@ -1289,17 +1338,19 @@ 'result. Division by zero raises the "ZeroDivisionError" ' 'exception.\n' '\n' - 'This operation can be customized using the special "__truediv__()" ' + 'The division operation can be customized using the special\n' + '"__truediv__()" and "__rtruediv__()" methods. The floor division\n' + 'operation can be customized using the special "__floordiv__()" ' 'and\n' - '"__floordiv__()" methods.\n' + '"__rfloordiv__()" methods.\n' '\n' 'The "%" (modulo) operator yields the remainder from the division ' 'of\n' 'the first argument by the second. The numeric arguments are ' 'first\n' 'converted to a common type. A zero right argument raises the\n' - '"ZeroDivisionError" exception. The arguments may be floating ' - 'point\n' + '"ZeroDivisionError" exception. The arguments may be ' + 'floating-point\n' 'numbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals ' '"4*0.7 +\n' '0.34".) The modulo operator always yields a result with the same ' @@ -1326,13 +1377,13 @@ '\n' 'The *modulo* operation can be customized using the special ' '"__mod__()"\n' - 'method.\n' + 'and "__rmod__()" methods.\n' '\n' 'The floor division operator, the modulo operator, and the ' '"divmod()"\n' 'function are not defined for complex numbers. Instead, convert to ' 'a\n' - 'floating point number using the "abs()" function if appropriate.\n' + 'floating-point number using the "abs()" function if appropriate.\n' '\n' 'The "+" (addition) operator yields the sum of its arguments. The\n' 'arguments must either both be numbers or both be sequences of the ' @@ -1351,7 +1402,8 @@ 'The numeric arguments are first converted to a common type.\n' '\n' 'This operation can be customized using the special "__sub__()" ' - 'method.\n', + 'and\n' + '"__rsub__()" methods.\n', 'bitwise': 'Binary bitwise operations\n' '*************************\n' '\n' @@ -2426,18 +2478,16 @@ 'An\n' 'expression-less "except" clause, if present, must be last; it ' 'matches\n' - 'any exception. For an "except" clause with an expression, that\n' - 'expression is evaluated, and the clause matches the exception if ' - 'the\n' - 'resulting object is “compatible” with the exception. An object ' - 'is\n' - 'compatible with an exception if the object is the class or a ' - '*non-\n' - 'virtual base class* of the exception object, or a tuple ' - 'containing an\n' - 'item that is the class or a non-virtual base class of the ' - 'exception\n' - 'object.\n' + 'any exception.\n' + '\n' + 'For an "except" clause with an expression, the expression must\n' + 'evaluate to an exception type or a tuple of exception types. ' + 'The\n' + 'raised exception matches an "except" clause whose expression ' + 'evaluates\n' + 'to the class or a *non-virtual base class* of the exception ' + 'object, or\n' + 'to a tuple that contains such a class.\n' '\n' 'If no "except" clause matches the exception, the search for an\n' 'exception handler continues in the surrounding code and on the\n' @@ -2586,13 +2636,16 @@ ' ...\n' " ExceptionGroup('', (BlockingIOError()))\n" '\n' - 'An "except*" clause must have a matching type, and this type ' - 'cannot be\n' - 'a subclass of "BaseExceptionGroup". It is not possible to mix ' - '"except"\n' - 'and "except*" in the same "try". "break", "continue" and ' - '"return"\n' - 'cannot appear in an "except*" clause.\n' + 'An "except*" clause must have a matching expression; it cannot ' + 'be\n' + '"except*:". Furthermore, this expression cannot contain ' + 'exception\n' + 'group types, because that would have ambiguous semantics.\n' + '\n' + 'It is not possible to mix "except" and "except*" in the same ' + '"try".\n' + '"break", "continue" and "return" cannot appear in an "except*" ' + 'clause.\n' '\n' '\n' '"else" clause\n' @@ -3090,7 +3143,7 @@ ' | "None"\n' ' | "True"\n' ' | "False"\n' - ' | signed_number: NUMBER | "-" NUMBER\n' + ' signed_number ::= ["-"] NUMBER\n' '\n' 'The rule "strings" and the token "NUMBER" are defined in the ' 'standard\n' @@ -3560,10 +3613,12 @@ ' parameter_list_no_posonly ::= defparameter ("," ' 'defparameter)* ["," [parameter_list_starargs]]\n' ' | parameter_list_starargs\n' - ' parameter_list_starargs ::= "*" [parameter] ("," ' + ' parameter_list_starargs ::= "*" [star_parameter] ("," ' 'defparameter)* ["," ["**" parameter [","]]]\n' ' | "**" parameter [","]\n' ' parameter ::= identifier [":" expression]\n' + ' star_parameter ::= identifier [":" ["*"] ' + 'expression]\n' ' defparameter ::= parameter ["=" expression]\n' ' funcname ::= identifier\n' '\n' @@ -3691,27 +3746,22 @@ 'expression"”\n' 'following the parameter name. Any parameter may have an ' 'annotation,\n' - 'even those of the form "*identifier" or "**identifier". ' - 'Functions may\n' - 'have “return” annotation of the form “"-> expression"” after ' - 'the\n' - 'parameter list. These annotations can be any valid Python ' - 'expression.\n' - 'The presence of annotations does not change the semantics of a\n' - 'function. The annotation values are available as values of a\n' - 'dictionary keyed by the parameters’ names in the ' - '"__annotations__"\n' - 'attribute of the function object. If the "annotations" import ' - 'from\n' - '"__future__" is used, annotations are preserved as strings at ' - 'runtime\n' - 'which enables postponed evaluation. Otherwise, they are ' - 'evaluated\n' - 'when the function definition is executed. In this case ' - 'annotations\n' - 'may be evaluated in a different order than they appear in the ' - 'source\n' - 'code.\n' + 'even those of the form "*identifier" or "**identifier". (As a ' + 'special\n' + 'case, parameters of the form "*identifier" may have an ' + 'annotation “":\n' + '*expression"”.) Functions may have “return” annotation of the ' + 'form\n' + '“"-> expression"” after the parameter list. These annotations ' + 'can be\n' + 'any valid Python expression. The presence of annotations does ' + 'not\n' + 'change the semantics of a function. See Annotations for more\n' + 'information on annotations.\n' + '\n' + 'Changed in version 3.11: Parameters of the form “"*identifier"” ' + 'may\n' + 'have an annotation “": *expression"”. See **PEP 646**.\n' '\n' 'It is also possible to create anonymous functions (functions not ' 'bound\n' @@ -4301,6 +4351,56 @@ 'not\n' 'actually bound at runtime.\n' '\n' + '\n' + 'Annotations\n' + '===========\n' + '\n' + 'Changed in version 3.14: Annotations are now lazily evaluated ' + 'by\n' + 'default.\n' + '\n' + 'Variables and function parameters may carry *annotations*, ' + 'created by\n' + 'adding a colon after the name, followed by an expression:\n' + '\n' + ' x: annotation = 1\n' + ' def f(param: annotation): ...\n' + '\n' + 'Functions may also carry a return annotation following an ' + 'arrow:\n' + '\n' + ' def f() -> annotation: ...\n' + '\n' + 'Annotations are conventionally used for *type hints*, but this ' + 'is not\n' + 'enforced by the language, and in general annotations may ' + 'contain\n' + 'arbitrary expressions. The presence of annotations does not ' + 'change the\n' + 'runtime semantics of the code, except if some mechanism is used ' + 'that\n' + 'introspects and uses the annotations (such as "dataclasses" or\n' + '"functools.singledispatch()").\n' + '\n' + 'By default, annotations are lazily evaluated in a annotation ' + 'scope.\n' + 'This means that they are not evaluated when the code containing ' + 'the\n' + 'annotation is evaluated. Instead, the interpreter saves ' + 'information\n' + 'that can be used to evaluate the annotation later if requested. ' + 'The\n' + '"annotationlib" module provides tools for evaluating ' + 'annotations.\n' + '\n' + 'If the future statement "from __future__ import annotations" is\n' + 'present, all annotations are instead stored as strings:\n' + '\n' + ' >>> from __future__ import annotations\n' + ' >>> def f(param: annotation): ...\n' + ' >>> f.__annotations__\n' + " {'param': 'annotation'}\n" + '\n' '-[ Footnotes ]-\n' '\n' '[1] The exception is propagated to the invocation stack unless ' @@ -4463,7 +4563,7 @@ 'converted to\n' ' complex;\n' '\n' - '* otherwise, if either argument is a floating point number, ' + '* otherwise, if either argument is a floating-point number, ' 'the other\n' ' is converted to floating point;\n' '\n' @@ -4574,6 +4674,10 @@ ' It is not guaranteed that "__del__()" methods are called ' 'for\n' ' objects that still exist when the interpreter exits.\n' + ' "weakref.finalize" provides a straightforward way to ' + 'register a\n' + ' cleanup function to be called when an object is garbage ' + 'collected.\n' '\n' ' Note:\n' '\n' @@ -5072,6 +5176,12 @@ ' 0\n' ' (Pdb)\n' '\n' + 'Changed in version 3.13: The implementation of **PEP 667** means ' + 'that\n' + 'name assignments made via "pdb" will immediately affect the ' + 'active\n' + 'scope, even when running inside an *optimized scope*.\n' + '\n' 'The module defines the following functions; each enters the ' 'debugger\n' 'in a slightly different way:\n' @@ -5113,7 +5223,7 @@ 'appears\n' ' as soon as the function is entered.\n' '\n' - 'pdb.set_trace(*, header=None)\n' + 'pdb.set_trace(*, header=None, commands=None)\n' '\n' ' Enter the debugger at the calling stack frame. This is ' 'useful to\n' @@ -5122,7 +5232,9 @@ ' code is not otherwise being debugged (e.g. when an assertion\n' ' fails). If given, *header* is printed to the console just ' 'before\n' - ' debugging begins.\n' + ' debugging begins. The *commands* argument, if given, is a ' + 'list of\n' + ' commands to execute when the debugger starts.\n' '\n' ' Changed in version 3.7: The keyword-only argument *header*.\n' '\n' @@ -5131,6 +5243,8 @@ ' immediately, rather than on the next line of code to be ' 'executed.\n' '\n' + ' Added in version 3.14: The *commands* argument.\n' + '\n' 'pdb.post_mortem(traceback=None)\n' '\n' ' Enter post-mortem debugging of the given *traceback* object. ' @@ -5153,7 +5267,7 @@ 'to access further features, you have to do this yourself:\n' '\n' "class pdb.Pdb(completekey='tab', stdin=None, stdout=None, " - 'skip=None, nosigint=False, readrc=True)\n' + 'skip=None, nosigint=False, readrc=True, mode=None)\n' '\n' ' "Pdb" is the debugger class.\n' '\n' @@ -5182,6 +5296,15 @@ 'Pdb\n' ' will load .pdbrc files from the filesystem.\n' '\n' + ' The *mode* argument specifies how the debugger was invoked. ' + 'It\n' + ' impacts the workings of some debugger commands. Valid values ' + 'are\n' + ' "\'inline\'" (used by the breakpoint() builtin), "\'cli\'" ' + '(used by the\n' + ' command line invocation) or "None" (for backwards compatible\n' + ' behaviour, as before the *mode* argument was added).\n' + '\n' ' Example call to enable tracing with *skip*:\n' '\n' " import pdb; pdb.Pdb(skip=['django.*']).set_trace()\n" @@ -5196,6 +5319,8 @@ '\n' ' Changed in version 3.6: The *readrc* argument.\n' '\n' + ' Added in version 3.14: Added the *mode* argument.\n' + '\n' ' run(statement, globals=None, locals=None)\n' ' runeval(expression, globals=None, locals=None)\n' ' runcall(function, *args, **kwds)\n' @@ -5283,7 +5408,8 @@ '* "$_exception": the exception if the frame is raising an ' 'exception\n' '\n' - 'Added in version 3.12.\n' + 'Added in version 3.12: Added the *convenience variable* ' + 'feature.\n' '\n' 'If a file ".pdbrc" exists in the user’s home directory or in ' 'the\n' @@ -5317,13 +5443,20 @@ '"help\n' ' exec" must be entered to get help on the "!" command.\n' '\n' - 'w(here)\n' + 'w(here) [count]\n' '\n' ' Print a stack trace, with the most recent frame at the ' - 'bottom. An\n' - ' arrow (">") indicates the current frame, which determines ' - 'the\n' - ' context of most commands.\n' + 'bottom. if\n' + ' *count* is 0, print the current frame entry. If *count* is\n' + ' negative, print the least recent - *count* frames. If *count* ' + 'is\n' + ' positive, print the most recent *count* frames. An arrow ' + '(">")\n' + ' indicates the current frame, which determines the context of ' + 'most\n' + ' commands.\n' + '\n' + ' Changed in version 3.14: *count* argument is added.\n' '\n' 'd(own) [count]\n' '\n' @@ -5347,7 +5480,7 @@ 'one that\n' ' hasn’t been loaded yet). The file is searched on ' '"sys.path".\n' - ' Accepatable forms of *filename* are "/abspath/to/file.py",\n' + ' Acceptable forms of *filename* are "/abspath/to/file.py",\n' ' "relpath/file.py", "module" and "package.module".\n' '\n' ' With a *function* argument, set a break at the first ' @@ -5449,25 +5582,27 @@ '\n' ' Specifying any command resuming execution (currently ' '"continue",\n' - ' "step", "next", "return", "jump", "quit" and their ' - 'abbreviations)\n' - ' terminates the command list (as if that command was ' - 'immediately\n' - ' followed by end). This is because any time you resume ' - 'execution\n' - ' (even with a simple next or step), you may encounter another\n' - ' breakpoint—which could have its own command list, leading to\n' - ' ambiguities about which list to execute.\n' - '\n' - ' If you use the "silent" command in the command list, the ' - 'usual\n' - ' message about stopping at a breakpoint is not printed. This ' - 'may be\n' - ' desirable for breakpoints that are to print a specific ' - 'message and\n' - ' then continue. If none of the other commands print anything, ' - 'you\n' - ' see no sign that the breakpoint was reached.\n' + ' "step", "next", "return", "until", "jump", "quit" and their\n' + ' abbreviations) terminates the command list (as if that ' + 'command was\n' + ' immediately followed by end). This is because any time you ' + 'resume\n' + ' execution (even with a simple next or step), you may ' + 'encounter\n' + ' another breakpoint—which could have its own command list, ' + 'leading\n' + ' to ambiguities about which list to execute.\n' + '\n' + ' If the list of commands contains the "silent" command, or a ' + 'command\n' + ' that resumes execution, then the breakpoint message ' + 'containing\n' + ' information about the frame is not displayed.\n' + '\n' + ' Changed in version 3.14: Frame information will not be ' + 'displayed if\n' + ' a command that resumes execution is present in the command ' + 'list.\n' '\n' 's(tep)\n' '\n' @@ -5658,24 +5793,22 @@ '\n' 'interact\n' '\n' - ' Start an interactive interpreter (using the "code" module) ' - 'whose\n' - ' global namespace contains all the (global and local) names ' - 'found in\n' - ' the current scope. Use "exit()" or "quit()" to exit the ' - 'interpreter\n' - ' and return to the debugger.\n' + ' Start an interactive interpreter (using the "code" module) in ' + 'a new\n' + ' global namespace initialised from the local and global ' + 'namespaces\n' + ' for the current scope. Use "exit()" or "quit()" to exit the\n' + ' interpreter and return to the debugger.\n' '\n' ' Note:\n' '\n' - ' Because interact creates a new global namespace with the ' - 'current\n' - ' global and local namespace for execution, assignment to ' - 'variables\n' - ' will not affect the original namespaces. However, ' - 'modification to\n' - ' the mutable objects will be reflected in the original ' - 'namespaces.\n' + ' As "interact" creates a new dedicated namespace for code\n' + ' execution, assignments to variables will not affect the ' + 'original\n' + ' namespaces. However, modifications to any referenced ' + 'mutable\n' + ' objects will be reflected in the original namespaces as ' + 'usual.\n' '\n' ' Added in version 3.2.\n' '\n' @@ -5755,6 +5888,10 @@ 'preserved.\n' ' "restart" is an alias for "run".\n' '\n' + ' Changed in version 3.14: "run" and "restart" commands are ' + 'disabled\n' + ' when the debugger is invoked in "\'inline\'" mode.\n' + '\n' 'q(uit)\n' '\n' ' Quit from the debugger. The program being executed is ' @@ -6264,17 +6401,18 @@ 'Annotation scopes\n' '-----------------\n' '\n' - 'Type parameter lists and "type" statements introduce ' - '*annotation\n' - 'scopes*, which behave mostly like function scopes, but with ' - 'some\n' - 'exceptions discussed below. *Annotations* currently do not use\n' - 'annotation scopes, but they are expected to use annotation ' - 'scopes in\n' - 'Python 3.13 when **PEP 649** is implemented.\n' + '*Annotations*, type parameter lists and "type" statements ' + 'introduce\n' + '*annotation scopes*, which behave mostly like function scopes, ' + 'but\n' + 'with some exceptions discussed below.\n' '\n' 'Annotation scopes are used in the following contexts:\n' '\n' + '* *Function annotations*.\n' + '\n' + '* *Variable annotations*.\n' + '\n' '* Type parameter lists for generic type aliases.\n' '\n' '* Type parameter lists for generic functions. A generic ' @@ -6328,11 +6466,11 @@ '\n' '* While annotation scopes have an internal name, that name is ' 'not\n' - ' reflected in the *__qualname__* of objects defined within the ' - 'scope.\n' - ' Instead, the "__qualname__" of such objects is as if the ' - 'object were\n' - ' defined in the enclosing scope.\n' + ' reflected in the *qualified name* of objects defined within ' + 'the\n' + ' scope. Instead, the "__qualname__" of such objects is as if ' + 'the\n' + ' object were defined in the enclosing scope.\n' '\n' 'Added in version 3.12: Annotation scopes were introduced in ' 'Python\n' @@ -6342,21 +6480,26 @@ 'type\n' 'parameter defaults, as introduced by **PEP 696**.\n' '\n' + 'Changed in version 3.14: Annotation scopes are now also used ' + 'for\n' + 'annotations, as specified in **PEP 649** and **PEP 749**.\n' + '\n' '\n' 'Lazy evaluation\n' '---------------\n' '\n' - 'The values of type aliases created through the "type" statement ' - 'are\n' - '*lazily evaluated*. The same applies to the bounds, ' - 'constraints, and\n' - 'default values of type variables created through the type ' - 'parameter\n' - 'syntax. This means that they are not evaluated when the type ' - 'alias or\n' - 'type variable is created. Instead, they are only evaluated when ' - 'doing\n' - 'so is necessary to resolve an attribute access.\n' + 'Most annotation scopes are *lazily evaluated*. This includes\n' + 'annotations, the values of type aliases created through the ' + '"type"\n' + 'statement, and the bounds, constraints, and default values of ' + 'type\n' + 'variables created through the type parameter syntax. This means ' + 'that\n' + 'they are not evaluated when the type alias or type variable is\n' + 'created, or when the object carrying annotations is created. ' + 'Instead,\n' + 'they are only evaluated when necessary, for example when the\n' + '"__value__" attribute on a type alias is accessed.\n' '\n' 'Example:\n' '\n' @@ -6534,12 +6677,17 @@ 'exprlists': 'Expression lists\n' '****************\n' '\n' - ' expression_list ::= expression ("," expression)* [","]\n' - ' starred_list ::= starred_item ("," starred_item)* ' + ' starred_expression ::= ["*"] or_expr\n' + ' flexible_expression ::= assignment_expression | ' + 'starred_expression\n' + ' flexible_expression_list ::= flexible_expression ("," ' + 'flexible_expression)* [","]\n' + ' starred_expression_list ::= starred_expression ("," ' + 'starred_expression)* [","]\n' + ' expression_list ::= expression ("," expression)* ' '[","]\n' - ' starred_expression ::= expression | (starred_item ",")* ' - '[starred_item]\n' - ' starred_item ::= assignment_expression | "*" or_expr\n' + ' yield_list ::= expression_list | ' + 'starred_expression "," [starred_expression_list]\n' '\n' 'Except when part of a list or set display, an expression list\n' 'containing at least one comma yields a tuple. The length of ' @@ -6558,6 +6706,10 @@ 'Added in version 3.5: Iterable unpacking in expression lists,\n' 'originally proposed by **PEP 448**.\n' '\n' + 'Added in version 3.11: Any item in an expression list may be ' + 'starred.\n' + 'See **PEP 646**.\n' + '\n' 'A trailing comma is required only to create a one-item tuple, ' 'such as\n' '"1,"; it is optional in all other cases. A single expression ' @@ -6567,10 +6719,10 @@ 'that expression. (To create an empty tuple, use an empty pair ' 'of\n' 'parentheses: "()".)\n', - 'floating': 'Floating point literals\n' + 'floating': 'Floating-point literals\n' '***********************\n' '\n' - 'Floating point literals are described by the following lexical\n' + 'Floating-point literals are described by the following lexical\n' 'definitions:\n' '\n' ' floatnumber ::= pointfloat | exponentfloat\n' @@ -6584,12 +6736,12 @@ 'using\n' 'radix 10. For example, "077e010" is legal, and denotes the same ' 'number\n' - 'as "77e10". The allowed range of floating point literals is\n' + 'as "77e10". The allowed range of floating-point literals is\n' 'implementation-dependent. As in integer literals, underscores ' 'are\n' 'supported for digit grouping.\n' '\n' - 'Some examples of floating point literals:\n' + 'Some examples of floating-point literals:\n' '\n' ' 3.14 10. .001 1e100 3.14e-10 0e0 ' '3.14_15_93\n' @@ -6972,7 +7124,7 @@ '\n' 'The "\'_\'" option signals the use of an underscore for a ' 'thousands\n' - 'separator for floating point presentation types and for ' + 'separator for floating-point presentation types and for ' 'integer\n' 'presentation type "\'d\'". For integer presentation types ' '"\'b\'", "\'o\'",\n' @@ -7099,11 +7251,11 @@ '\n' 'In addition to the above presentation types, integers can ' 'be formatted\n' - 'with the floating point presentation types listed below ' + 'with the floating-point presentation types listed below ' '(except "\'n\'"\n' 'and "None"). When doing so, "float()" is used to convert ' 'the integer\n' - 'to a floating point number before formatting.\n' + 'to a floating-point number before formatting.\n' '\n' 'The available presentation types for "float" and "Decimal" ' 'values are:\n' @@ -7129,12 +7281,10 @@ 'of "6" digits |\n' ' | | after the decimal point for "float", and ' 'shows all |\n' - ' | | coefficient digits for "Decimal". If no ' - 'digits follow the |\n' - ' | | decimal point, the decimal point is also ' - 'removed unless |\n' - ' | | the "#" option is ' - 'used. |\n' + ' | | coefficient digits for "Decimal". If ' + '"p=0", the decimal |\n' + ' | | point is omitted unless the "#" option is ' + 'used. |\n' ' ' '+-----------+------------------------------------------------------------+\n' ' | "\'E\'" | Scientific notation. Same as "\'e\'" ' @@ -7153,12 +7303,10 @@ 'decimal point for |\n' ' | | "float", and uses a precision large enough ' 'to show all |\n' - ' | | coefficient digits for "Decimal". If no ' - 'digits follow the |\n' - ' | | decimal point, the decimal point is also ' - 'removed unless |\n' - ' | | the "#" option is ' - 'used. |\n' + ' | | coefficient digits for "Decimal". If ' + '"p=0", the decimal |\n' + ' | | point is omitted unless the "#" option is ' + 'used. |\n' ' ' '+-----------+------------------------------------------------------------+\n' ' | "\'F\'" | Fixed-point notation. Same as "\'f\'", ' @@ -7243,18 +7391,22 @@ 'percent sign. |\n' ' ' '+-----------+------------------------------------------------------------+\n' - ' | None | For "float" this is the same as "\'g\'", ' - 'except that when |\n' - ' | | fixed-point notation is used to format the ' - 'result, it |\n' + ' | None | For "float" this is like the "\'g\'" type, ' + 'except that when |\n' + ' | | fixed- point notation is used to format ' + 'the result, it |\n' ' | | always includes at least one digit past ' - 'the decimal point. |\n' - ' | | The precision used is as large as needed ' - 'to represent the |\n' - ' | | given value faithfully. For "Decimal", ' - 'this is the same |\n' - ' | | as either "\'g\'" or "\'G\'" depending on ' - 'the value of |\n' + 'the decimal point, |\n' + ' | | and switches to the scientific notation ' + 'when "exp >= p - |\n' + ' | | 1". When the precision is not specified, ' + 'the latter will |\n' + ' | | be as large as needed to represent the ' + 'given value |\n' + ' | | faithfully. For "Decimal", this is the ' + 'same as either |\n' + ' | | "\'g\'" or "\'G\'" depending on the value ' + 'of |\n' ' | | "context.capitals" for the current decimal ' 'context. The |\n' ' | | overall effect is to match the output of ' @@ -7444,10 +7596,12 @@ ' parameter_list_no_posonly ::= defparameter ("," ' 'defparameter)* ["," [parameter_list_starargs]]\n' ' | parameter_list_starargs\n' - ' parameter_list_starargs ::= "*" [parameter] ("," ' + ' parameter_list_starargs ::= "*" [star_parameter] ("," ' 'defparameter)* ["," ["**" parameter [","]]]\n' ' | "**" parameter [","]\n' ' parameter ::= identifier [":" expression]\n' + ' star_parameter ::= identifier [":" ["*"] ' + 'expression]\n' ' defparameter ::= parameter ["=" expression]\n' ' funcname ::= identifier\n' '\n' @@ -7575,27 +7729,22 @@ 'expression"”\n' 'following the parameter name. Any parameter may have an ' 'annotation,\n' - 'even those of the form "*identifier" or "**identifier". ' - 'Functions may\n' - 'have “return” annotation of the form “"-> expression"” after ' - 'the\n' - 'parameter list. These annotations can be any valid Python ' - 'expression.\n' - 'The presence of annotations does not change the semantics of a\n' - 'function. The annotation values are available as values of a\n' - 'dictionary keyed by the parameters’ names in the ' - '"__annotations__"\n' - 'attribute of the function object. If the "annotations" import ' - 'from\n' - '"__future__" is used, annotations are preserved as strings at ' - 'runtime\n' - 'which enables postponed evaluation. Otherwise, they are ' - 'evaluated\n' - 'when the function definition is executed. In this case ' - 'annotations\n' - 'may be evaluated in a different order than they appear in the ' - 'source\n' - 'code.\n' + 'even those of the form "*identifier" or "**identifier". (As a ' + 'special\n' + 'case, parameters of the form "*identifier" may have an ' + 'annotation “":\n' + '*expression"”.) Functions may have “return” annotation of the ' + 'form\n' + '“"-> expression"” after the parameter list. These annotations ' + 'can be\n' + 'any valid Python expression. The presence of annotations does ' + 'not\n' + 'change the semantics of a function. See Annotations for more\n' + 'information on annotations.\n' + '\n' + 'Changed in version 3.11: Parameters of the form “"*identifier"” ' + 'may\n' + 'have an annotation “": *expression"”. See **PEP 646**.\n' '\n' 'It is also possible to create anonymous functions (functions not ' 'bound\n' @@ -7669,7 +7818,7 @@ 'parameters, or as targets in "with" statements or "except" ' 'clauses, or\n' 'in a "for" target list, "class" definition, function definition,\n' - '"import" statement, or variable annotation.\n' + '"import" statement, or *variable annotations*.\n' '\n' '**CPython implementation detail:** The current implementation does ' 'not\n' @@ -7764,19 +7913,16 @@ '\n' 'Within the ASCII range (U+0001..U+007F), the valid characters ' 'for\n' - 'identifiers are the same as in Python 2.x: the uppercase and ' - 'lowercase\n' - 'letters "A" through "Z", the underscore "_" and, except for ' - 'the first\n' - 'character, the digits "0" through "9".\n' - '\n' - 'Python 3.0 introduces additional characters from outside the ' - 'ASCII\n' - 'range (see **PEP 3131**). For these characters, the ' - 'classification\n' - 'uses the version of the Unicode Character Database as ' - 'included in the\n' - '"unicodedata" module.\n' + 'identifiers include the uppercase and lowercase letters "A" ' + 'through\n' + '"Z", the underscore "_" and, except for the first character, ' + 'the\n' + 'digits "0" through "9". Python 3.0 introduced additional ' + 'characters\n' + 'from outside the ASCII range (see **PEP 3131**). For these\n' + 'characters, the classification uses the version of the ' + 'Unicode\n' + 'Character Database as included in the "unicodedata" module.\n' '\n' 'Identifiers are unlimited in length. Case is significant.\n' '\n' @@ -7826,8 +7972,8 @@ '\n' 'A non-normative HTML file listing all valid identifier ' 'characters for\n' - 'Unicode 15.1.0 can be found at\n' - 'https://www.unicode.org/Public/15.1.0/ucd/DerivedCoreProperties.txt\n' + 'Unicode 16.0.0 can be found at\n' + 'https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt\n' '\n' '\n' 'Keywords\n' @@ -7961,11 +8107,11 @@ '\n' 'An imaginary literal yields a complex number with a real part ' 'of 0.0.\n' - 'Complex numbers are represented as a pair of floating point ' + 'Complex numbers are represented as a pair of floating-point ' 'numbers\n' 'and have the same restrictions on their range. To create a ' 'complex\n' - 'number with a nonzero real part, add a floating point number to ' + 'number with a nonzero real part, add a floating-point number to ' 'it,\n' 'e.g., "(3+4j)". Some examples of imaginary literals:\n' '\n' @@ -8351,7 +8497,8 @@ 'in\n' 'square brackets:\n' '\n' - ' list_display ::= "[" [starred_list | comprehension] "]"\n' + ' list_display ::= "[" [flexible_expression_list | comprehension] ' + '"]"\n' '\n' 'A list display yields a new list object, the contents being ' 'specified\n' @@ -8545,15 +8692,18 @@ 'Annotation scopes\n' '=================\n' '\n' - 'Type parameter lists and "type" statements introduce *annotation\n' - 'scopes*, which behave mostly like function scopes, but with some\n' - 'exceptions discussed below. *Annotations* currently do not use\n' - 'annotation scopes, but they are expected to use annotation scopes ' - 'in\n' - 'Python 3.13 when **PEP 649** is implemented.\n' + '*Annotations*, type parameter lists and "type" statements ' + 'introduce\n' + '*annotation scopes*, which behave mostly like function scopes, ' + 'but\n' + 'with some exceptions discussed below.\n' '\n' 'Annotation scopes are used in the following contexts:\n' '\n' + '* *Function annotations*.\n' + '\n' + '* *Variable annotations*.\n' + '\n' '* Type parameter lists for generic type aliases.\n' '\n' '* Type parameter lists for generic functions. A generic ' @@ -8602,11 +8752,9 @@ ' can introduce new names.\n' '\n' '* While annotation scopes have an internal name, that name is not\n' - ' reflected in the *__qualname__* of objects defined within the ' - 'scope.\n' - ' Instead, the "__qualname__" of such objects is as if the object ' - 'were\n' - ' defined in the enclosing scope.\n' + ' reflected in the *qualified name* of objects defined within the\n' + ' scope. Instead, the "__qualname__" of such objects is as if the\n' + ' object were defined in the enclosing scope.\n' '\n' 'Added in version 3.12: Annotation scopes were introduced in ' 'Python\n' @@ -8615,21 +8763,25 @@ 'Changed in version 3.13: Annotation scopes are also used for type\n' 'parameter defaults, as introduced by **PEP 696**.\n' '\n' + 'Changed in version 3.14: Annotation scopes are now also used for\n' + 'annotations, as specified in **PEP 649** and **PEP 749**.\n' + '\n' '\n' 'Lazy evaluation\n' '===============\n' '\n' - 'The values of type aliases created through the "type" statement ' - 'are\n' - '*lazily evaluated*. The same applies to the bounds, constraints, ' - 'and\n' - 'default values of type variables created through the type ' - 'parameter\n' - 'syntax. This means that they are not evaluated when the type alias ' - 'or\n' - 'type variable is created. Instead, they are only evaluated when ' - 'doing\n' - 'so is necessary to resolve an attribute access.\n' + 'Most annotation scopes are *lazily evaluated*. This includes\n' + 'annotations, the values of type aliases created through the ' + '"type"\n' + 'statement, and the bounds, constraints, and default values of ' + 'type\n' + 'variables created through the type parameter syntax. This means ' + 'that\n' + 'they are not evaluated when the type alias or type variable is\n' + 'created, or when the object carrying annotations is created. ' + 'Instead,\n' + 'they are only evaluated when necessary, for example when the\n' + '"__value__" attribute on a type alias is accessed.\n' '\n' 'Example:\n' '\n' @@ -8762,8 +8914,8 @@ 'numbers': 'Numeric literals\n' '****************\n' '\n' - 'There are three types of numeric literals: integers, floating ' - 'point\n' + 'There are three types of numeric literals: integers, ' + 'floating-point\n' 'numbers, and imaginary numbers. There are no complex literals\n' '(complex numbers can be formed by adding a real number and an\n' 'imaginary number).\n' @@ -8969,13 +9121,9 @@ ' of the object truncated to an "Integral" (typically an ' '"int").\n' '\n' - ' The built-in function "int()" falls back to ' - '"__trunc__()" if\n' - ' neither "__int__()" nor "__index__()" is defined.\n' - '\n' - ' Changed in version 3.11: The delegation of "int()" to ' - '"__trunc__()"\n' - ' is deprecated.\n', + ' Changed in version 3.14: "int()" no longer delegates to ' + 'the\n' + ' "__trunc__()" method.\n', 'objects': 'Objects, values and types\n' '*************************\n' '\n' @@ -9095,16 +9243,22 @@ 'types, operations that compute new values may actually return a\n' 'reference to any existing object with the same type and value, ' 'while\n' - 'for mutable objects this is not allowed. E.g., after "a = 1; b = ' - '1",\n' - '"a" and "b" may or may not refer to the same object with the ' - 'value\n' - 'one, depending on the implementation, but after "c = []; d = []", ' - '"c"\n' - 'and "d" are guaranteed to refer to two different, unique, newly\n' - 'created empty lists. (Note that "c = d = []" assigns the same ' - 'object\n' - 'to both "c" and "d".)\n', + 'for mutable objects this is not allowed. For example, after "a = ' + '1; b\n' + '= 1", *a* and *b* may or may not refer to the same object with ' + 'the\n' + 'value one, depending on the implementation. This is because "int" ' + 'is\n' + 'an immutable type, so the reference to "1" can be reused. This\n' + 'behaviour depends on the implementation used, so should not be ' + 'relied\n' + 'upon, but is something to be aware of when making use of object\n' + 'identity tests. However, after "c = []; d = []", *c* and *d* are\n' + 'guaranteed to refer to two different, unique, newly created ' + 'empty\n' + 'lists. (Note that "e = f = []" assigns the *same* object to both ' + '*e*\n' + 'and *f*.)\n', 'operator-summary': 'Operator precedence\n' '*******************\n' '\n' @@ -9333,8 +9487,8 @@ '"complex"\n' 'number. (In earlier versions it raised a "ValueError".)\n' '\n' - 'This operation can be customized using the special "__pow__()" ' - 'method.\n', + 'This operation can be customized using the special "__pow__()" and\n' + '"__rpow__()" methods.\n', 'raise': 'The "raise" statement\n' '*********************\n' '\n' @@ -9748,9 +9902,12 @@ 'the\n' 'second argument.\n' '\n' - 'This operation can be customized using the special ' - '"__lshift__()" and\n' - '"__rshift__()" methods.\n' + 'The left shift operation can be customized using the special\n' + '"__lshift__()" and "__rlshift__()" methods. The right shift ' + 'operation\n' + 'can be customized using the special "__rshift__()" and ' + '"__rrshift__()"\n' + 'methods.\n' '\n' 'A right shift by *n* bits is defined as floor division by ' '"pow(2,n)".\n' @@ -9816,20 +9973,6 @@ 'not reported\n' 'by the "dir()" built-in function.\n' '\n' - 'object.__dict__\n' - '\n' - ' A dictionary or other mapping object used to store an ' - 'object’s\n' - ' (writable) attributes.\n' - '\n' - 'instance.__class__\n' - '\n' - ' The class to which a class instance belongs.\n' - '\n' - 'class.__bases__\n' - '\n' - ' The tuple of base classes of a class object.\n' - '\n' 'definition.__name__\n' '\n' ' The name of the class, function, method, descriptor, or ' @@ -9844,47 +9987,26 @@ '\n' ' Added in version 3.3.\n' '\n' - 'definition.__type_params__\n' - '\n' - ' The type parameters of generic classes, functions, and ' - 'type\n' - ' aliases.\n' - '\n' - ' Added in version 3.12.\n' - '\n' - 'class.__mro__\n' + 'definition.__module__\n' '\n' - ' This attribute is a tuple of classes that are considered ' - 'when\n' - ' looking for base classes during method resolution.\n' + ' The name of the module in which a class or function was ' + 'defined.\n' '\n' - 'class.mro()\n' - '\n' - ' This method can be overridden by a metaclass to customize ' - 'the\n' - ' method resolution order for its instances. It is called ' - 'at class\n' - ' instantiation, and its result is stored in "__mro__".\n' + 'definition.__doc__\n' '\n' - 'class.__subclasses__()\n' + ' The documentation string of a class or function, or ' + '"None" if\n' + ' undefined.\n' '\n' - ' Each class keeps a list of weak references to its ' - 'immediate\n' - ' subclasses. This method returns a list of all those ' - 'references\n' - ' still alive. The list is in definition order. Example:\n' - '\n' - ' >>> int.__subclasses__()\n' - " [, , , " - "]\n" - '\n' - 'class.__static_attributes__\n' + 'definition.__type_params__\n' '\n' - ' A tuple containing names of attributes of this class ' - 'which are\n' - ' accessed through "self.X" from any function in its body.\n' + ' The type parameters of generic classes, functions, and ' + 'type\n' + ' aliases. For classes and functions that are not generic, ' + 'this will\n' + ' be an empty tuple.\n' '\n' - ' Added in version 3.13.\n', + ' Added in version 3.12.\n', 'specialnames': 'Special method names\n' '********************\n' '\n' @@ -10028,6 +10150,10 @@ ' It is not guaranteed that "__del__()" methods are called ' 'for\n' ' objects that still exist when the interpreter exits.\n' + ' "weakref.finalize" provides a straightforward way to ' + 'register a\n' + ' cleanup function to be called when an object is garbage ' + 'collected.\n' '\n' ' Note:\n' '\n' @@ -10826,11 +10952,13 @@ 'the class\n' ' where it is defined. *__slots__* declared in parents are ' 'available\n' - ' in child classes. However, child subclasses will get a ' - '"__dict__"\n' - ' and *__weakref__* unless they also define *__slots__* ' - '(which should\n' - ' only contain names of any *additional* slots).\n' + ' in child classes. However, instances of a child subclass ' + 'will get a\n' + ' "__dict__" and *__weakref__* unless the subclass also ' + 'defines\n' + ' *__slots__* (which should only contain names of any ' + '*additional*\n' + ' slots).\n' '\n' '* If a class defines a slot also defined in a base class, ' 'the instance\n' @@ -11247,7 +11375,7 @@ 'built-in\n' 'types), including other ABCs.\n' '\n' - 'class.__instancecheck__(self, instance)\n' + 'type.__instancecheck__(self, instance)\n' '\n' ' Return true if *instance* should be considered a (direct ' 'or\n' @@ -11255,7 +11383,7 @@ 'implement\n' ' "isinstance(instance, class)".\n' '\n' - 'class.__subclasscheck__(self, subclass)\n' + 'type.__subclasscheck__(self, subclass)\n' '\n' ' Return true if *subclass* should be considered a (direct ' 'or\n' @@ -11909,13 +12037,9 @@ ' of the object truncated to an "Integral" (typically an ' '"int").\n' '\n' - ' The built-in function "int()" falls back to "__trunc__()" ' - 'if\n' - ' neither "__int__()" nor "__index__()" is defined.\n' - '\n' - ' Changed in version 3.11: The delegation of "int()" to ' - '"__trunc__()"\n' - ' is deprecated.\n' + ' Changed in version 3.14: "int()" no longer delegates to ' + 'the\n' + ' "__trunc__()" method.\n' '\n' '\n' 'With Statement Context Managers\n' @@ -12082,6 +12206,71 @@ ' ABC for buffer types.\n' '\n' '\n' + 'Annotations\n' + '===========\n' + '\n' + 'Functions, classes, and modules may contain *annotations*, ' + 'which are a\n' + 'way to associate information (usually *type hints*) with a ' + 'symbol.\n' + '\n' + 'object.__annotations__\n' + '\n' + ' This attribute contains the annotations for an object. It ' + 'is lazily\n' + ' evaluated, so accessing the attribute may execute ' + 'arbitrary code\n' + ' and raise exceptions. If evaluation is successful, the ' + 'attribute is\n' + ' set to a dictionary mapping from variable names to ' + 'annotations.\n' + '\n' + ' Changed in version 3.14: Annotations are now lazily ' + 'evaluated.\n' + '\n' + 'object.__annotate__(format)\n' + '\n' + ' An *annotate function*. Returns a new dictionary object ' + 'mapping\n' + ' attribute/parameter names to their annotation values.\n' + '\n' + ' Takes a format parameter specifying the format in which ' + 'annotations\n' + ' values should be provided. It must be a member of the\n' + ' "annotationlib.Format" enum, or an integer with a value\n' + ' corresponding to a member of the enum.\n' + '\n' + ' If an annotate function doesn’t support the requested ' + 'format, it\n' + ' must raise "NotImplementedError". Annotate functions must ' + 'always\n' + ' support "VALUE" format; they must not raise ' + '"NotImplementedError()"\n' + ' when called with this format.\n' + '\n' + ' When called with "VALUE" format, an annotate function ' + 'may raise\n' + ' "NameError"; it must not raise "NameError" when called ' + 'requesting\n' + ' any other format.\n' + '\n' + ' If an object does not have any annotations, ' + '"__annotate__" should\n' + ' preferably be set to "None" (it can’t be deleted), rather ' + 'than set\n' + ' to a function that returns an empty dict.\n' + '\n' + ' Added in version 3.14.\n' + '\n' + 'See also:\n' + '\n' + ' **PEP 649** — Deferred evaluation of annotation using ' + 'descriptors\n' + ' Introduces lazy evaluation of annotations and the ' + '"__annotate__"\n' + ' function.\n' + '\n' + '\n' 'Special method lookup\n' '=====================\n' '\n' @@ -12400,7 +12589,7 @@ 'the\n' ' "LC_NUMERIC" locale in some cases.\n' '\n' - 'str.format_map(mapping)\n' + 'str.format_map(mapping, /)\n' '\n' ' Similar to "str.format(**mapping)", except that ' '"mapping" is used\n' @@ -12828,11 +13017,11 @@ ' and are deemed to delimit empty strings (for example,\n' ' "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', ' '\'2\']"). The *sep* argument\n' - ' may consist of multiple characters (for example,\n' - ' "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', ' - '\'3\']"). Splitting an\n' - ' empty string with a specified separator returns ' - '"[\'\']".\n' + ' may consist of multiple characters as a single ' + 'delimiter (to split\n' + ' with multiple delimiters, use "re.split()"). Splitting ' + 'an empty\n' + ' string with a specified separator returns "[\'\']".\n' '\n' ' For example:\n' '\n' @@ -12842,6 +13031,8 @@ " ['1', '2,3']\n" " >>> '1,2,,3,'.split(',')\n" " ['1', '2', '', '3', '']\n" + " >>> '1<>2<>3<4'.split('<>')\n" + " ['1', '2', '3<4']\n" '\n' ' If *sep* is not specified or is "None", a different ' 'splitting\n' @@ -13184,15 +13375,13 @@ 'greater must be expressed with escapes.\n' '\n' 'Both string and bytes literals may optionally be prefixed with a\n' - 'letter "\'r\'" or "\'R\'"; such strings are called *raw strings* ' - 'and treat\n' - 'backslashes as literal characters. As a result, in string ' - 'literals,\n' - '"\'\\U\'" and "\'\\u\'" escapes in raw strings are not treated ' - 'specially.\n' - 'Given that Python 2.x’s raw unicode literals behave differently ' - 'than\n' - 'Python 3.x’s the "\'ur\'" syntax is not supported.\n' + 'letter "\'r\'" or "\'R\'"; such constructs are called *raw ' + 'string\n' + 'literals* and *raw bytes literals* respectively and treat ' + 'backslashes\n' + 'as literal characters. As a result, in raw string literals, ' + '"\'\\U\'"\n' + 'and "\'\\u\'" escapes are not treated specially.\n' '\n' 'Added in version 3.3: The "\'rb\'" prefix of raw bytes literals ' 'has been\n' @@ -13383,7 +13572,8 @@ '*generic\n' 'class* will generally return a GenericAlias object.\n' '\n' - ' subscription ::= primary "[" expression_list "]"\n' + ' subscription ::= primary "[" flexible_expression_list ' + '"]"\n' '\n' 'When an object is subscripted, the interpreter will ' 'evaluate the\n' @@ -13402,13 +13592,18 @@ 'see\n' '__class_getitem__ versus __getitem__.\n' '\n' - 'If the expression list contains at least one comma, it will ' - 'evaluate\n' - 'to a "tuple" containing the items of the expression list. ' - 'Otherwise,\n' - 'the expression list will evaluate to the value of the ' - 'list’s sole\n' - 'member.\n' + 'If the expression list contains at least one comma, or if ' + 'any of the\n' + 'expressions are starred, the expression list will evaluate ' + 'to a\n' + '"tuple" containing the items of the expression list. ' + 'Otherwise, the\n' + 'expression list will evaluate to the value of the list’s ' + 'sole member.\n' + '\n' + 'Changed in version 3.11: Expressions in an expression list ' + 'may be\n' + 'starred. See **PEP 646**.\n' '\n' 'For built-in objects, there are two types of objects that ' 'support\n' @@ -13522,14 +13717,15 @@ 'clauses in turn until one is found that matches the exception. An\n' 'expression-less "except" clause, if present, must be last; it ' 'matches\n' - 'any exception. For an "except" clause with an expression, that\n' - 'expression is evaluated, and the clause matches the exception if the\n' - 'resulting object is “compatible” with the exception. An object is\n' - 'compatible with an exception if the object is the class or a *non-\n' - 'virtual base class* of the exception object, or a tuple containing ' - 'an\n' - 'item that is the class or a non-virtual base class of the exception\n' - 'object.\n' + 'any exception.\n' + '\n' + 'For an "except" clause with an expression, the expression must\n' + 'evaluate to an exception type or a tuple of exception types. The\n' + 'raised exception matches an "except" clause whose expression ' + 'evaluates\n' + 'to the class or a *non-virtual base class* of the exception object, ' + 'or\n' + 'to a tuple that contains such a class.\n' '\n' 'If no "except" clause matches the exception, the search for an\n' 'exception handler continues in the surrounding code and on the\n' @@ -13658,12 +13854,13 @@ ' ...\n' " ExceptionGroup('', (BlockingIOError()))\n" '\n' - 'An "except*" clause must have a matching type, and this type cannot ' - 'be\n' - 'a subclass of "BaseExceptionGroup". It is not possible to mix ' - '"except"\n' - 'and "except*" in the same "try". "break", "continue" and "return"\n' - 'cannot appear in an "except*" clause.\n' + 'An "except*" clause must have a matching expression; it cannot be\n' + '"except*:". Furthermore, this expression cannot contain exception\n' + 'group types, because that would have ambiguous semantics.\n' + '\n' + 'It is not possible to mix "except" and "except*" in the same "try".\n' + '"break", "continue" and "return" cannot appear in an "except*" ' + 'clause.\n' '\n' '\n' '"else" clause\n' @@ -13778,11 +13975,12 @@ 'See Implementing the arithmetic operations for more details.\n' '\n' 'Changed in version 3.9: Evaluating "NotImplemented" in a boolean\n' - 'context is deprecated. While it currently evaluates as true, it ' - 'will\n' - 'emit a "DeprecationWarning". It will raise a "TypeError" in a ' - 'future\n' - 'version of Python.\n' + 'context was deprecated.\n' + '\n' + 'Changed in version 3.14: Evaluating "NotImplemented" in a boolean\n' + 'context now raises a "TypeError". It previously evaluated to ' + '"True"\n' + 'and emitted a "DeprecationWarning" since Python 3.9.\n' '\n' '\n' 'Ellipsis\n' @@ -13824,7 +14022,7 @@ '\n' '* A sign is shown only when the number is negative.\n' '\n' - 'Python distinguishes between integers, floating point numbers, and\n' + 'Python distinguishes between integers, floating-point numbers, and\n' 'complex numbers:\n' '\n' '\n' @@ -13869,28 +14067,28 @@ '"numbers.Real" ("float")\n' '------------------------\n' '\n' - 'These represent machine-level double precision floating point ' + 'These represent machine-level double precision floating-point ' 'numbers.\n' 'You are at the mercy of the underlying machine architecture (and C ' 'or\n' 'Java implementation) for the accepted range and handling of ' 'overflow.\n' - 'Python does not support single-precision floating point numbers; ' + 'Python does not support single-precision floating-point numbers; ' 'the\n' 'savings in processor and memory usage that are usually the reason ' 'for\n' 'using these are dwarfed by the overhead of using objects in Python, ' 'so\n' 'there is no reason to complicate the language with two kinds of\n' - 'floating point numbers.\n' + 'floating-point numbers.\n' '\n' '\n' '"numbers.Complex" ("complex")\n' '-----------------------------\n' '\n' 'These represent complex numbers as a pair of machine-level double\n' - 'precision floating point numbers. The same caveats apply as for\n' - 'floating point numbers. The real and imaginary parts of a complex\n' + 'precision floating-point numbers. The same caveats apply as for\n' + 'floating-point numbers. The real and imaginary parts of a complex\n' 'number "z" can be retrieved through the read-only attributes ' '"z.real"\n' 'and "z.imag".\n' @@ -14084,8 +14282,7 @@ 'however removing a key and re-inserting it will add it to the end\n' 'instead of keeping its old place.\n' '\n' - 'Dictionaries are mutable; they can be created by the "{...}" ' - 'notation\n' + 'Dictionaries are mutable; they can be created by the "{}" notation\n' '(see section Dictionary displays).\n' '\n' 'The extension modules "dbm.ndbm" and "dbm.gnu" provide additional\n' @@ -14135,13 +14332,15 @@ '| function.__closure__ | "None" or a ' '"tuple" of cells that contain bindings |\n' '| | for the ' - 'function’s free variables. A cell object |\n' - '| | has the ' - 'attribute "cell_contents". This can be |\n' - '| | used to get ' - 'the value of the cell, as well as set |\n' - '| | the ' - 'value. |\n' + 'names specified in the "co_freevars" |\n' + '| | attribute of ' + 'the function’s "code object". A cell |\n' + '| | object has ' + 'the attribute "cell_contents". This can |\n' + '| | be used to ' + 'get the value of the cell, as well as |\n' + '| | set the ' + 'value. |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '\n' '\n' @@ -14156,8 +14355,8 @@ '|====================================================|====================================================|\n' '| function.__doc__ | The ' 'function’s documentation string, or "None" if |\n' - '| | unavailable. ' - 'Not inherited by subclasses. |\n' + '| | ' + 'unavailable. |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '| function.__name__ | The ' 'function’s name. See also: "__name__ |\n' @@ -14198,9 +14397,20 @@ '| | parameter ' 'names, and "\'return\'" for the return |\n' '| | annotation, ' - 'if provided. See also: Annotations |\n' - '| | Best ' - 'Practices. |\n' + 'if provided. See also: |\n' + '| | ' + '"object.__annotations__". Changed in version |\n' + '| | 3.14: ' + 'Annotations are now lazily evaluated. See |\n' + '| | **PEP ' + '649**. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| function.__annotate__ | The ' + '*annotate function* for this function, or |\n' + '| | "None" if ' + 'the function has no annotations. See |\n' + '| | ' + '"object.__annotate__". Added in version 3.14. |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '| function.__kwdefaults__ | A ' '"dictionary" containing defaults for keyword- |\n' @@ -14305,21 +14515,10 @@ 'to\n' 'calling "f(C,1)" where "f" is the underlying function.\n' '\n' - 'Note that the transformation from function object to instance ' - 'method\n' - 'object happens each time the attribute is retrieved from the ' - 'instance.\n' - 'In some cases, a fruitful optimization is to assign the attribute ' - 'to a\n' - 'local variable and call that local variable. Also notice that this\n' - 'transformation only happens for user-defined functions; other ' - 'callable\n' - 'objects (and all non-callable objects) are retrieved without\n' - 'transformation. It is also important to note that user-defined\n' - 'functions which are attributes of a class instance are not ' - 'converted\n' - 'to bound methods; this *only* happens when the function is an\n' - 'attribute of the class.\n' + 'It is important to note that user-defined functions which are\n' + 'attributes of a class instance are not converted to bound methods;\n' + 'this *only* happens when the function is an attribute of the ' + 'class.\n' '\n' '\n' 'Generator functions\n' @@ -14456,43 +14655,279 @@ 'e.g.,\n' '"m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n' '\n' - 'Predefined (writable) attributes:\n' '\n' - ' "__name__"\n' - ' The module’s name.\n' + 'Import-related attributes on module objects\n' + '-------------------------------------------\n' + '\n' + 'Module objects have the following attributes that relate to the ' + 'import\n' + 'system. When a module is created using the machinery associated ' + 'with\n' + 'the import system, these attributes are filled in based on the\n' + 'module’s *spec*, before the *loader* executes and loads the ' + 'module.\n' + '\n' + 'To create a module dynamically rather than using the import ' + 'system,\n' + 'it’s recommended to use "importlib.util.module_from_spec()", which\n' + 'will set the various import-controlled attributes to appropriate\n' + 'values. It’s also possible to use the "types.ModuleType" ' + 'constructor\n' + 'to create modules directly, but this technique is more error-prone, ' + 'as\n' + 'most attributes must be manually set on the module object after it ' + 'has\n' + 'been created when using this approach.\n' + '\n' + 'Caution:\n' + '\n' + ' With the exception of "__name__", it is **strongly** recommended\n' + ' that you rely on "__spec__" and its attributes instead of any of ' + 'the\n' + ' other individual attributes listed in this subsection. Note that\n' + ' updating an attribute on "__spec__" will not update the\n' + ' corresponding attribute on the module itself:\n' + '\n' + ' >>> import typing\n' + ' >>> typing.__name__, typing.__spec__.name\n' + " ('typing', 'typing')\n" + " >>> typing.__spec__.name = 'spelling'\n" + ' >>> typing.__name__, typing.__spec__.name\n' + " ('typing', 'spelling')\n" + " >>> typing.__name__ = 'keyboard_smashing'\n" + ' >>> typing.__name__, typing.__spec__.name\n' + " ('keyboard_smashing', 'spelling')\n" + '\n' + 'module.__name__\n' + '\n' + ' The name used to uniquely identify the module in the import ' + 'system.\n' + ' For a directly executed module, this will be set to ' + '""__main__"".\n' + '\n' + ' This attribute must be set to the fully qualified name of the\n' + ' module. It is expected to match the value of\n' + ' "module.__spec__.name".\n' + '\n' + 'module.__spec__\n' + '\n' + ' A record of the module’s import-system-related state.\n' + '\n' + ' Set to the "module spec" that was used when importing the ' + 'module.\n' + ' See Module specs for more details.\n' + '\n' + ' Added in version 3.4.\n' + '\n' + 'module.__package__\n' + '\n' + ' The *package* a module belongs to.\n' + '\n' + ' If the module is top-level (that is, not a part of any specific\n' + ' package) then the attribute should be set to "\'\'" (the empty\n' + ' string). Otherwise, it should be set to the name of the ' + 'module’s\n' + ' package (which can be equal to "module.__name__" if the module\n' + ' itself is a package). See **PEP 366** for further details.\n' + '\n' + ' This attribute is used instead of "__name__" to calculate ' + 'explicit\n' + ' relative imports for main modules. It defaults to "None" for\n' + ' modules created dynamically using the "types.ModuleType"\n' + ' constructor; use "importlib.util.module_from_spec()" instead to\n' + ' ensure the attribute is set to a "str".\n' + '\n' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.parent" instead of "module.__package__".\n' + ' "__package__" is now only used as a fallback if ' + '"__spec__.parent"\n' + ' is not set, and this fallback path is deprecated.\n' + '\n' + ' Changed in version 3.4: This attribute now defaults to "None" ' + 'for\n' + ' modules created dynamically using the "types.ModuleType"\n' + ' constructor. Previously the attribute was optional.\n' + '\n' + ' Changed in version 3.6: The value of "__package__" is expected ' + 'to\n' + ' be the same as "__spec__.parent". "__package__" is now only used ' + 'as\n' + ' a fallback during import resolution if "__spec__.parent" is not\n' + ' defined.\n' + '\n' + ' Changed in version 3.10: "ImportWarning" is raised if an import\n' + ' resolution falls back to "__package__" instead of\n' + ' "__spec__.parent".\n' + '\n' + ' Changed in version 3.12: Raise "DeprecationWarning" instead of\n' + ' "ImportWarning" when falling back to "__package__" during ' + 'import\n' + ' resolution.\n' + '\n' + ' Deprecated since version 3.13, will be removed in version 3.15:\n' + ' "__package__" will cease to be set or taken into consideration ' + 'by\n' + ' the import system or standard library.\n' + '\n' + 'module.__loader__\n' + '\n' + ' The *loader* object that the import machinery used to load the\n' + ' module.\n' '\n' - ' "__doc__"\n' - ' The module’s documentation string, or "None" if unavailable.\n' + ' This attribute is mostly useful for introspection, but can be ' + 'used\n' + ' for additional loader-specific functionality, for example ' + 'getting\n' + ' data associated with a loader.\n' + '\n' + ' "__loader__" defaults to "None" for modules created dynamically\n' + ' using the "types.ModuleType" constructor; use\n' + ' "importlib.util.module_from_spec()" instead to ensure the ' + 'attribute\n' + ' is set to a *loader* object.\n' '\n' - ' "__file__"\n' - ' The pathname of the file from which the module was loaded, if ' - 'it\n' - ' was loaded from a file. The "__file__" attribute may be ' - 'missing\n' - ' for certain types of modules, such as C modules that are\n' - ' statically linked into the interpreter. For extension ' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.loader" instead of "module.__loader__".\n' + '\n' + ' Changed in version 3.4: This attribute now defaults to "None" ' + 'for\n' + ' modules created dynamically using the "types.ModuleType"\n' + ' constructor. Previously the attribute was optional.\n' + '\n' + ' Deprecated since version 3.12, removed in version 3.14: Setting\n' + ' "__loader__" on a module while failing to set "__spec__.loader" ' + 'is\n' + ' deprecated. In Python 3.14, "__loader__" will cease to be set ' + 'or\n' + ' taken into consideration by the import system or the standard\n' + ' library.\n' + '\n' + 'module.__path__\n' + '\n' + ' A (possibly empty) *sequence* of strings enumerating the ' + 'locations\n' + ' where the package’s submodules will be found. Non-package ' 'modules\n' - ' loaded dynamically from a shared library, it’s the pathname ' - 'of\n' - ' the shared library file.\n' + ' should not have a "__path__" attribute. See __path__ attributes ' + 'on\n' + ' modules for more details.\n' '\n' - ' "__annotations__"\n' - ' A dictionary containing *variable annotations* collected ' - 'during\n' - ' module body execution. For best practices on working with\n' - ' "__annotations__", please see Annotations Best Practices.\n' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.submodule_search_locations" instead of\n' + ' "module.__path__".\n' '\n' - 'Special read-only attribute: "__dict__" is the module’s namespace ' - 'as a\n' - 'dictionary object.\n' + 'module.__file__\n' '\n' - '**CPython implementation detail:** Because of the way CPython ' - 'clears\n' - 'module dictionaries, the module dictionary will be cleared when ' + 'module.__cached__\n' + '\n' + ' "__file__" and "__cached__" are both optional attributes that ' + 'may\n' + ' or may not be set. Both attributes should be a "str" when they ' + 'are\n' + ' available.\n' + '\n' + ' "__file__" indicates the pathname of the file from which the ' + 'module\n' + ' was loaded (if loaded from a file), or the pathname of the ' + 'shared\n' + ' library file for extension modules loaded dynamically from a ' + 'shared\n' + ' library. It might be missing for certain types of modules, such ' + 'as\n' + ' C modules that are statically linked into the interpreter, and ' 'the\n' - 'module falls out of scope even if the dictionary still has live\n' - 'references. To avoid this, copy the dictionary or keep the module\n' - 'around while using its dictionary directly.\n' + ' import system may opt to leave it unset if it has no semantic\n' + ' meaning (for example, a module loaded from a database).\n' + '\n' + ' If "__file__" is set then the "__cached__" attribute might also ' + 'be\n' + ' set, which is the path to any compiled version of the code ' + '(for\n' + ' example, a byte-compiled file). The file does not need to exist ' + 'to\n' + ' set this attribute; the path can simply point to where the ' + 'compiled\n' + ' file *would* exist (see **PEP 3147**).\n' + '\n' + ' Note that "__cached__" may be set even if "__file__" is not ' + 'set.\n' + ' However, that scenario is quite atypical. Ultimately, the ' + '*loader*\n' + ' is what makes use of the module spec provided by the *finder* ' + '(from\n' + ' which "__file__" and "__cached__" are derived). So if a loader ' + 'can\n' + ' load from a cached module but otherwise does not load from a ' + 'file,\n' + ' that atypical scenario may be appropriate.\n' + '\n' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.cached" instead of "module.__cached__".\n' + '\n' + ' Deprecated since version 3.13, will be removed in version 3.15:\n' + ' Setting "__cached__" on a module while failing to set\n' + ' "__spec__.cached" is deprecated. In Python 3.15, "__cached__" ' + 'will\n' + ' cease to be set or taken into consideration by the import system ' + 'or\n' + ' standard library.\n' + '\n' + '\n' + 'Other writable attributes on module objects\n' + '-------------------------------------------\n' + '\n' + 'As well as the import-related attributes listed above, module ' + 'objects\n' + 'also have the following writable attributes:\n' + '\n' + 'module.__doc__\n' + '\n' + ' The module’s documentation string, or "None" if unavailable. ' + 'See\n' + ' also: "__doc__ attributes".\n' + '\n' + 'module.__annotations__\n' + '\n' + ' A dictionary containing *variable annotations* collected during\n' + ' module body execution. For best practices on working with\n' + ' "__annotations__", see "annotationlib".\n' + '\n' + ' Changed in version 3.14: Annotations are now lazily evaluated. ' + 'See\n' + ' **PEP 649**.\n' + '\n' + 'module.__annotate__\n' + '\n' + ' The *annotate function* for this module, or "None" if the ' + 'module\n' + ' has no annotations. See also: "__annotate__" attributes.\n' + '\n' + ' Added in version 3.14.\n' + '\n' + '\n' + 'Module dictionaries\n' + '-------------------\n' + '\n' + 'Module objects also have the following special read-only ' + 'attribute:\n' + '\n' + 'module.__dict__\n' + '\n' + ' The module’s namespace as a dictionary object. Uniquely among ' + 'the\n' + ' attributes listed here, "__dict__" cannot be accessed as a ' + 'global\n' + ' variable from within a module; it can only be accessed as an\n' + ' attribute on module objects.\n' + '\n' + ' **CPython implementation detail:** Because of the way CPython\n' + ' clears module dictionaries, the module dictionary will be ' + 'cleared\n' + ' when the module falls out of scope even if the dictionary still ' + 'has\n' + ' live references. To avoid this, copy the dictionary or keep ' + 'the\n' + ' module around while using its dictionary directly.\n' '\n' '\n' 'Custom classes\n' @@ -14538,41 +14973,147 @@ 'A class object can be called (see above) to yield a class instance\n' '(see below).\n' '\n' - 'Special attributes:\n' '\n' - ' "__name__"\n' - ' The class name.\n' + 'Special attributes\n' + '------------------\n' '\n' - ' "__module__"\n' - ' The name of the module in which the class was defined.\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| Attribute | ' + 'Meaning |\n' + '|====================================================|====================================================|\n' + '| type.__name__ | The class’s ' + 'name. See also: "__name__ attributes". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__qualname__ | The class’s ' + '*qualified name*. See also: |\n' + '| | ' + '"__qualname__ attributes". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__module__ | The name of ' + 'the module in which the class was |\n' + '| | ' + 'defined. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__dict__ | A "mapping ' + 'proxy" providing a read-only view of |\n' + '| | the class’s ' + 'namespace. See also: "__dict__ |\n' + '| | ' + 'attributes". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__bases__ | A "tuple" ' + 'containing the class’s bases. In most |\n' + '| | cases, for a ' + 'class defined as "class X(A, B, C)", |\n' + '| | ' + '"X.__bases__" will be exactly equal to "(A, B, |\n' + '| | ' + 'C)". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__doc__ | The class’s ' + 'documentation string, or "None" if |\n' + '| | undefined. ' + 'Not inherited by subclasses. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__annotations__ | A dictionary ' + 'containing *variable annotations* |\n' + '| | collected ' + 'during class body execution. See also: |\n' + '| | ' + '"__annotations__ attributes". For best practices |\n' + '| | on working ' + 'with "__annotations__", please see |\n' + '| | ' + '"annotationlib". Caution: Accessing the |\n' + '| | ' + '"__annotations__" attribute of a class object |\n' + '| | directly may ' + 'yield incorrect results in the |\n' + '| | presence of ' + 'metaclasses. In addition, the |\n' + '| | attribute ' + 'may not exist for some classes. Use |\n' + '| | ' + '"annotationlib.get_annotations()" to retrieve |\n' + '| | class ' + 'annotations safely. Changed in version |\n' + '| | 3.14: ' + 'Annotations are now lazily evaluated. See |\n' + '| | **PEP ' + '649**. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__annotate__() | The ' + '*annotate function* for this class, or "None" |\n' + '| | if the class ' + 'has no annotations. See also: |\n' + '| | ' + '"__annotate__ attributes". Caution: Accessing |\n' + '| | the ' + '"__annotate__" attribute of a class object |\n' + '| | directly may ' + 'yield incorrect results in the |\n' + '| | presence of ' + 'metaclasses. Use |\n' + '| | ' + '"annotationlib.get_annotate_function()" to |\n' + '| | retrieve the ' + 'annotate function safely. Added in |\n' + '| | version ' + '3.14. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__type_params__ | A "tuple" ' + 'containing the type parameters of a |\n' + '| | generic ' + 'class. Added in version 3.12. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__static_attributes__ | A "tuple" ' + 'containing names of attributes of this |\n' + '| | class which ' + 'are assigned through "self.X" from any |\n' + '| | function in ' + 'its body. Added in version 3.13. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__firstlineno__ | The line ' + 'number of the first line of the class |\n' + '| | definition, ' + 'including decorators. Setting the |\n' + '| | "__module__" ' + 'attribute removes the |\n' + '| | ' + '"__firstlineno__" item from the type’s dictionary. |\n' + '| | Added in ' + 'version 3.13. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__mro__ | The "tuple" ' + 'of classes that are considered when |\n' + '| | looking for ' + 'base classes during method resolution. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' '\n' - ' "__dict__"\n' - ' The dictionary containing the class’s namespace.\n' '\n' - ' "__bases__"\n' - ' A tuple containing the base classes, in the order of their\n' - ' occurrence in the base class list.\n' + 'Special methods\n' + '---------------\n' + '\n' + 'In addition to the special attributes described above, all Python\n' + 'classes also have the following two methods available:\n' '\n' - ' "__doc__"\n' - ' The class’s documentation string, or "None" if undefined.\n' + 'type.mro()\n' '\n' - ' "__annotations__"\n' - ' A dictionary containing *variable annotations* collected ' - 'during\n' - ' class body execution. For best practices on working with\n' - ' "__annotations__", please see Annotations Best Practices.\n' + ' This method can be overridden by a metaclass to customize the\n' + ' method resolution order for its instances. It is called at ' + 'class\n' + ' instantiation, and its result is stored in "__mro__".\n' '\n' - ' "__type_params__"\n' - ' A tuple containing the type parameters of a generic class.\n' + 'type.__subclasses__()\n' '\n' - ' "__static_attributes__"\n' - ' A tuple containing names of attributes of this class which ' - 'are\n' - ' accessed through "self.X" from any function in its body.\n' + ' Each class keeps a list of weak references to its immediate\n' + ' subclasses. This method returns a list of all those references\n' + ' still alive. The list is in definition order. Example:\n' '\n' - ' "__firstlineno__"\n' - ' The line number of the first line of the class definition,\n' - ' including decorators.\n' + ' >>> class A: pass\n' + ' >>> class B(A): pass\n' + ' >>> A.__subclasses__()\n' + " []\n" '\n' '\n' 'Class instances\n' @@ -14612,8 +15153,19 @@ 'they have methods with certain special names. See section Special\n' 'method names.\n' '\n' - 'Special attributes: "__dict__" is the attribute dictionary;\n' - '"__class__" is the instance’s class.\n' + '\n' + 'Special attributes\n' + '------------------\n' + '\n' + 'object.__class__\n' + '\n' + ' The class to which a class instance belongs.\n' + '\n' + 'object.__dict__\n' + '\n' + ' A dictionary or other mapping object used to store an object’s\n' + ' (writable) attributes. Not all instances have a "__dict__"\n' + ' attribute; see the section on __slots__ for more details.\n' '\n' '\n' 'I/O objects (also known as file objects)\n' @@ -14712,14 +15264,20 @@ '| codeobject.co_cellvars | A "tuple" ' 'containing the names of local variables |\n' '| | that are ' - 'referenced by nested functions inside the |\n' - '| | ' - 'function |\n' + 'referenced from at least one *nested |\n' + '| | scope* ' + 'inside the function |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '| codeobject.co_freevars | A "tuple" ' - 'containing the names of free variables |\n' - '| | in the ' - 'function |\n' + 'containing the names of *free (closure) |\n' + '| | variables* ' + 'that a *nested scope* references in an |\n' + '| | outer scope. ' + 'See also "function.__closure__". |\n' + '| | Note: ' + 'references to global and builtin names are |\n' + '| | *not* ' + 'included. |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '| codeobject.co_code | A string ' 'representing the sequence of *bytecode* |\n' @@ -14804,10 +15362,10 @@ ' The iterator returns "tuple"s containing the "(start_line,\n' ' end_line, start_column, end_column)". The *i-th* tuple ' 'corresponds\n' - ' to the position of the source code that compiled to the *i-th*\n' - ' instruction. Column information is 0-indexed utf-8 byte offsets ' - 'on\n' - ' the given source line.\n' + ' to the position of the source code that compiled to the *i-th* ' + 'code\n' + ' unit. Column information is 0-indexed utf-8 byte offsets on the\n' + ' given source line.\n' '\n' ' This positional information can be missing. A non-exhaustive ' 'lists\n' @@ -14932,16 +15490,16 @@ '| | ' '""f_code"". |\n' '+----------------------------------------------------+----------------------------------------------------+\n' - '| frame.f_locals | The ' - 'dictionary used by the frame to look up local |\n' + '| frame.f_locals | The mapping ' + 'used by the frame to look up local |\n' '| | variables. ' - 'If the frame refers to a function or |\n' - '| | ' - 'comprehension, this may return a write- through |\n' - '| | proxy ' - 'object. Changed in version 3.13: Return a |\n' - '| | proxy for ' - 'functions and comprehensions. |\n' + 'If the frame refers to an *optimized |\n' + '| | scope*, this ' + 'may return a write-through proxy |\n' + '| | object. ' + 'Changed in version 3.13: Return a proxy |\n' + '| | for ' + 'optimized scopes. |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '| frame.f_globals | The ' 'dictionary used by the frame to look up global |\n' @@ -15223,21 +15781,23 @@ '\n' ' If no positional argument is given, an empty dictionary ' 'is created.\n' - ' If a positional argument is given and it is a mapping ' - 'object, a\n' - ' dictionary is created with the same key-value pairs as ' - 'the mapping\n' - ' object. Otherwise, the positional argument must be an ' - '*iterable*\n' - ' object. Each item in the iterable must itself be an ' - 'iterable with\n' - ' exactly two objects. The first object of each item ' - 'becomes a key\n' - ' in the new dictionary, and the second object the ' - 'corresponding\n' - ' value. If a key occurs more than once, the last value ' - 'for that key\n' - ' becomes the corresponding value in the new dictionary.\n' + ' If a positional argument is given and it defines a ' + '"keys()" method,\n' + ' a dictionary is created by calling "__getitem__()" on the ' + 'argument\n' + ' with each returned key from the method. Otherwise, the ' + 'positional\n' + ' argument must be an *iterable* object. Each item in the ' + 'iterable\n' + ' must itself be an iterable with exactly two elements. ' + 'The first\n' + ' element of each item becomes a key in the new dictionary, ' + 'and the\n' + ' second element the corresponding value. If a key occurs ' + 'more than\n' + ' once, the last value for that key becomes the ' + 'corresponding value\n' + ' in the new dictionary.\n' '\n' ' If keyword arguments are given, the keyword arguments and ' 'their\n' @@ -15350,7 +15910,7 @@ '\n' ' Return a shallow copy of the dictionary.\n' '\n' - ' classmethod fromkeys(iterable[, value])\n' + ' classmethod fromkeys(iterable, value=None, /)\n' '\n' ' Create a new dictionary with keys from *iterable* and ' 'values set\n' @@ -15366,7 +15926,7 @@ 'distinct\n' ' values, use a dict comprehension instead.\n' '\n' - ' get(key[, default])\n' + ' get(key, default=None)\n' '\n' ' Return the value for *key* if *key* is in the ' 'dictionary, else\n' @@ -15418,7 +15978,7 @@ '\n' ' Added in version 3.8.\n' '\n' - ' setdefault(key[, default])\n' + ' setdefault(key, default=None)\n' '\n' ' If *key* is in the dictionary, return its value. If ' 'not, insert\n' @@ -15432,15 +15992,17 @@ '*other*,\n' ' overwriting existing keys. Return "None".\n' '\n' - ' "update()" accepts either another dictionary object or ' - 'an\n' - ' iterable of key/value pairs (as tuples or other ' - 'iterables of\n' - ' length two). If keyword arguments are specified, the ' - 'dictionary\n' - ' is then updated with those key/value pairs: ' - '"d.update(red=1,\n' - ' blue=2)".\n' + ' "update()" accepts either another object with a ' + '"keys()" method\n' + ' (in which case "__getitem__()" is called with every ' + 'key returned\n' + ' from the method). or an iterable of key/value pairs ' + '(as tuples\n' + ' or other iterables of length two). If keyword ' + 'arguments are\n' + ' specified, the dictionary is then updated with those ' + 'key/value\n' + ' pairs: "d.update(red=1, blue=2)".\n' '\n' ' values()\n' '\n' @@ -16105,8 +16667,8 @@ '| | also removes it from ' '*s* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' - '| "s.remove(x)" | remove the first item from ' - '*s* | (3) |\n' + '| "s.remove(x)" | removes the first item from ' + '*s* | (3) |\n' '| | where "s[i]" is equal to ' '*x* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' @@ -16118,7 +16680,9 @@ '\n' 'Notes:\n' '\n' - '1. *t* must have the same length as the slice it is replacing.\n' + '1. If *k* is not equal to "1", *t* must have the same length as ' + 'the\n' + ' slice it is replacing.\n' '\n' '2. The optional argument *i* defaults to "-1", so that by ' 'default the\n' @@ -16475,7 +17039,7 @@ '\n' ' * The linspace recipe shows how to implement a lazy version of ' 'range\n' - ' suitable for floating point applications.\n', + ' suitable for floating-point applications.\n', 'typesseq-mutable': 'Mutable Sequence Types\n' '**********************\n' '\n' @@ -16568,8 +17132,8 @@ '| | also removes it from ' '*s* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' - '| "s.remove(x)" | remove the first item ' - 'from *s* | (3) |\n' + '| "s.remove(x)" | removes the first ' + 'item from *s* | (3) |\n' '| | where "s[i]" is equal ' 'to *x* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' @@ -16582,8 +17146,9 @@ '\n' 'Notes:\n' '\n' - '1. *t* must have the same length as the slice it is ' - 'replacing.\n' + '1. If *k* is not equal to "1", *t* must have the same ' + 'length as the\n' + ' slice it is replacing.\n' '\n' '2. The optional argument *i* defaults to "-1", so that ' 'by default the\n' diff --git a/Misc/NEWS.d/3.14.0a1.rst b/Misc/NEWS.d/3.14.0a1.rst new file mode 100644 index 00000000000000..dfc33812611185 --- /dev/null +++ b/Misc/NEWS.d/3.14.0a1.rst @@ -0,0 +1,6604 @@ +.. date: 2024-09-24-10-48-46 +.. gh-issue: 124448 +.. nonce: bFMrS6 +.. release date: 2024-10-15 +.. section: macOS + +Update bundled Tcl/Tk in macOS installer to 8.6.15. + +.. + +.. date: 2024-09-07-12-14-54 +.. gh-issue: 123797 +.. nonce: yFDeug +.. section: macOS + +Check for runtime availability of ``ptsname_r`` function on macos. + +.. + +.. date: 2024-09-04-11-55-29 +.. gh-issue: 123418 +.. nonce: 8P4bmN +.. section: macOS + +Updated macOS installer build to use OpenSSL 3.0.15. + +.. + +.. date: 2024-09-27-15-07-30 +.. gh-issue: 124487 +.. nonce: 7LrwHC +.. section: Windows + +Increases Windows required OS and API level to Windows 10. + +.. + +.. date: 2024-09-27-13-40-25 +.. gh-issue: 124609 +.. nonce: WaKk8G +.. section: Windows + +Fix ``_Py_ThreadId`` for Windows builds using MinGW. Patch by Tony Roberts. + +.. + +.. date: 2024-09-24-19-04-56 +.. gh-issue: 124448 +.. nonce: srVT3d +.. section: Windows + +Updated bundled Tcl/Tk to 8.6.15. + +.. + +.. date: 2024-09-20-11-18-50 +.. gh-issue: 124254 +.. nonce: iPin-L +.. section: Windows + +Ensures experimental free-threaded binaries remain installed when updating. + +.. + +.. date: 2024-09-10-19-23-00 +.. gh-issue: 123915 +.. nonce: yZMEDO +.. section: Windows + +Ensure that ``Tools\msi\buildrelease.bat`` uses different directories for +AMD64 and ARM64 builds. + +.. + +.. date: 2024-09-04-09-59-18 +.. gh-issue: 123418 +.. nonce: QaMC12 +.. section: Windows + +Updated Windows build to use OpenSSL 3.0.15. + +.. + +.. date: 2024-08-29-16-13-45 +.. gh-issue: 123476 +.. nonce: m2DFS4 +.. section: Windows + +Add support for ``socket.TCP_QUICKACK`` on Windows platforms. + +.. + +.. date: 2024-08-01-10-55-15 +.. gh-issue: 122573 +.. nonce: 4-UCFY +.. section: Windows + +The Windows build of CPython now requires 3.10 or newer. + +.. + +.. date: 2024-07-19-21-50-54 +.. gh-issue: 100256 +.. nonce: GDrKba +.. section: Windows + +:mod:`mimetypes` no longer fails when it encounters an inaccessible registry +key. + +.. + +.. date: 2024-05-30-17-39-25 +.. gh-issue: 119679 +.. nonce: mZC87w +.. section: Windows + +Ensures correct import libraries are included in Windows installs. + +.. + +.. date: 2024-05-29-11-06-12 +.. gh-issue: 119690 +.. nonce: 8q6e1p +.. section: Windows + +Adds Unicode support and fixes audit events for ``_winapi.CreateNamedPipe``. + +.. + +.. date: 2024-05-25-18-43-10 +.. gh-issue: 111201 +.. nonce: SLPJIx +.. section: Windows + +Add support for new pyrepl on Windows + +.. + +.. date: 2024-05-22-19-43-29 +.. gh-issue: 119070 +.. nonce: _enton +.. section: Windows + +Fixes ``py.exe`` handling of shebangs like ``/usr/bin/env python3.12``, +which were previously interpreted as ``python3.exe`` instead of +``python3.12.exe``. + +.. + +.. date: 2024-04-24-22-50-33 +.. gh-issue: 117505 +.. nonce: gcTb_p +.. section: Windows + +Fixes an issue with the Windows installer not running ensurepip in a fully +isolated environment. This could cause unexpected interactions with the user +site-packages. + +.. + +.. date: 2024-04-24-05-16-32 +.. gh-issue: 118209 +.. nonce: Ryyzlz +.. section: Windows + +Avoid crashing in :mod:`mmap` on Windows when the mapped memory is +inaccessible due to file system errors or access violations. + +.. + +.. date: 2022-04-20-18-32-30 +.. gh-issue: 79846 +.. nonce: Vggv3f +.. section: Windows + +Makes :code:`ssl.create_default_context()` ignore invalid certificates in +the Windows certificate store + +.. + +.. date: 2024-09-04-10-07-51 +.. gh-issue: 123418 +.. nonce: 1eIFZb +.. section: Tools/Demos + +Update GitHub CI workflows to use OpenSSL 3.0.15 and multissltests to use +3.0.15, 3.1.7, and 3.2.3. + +.. + +.. date: 2024-10-07-14-13-38 +.. gh-issue: 125041 +.. nonce: PKLWDf +.. section: Tests + +Re-enable skipped tests for :mod:`zlib` on the s390x architecture: only skip +checks of the compressed bytes, which can be different between zlib's +software implementation and the hardware-accelerated implementation. + +.. + +.. date: 2024-09-25-12-39-34 +.. gh-issue: 124378 +.. nonce: Ywwgia +.. section: Tests + +Updated ``test_ttk`` to pass with Tcl/Tk 8.6.15. + +.. + +.. date: 2024-09-18-18-39-21 +.. gh-issue: 124213 +.. nonce: AQq_xg +.. section: Tests + +Detect whether the test suite is running inside a systemd-nspawn container +with ``--suppress-sync=true`` option, and skip the ``test_os`` and +``test_mmap`` tests that are failing in this scenario. + +.. + +.. date: 2024-09-17-22-21-58 +.. gh-issue: 124190 +.. nonce: 3fWhiX +.. section: Tests + +Add capability to ignore entire files or directories in check warning CI +tool + +.. + +.. date: 2024-07-17-08-25-06 +.. gh-issue: 121921 +.. nonce: HW8CIS +.. section: Tests + +Update ``Lib/test/crashers/bogus_code_obj.py`` so that it crashes properly +again. + +.. + +.. date: 2024-07-13-21-55-58 +.. gh-issue: 112301 +.. nonce: YJS1dl +.. section: Tests + +Add tooling to check for changes in compiler warnings. Patch by Nate Ohlson. + +.. + +.. date: 2024-07-13-11-48-20 +.. gh-issue: 59022 +.. nonce: fYNbQ8 +.. section: Tests + +Add tests for :func:`pkgutil.extend_path`. Patch by Andreas Stocker. + +.. + +.. date: 2024-07-13-11-04-44 +.. gh-issue: 99242 +.. nonce: aGxnwz +.. section: Tests + +:func:`os.getloadavg` may throw :exc:`OSError` when running regression tests +under certain conditions (e.g. chroot). This error is now caught and +ignored, since reporting load average is optional. + +.. + +.. date: 2024-07-04-15-10-29 +.. gh-issue: 121084 +.. nonce: qxcd5d +.. section: Tests + +Fix test_typing random leaks. Clear typing ABC caches when running tests for +refleaks (``-R`` option): call ``_abc_caches_clear()`` on typing abstract +classes and their subclasses. Patch by Victor Stinner. + +.. + +.. date: 2024-07-03-14-41-00 +.. gh-issue: 121160 +.. nonce: LEtiTd +.. section: Tests + +Add a test for :func:`readline.set_history_length`. Note that this test may +fail on readline libraries. + +.. + +.. date: 2024-07-01-16-15-06 +.. gh-issue: 121200 +.. nonce: 4Pc-gc +.. section: Tests + +Fix ``test_expanduser_pwd2()`` of ``test_posixpath``. Call ``getpwnam()`` +to get ``pw_dir``, since it can be different than ``getpwall()`` ``pw_dir``. +Patch by Victor Stinner. + +.. + +.. date: 2024-07-01-09-04-32 +.. gh-issue: 121188 +.. nonce: XbuTVa +.. section: Tests + +When creating the JUnit XML file, regrtest now escapes characters which are +invalid in XML, such as the chr(27) control character used in ANSI escape +sequences. Patch by Victor Stinner. + +.. + +.. date: 2024-06-20-12-51-26 +.. gh-issue: 120801 +.. nonce: lMVXC9 +.. section: Tests + +Cleaned up fixtures for importlib.metadata tests and consolidated behavior +with 'test.support.os_helper'. + +.. + +.. date: 2024-05-29-15-28-08 +.. gh-issue: 119727 +.. nonce: dVkaZM +.. section: Tests + +Add ``--single-process`` command line option to Python test runner +(regrtest). Patch by Victor Stinner. + +.. + +.. date: 2024-05-20-18-06-31 +.. gh-issue: 119273 +.. nonce: hf-yhX +.. section: Tests + +Python test runner no longer runs tests using TTY (ex: test_ioctl) in a +process group (using ``setsid()``). Previously, tests using TTY were +skipped. Patch by Victor Stinner. + +.. + +.. date: 2024-05-18-10-59-27 +.. gh-issue: 119050 +.. nonce: g4qiH7 +.. section: Tests + +regrtest test runner: Add XML support to the refleak checker (-R option). +Patch by Victor Stinner. + +.. + +.. date: 2024-05-04-22-56-41 +.. gh-issue: 101525 +.. nonce: LHK166 +.. section: Tests + +Skip ``test_gdb`` if the binary is relocated by BOLT. Patch by Donghee Na. + +.. + +.. date: 2023-08-03-17-26-55 +.. gh-issue: 107562 +.. nonce: ZnbscS +.. section: Tests + +Test certificates have been updated to expire far in the future. This allows +testing Y2038 with system time set to after that, so that actual Y2038 +issues can be exposed, and not masked by expired certificate errors. + +.. + +.. date: 2024-10-09-20-08-13 +.. gh-issue: 125140 +.. nonce: YgNWRB +.. section: Security + +Remove the current directory from ``sys.path`` when using PyREPL. + +.. + +.. date: 2024-09-04-12-41-35 +.. gh-issue: 123678 +.. nonce: N41y9n +.. section: Security + +Upgrade libexpat to 2.6.3 + +.. + +.. date: 2024-08-14-19-43-57 +.. gh-issue: 112301 +.. nonce: IQUcOy +.. section: Security + +Enable compiler options that warn of potential security vulnerabilities. + +.. + +.. date: 2024-08-07-10-42-13 +.. gh-issue: 122792 +.. nonce: oiTMo9 +.. section: Security + +Changed IPv4-mapped ``ipaddress.IPv6Address`` to consistently use the mapped +IPv4 address value for deciding properties. Properties which have their +behavior fixed are ``is_multicast``, ``is_reserved``, ``is_link_local``, +``is_global``, and ``is_unspecified``. + +.. + +.. date: 2024-08-06-00-06-23 +.. gh-issue: 112301 +.. nonce: 4k4lw6 +.. section: Security + +Add ability to ignore warnings per file with warning count in warning +checking tooling. Patch by Nate Ohlson. + +.. + +.. date: 2024-07-24-05-18-25 +.. gh-issue: 112301 +.. nonce: lfINgZ +.. section: Security + +Add macOS warning tracking to warning check tooling. Patch by Nate Ohlson. + +.. + +.. date: 2024-07-22-13-11-28 +.. gh-issue: 122133 +.. nonce: 0mPeta +.. section: Security + +Authenticate the socket connection for the ``socket.socketpair()`` fallback +on platforms where ``AF_UNIX`` is not available like Windows. + +Patch by Gregory P. Smith and Seth Larson +. Reported by Ellie + +.. + +.. date: 2024-07-18-13-17-47 +.. gh-issue: 121957 +.. nonce: QemKLU +.. section: Security + +Fixed missing audit events around interactive use of Python, now also +properly firing for ``python -i``, as well as for ``python -m asyncio``. The +events in question are ``cpython.run_stdin`` and ``cpython.run_startup``. + +.. + +.. date: 2024-07-08-23-39-04 +.. gh-issue: 112301 +.. nonce: TD8G01 +.. section: Security + +Enable runtime protections for glibc to abort execution when unsafe behavior +is encountered, for all platforms except Windows. + +.. + +.. date: 2024-07-02-13-39-20 +.. gh-issue: 121285 +.. nonce: hrl-yI +.. section: Security + +Remove backtracking from tarfile header parsing for ``hdrcharset``, PAX, and +GNU sparse headers. + +.. + +.. date: 2024-06-25-04-42-43 +.. gh-issue: 112301 +.. nonce: god4IC +.. section: Security + +Add default compiler options to improve security. Enable +-Wimplicit-fallthrough, -fstack-protector-strong, -Wtrampolines. + +.. + +.. date: 2024-05-08-21-59-38 +.. gh-issue: 118773 +.. nonce: 7dFRJY +.. section: Security + +Fixes creation of ACLs in :func:`os.mkdir` on Windows to work correctly on +non-English machines. + +.. + +.. date: 2024-05-01-20-57-09 +.. gh-issue: 118486 +.. nonce: K44KJG +.. section: Security + +:func:`os.mkdir` on Windows now accepts *mode* of ``0o700`` to restrict the +new directory to the current user. This fixes :cve:`2024-4030` affecting +:func:`tempfile.mkdtemp` in scenarios where the base temporary directory is +more permissive than the default. + +.. + +.. date: 2024-10-14-04-44-12 +.. gh-issue: 125422 +.. nonce: MlVuC6 +.. section: Library + +Fixed the bug where :mod:`pdb` and :mod:`bdb` can step into the bottom +caller frame. + +.. + +.. date: 2024-10-14-02-27-03 +.. gh-issue: 100141 +.. nonce: NuAcwa +.. section: Library + +Fixed the bug where :mod:`pdb` will be stuck in an infinite loop when +debugging an empty file. + +.. + +.. date: 2024-10-13-20-21-35 +.. gh-issue: 53203 +.. nonce: Rz1c8A +.. section: Library + +Fix :func:`time.strptime` for ``%c``, ``%x`` and ``%X`` formats in many +locales that use non-ASCII digits, like Persian, Burmese, Odia and Shan. + +.. + +.. date: 2024-10-11-18-03-05 +.. gh-issue: 125206 +.. nonce: pWRRK6 +.. section: Library + +Workaround for old libffi versions is added. Module ctypes supports +:c:expr:`double complex` only with libffi >= 3.3.0. Patch by Mikhail Efimov. + +.. + +.. date: 2024-10-11-16-19-46 +.. gh-issue: 89967 +.. nonce: vhWUOR +.. section: Library + +Make :class:`~weakref.WeakKeyDictionary` and +:class:`~weakref.WeakValueDictionary` safe against concurrent mutations from +other threads. Patch by Kumar Aditya. + +.. + +.. date: 2024-10-11-04-04-38 +.. gh-issue: 125260 +.. nonce: PeZ0Mb +.. section: Library + +The :func:`gzip.compress` *mtime* parameter now defaults to 0 for +reproducible output. Patch by Bernhard M. Wiedemann and Adam Turner. + +.. + +.. date: 2024-10-10-20-39-57 +.. gh-issue: 125243 +.. nonce: eUbbtu +.. section: Library + +Fix data race when creating :class:`zoneinfo.ZoneInfo` objects in the free +threading build. + +.. + +.. date: 2024-10-10-19-57-35 +.. gh-issue: 125254 +.. nonce: RtZxXS +.. section: Library + +Fix a bug where ArgumentError includes the incorrect ambiguous option in +:mod:`argparse`. + +.. + +.. date: 2024-10-10-18-33-31 +.. gh-issue: 125235 +.. nonce: 0kOB5I +.. section: Library + +Keep :mod:`tkinter` TCL paths in venv pointing to base installation on +Windows. + +.. + +.. date: 2024-10-09-21-42-43 +.. gh-issue: 61011 +.. nonce: pQXZb1 +.. section: Library + +Fix inheritance of nested mutually exclusive groups from parent parser in +:class:`argparse.ArgumentParser`. Previously, all nested mutually exclusive +groups lost their connection to the group containing them and were displayed +as belonging directly to the parser. + +.. + +.. date: 2024-10-09-07-09-00 +.. gh-issue: 125118 +.. nonce: J9rQ1S +.. section: Library + +Don't copy arbitrary values to :c:expr:`_Bool` in the :mod:`struct` module. + +.. + +.. date: 2024-10-08-21-17-16 +.. gh-issue: 125069 +.. nonce: 0RP0Mx +.. section: Library + +Fix an issue where providing a :class:`pathlib.PurePath` object as an +initializer argument to a second :class:`~pathlib.PurePath` object with a +different :attr:`~pathlib.PurePath.parser` resulted in arguments to the +former object's initializer being joined by the latter object's parser. + +.. + +.. date: 2024-10-08-13-28-22 +.. gh-issue: 125096 +.. nonce: Vz0W5g +.. section: Library + +If the :envvar:`PYTHON_BASIC_REPL` environment variable is set, the +:mod:`site` module no longer imports the :mod:`!_pyrepl` module. Moreover, +the :mod:`site` module now respects :option:`-E` and :option:`-I` command +line options: ignore :envvar:`PYTHON_BASIC_REPL` in this case. Patch by +Victor Stinner. + +.. + +.. date: 2024-10-08-12-09-09 +.. gh-issue: 124969 +.. nonce: _VBQLq +.. section: Library + +Fix ``locale.nl_langinfo(locale.ALT_DIGITS)``. Now it returns a tuple of up +to 100 strings (an empty tuple on most locales). Previously it returned the +first item of that tuple or an empty string. + +.. + +.. date: 2024-10-05-15-49-53 +.. gh-issue: 124960 +.. nonce: Bol9hT +.. section: Library + +Fix support for the ``barry_as_FLUFL`` future flag in the new REPL. + +.. + +.. date: 2024-10-04-12-43-03 +.. gh-issue: 69998 +.. nonce: DVqOXX +.. section: Library + +Fix :func:`locale.nl_langinfo` in case when different categories have +different locales. The function now sets temporarily the ``LC_CTYPE`` locale +in some cases. This temporary change affects other threads. + +.. + +.. date: 2024-10-04-08-46-00 +.. gh-issue: 124958 +.. nonce: rea9-x +.. section: Library + +Fix refcycles in exceptions raised from :class:`asyncio.TaskGroup` and the +python implementation of :class:`asyncio.Future` + +.. + +.. date: 2024-10-03-20-45-57 +.. gh-issue: 53203 +.. nonce: 3Sk4Ia +.. section: Library + +Fix :func:`time.strptime` for ``%c`` and ``%x`` formats in many locales: +Arabic, Bislama, Breton, Bodo, Kashubian, Chuvash, Estonian, French, Irish, +Ge'ez, Gurajati, Manx Gaelic, Hebrew, Hindi, Chhattisgarhi, Haitian Kreyol, +Japanese, Kannada, Korean, Marathi, Malay, Norwegian, Nynorsk, Punjabi, +Rajasthani, Tok Pisin, Yoruba, Yue Chinese, Yau/Nungon and Chinese. + +.. + +.. date: 2024-10-03-19-16-38 +.. gh-issue: 123961 +.. nonce: ik1Dgs +.. section: Library + +Convert :mod:`curses` to multi-phase initialization (:pep:`489`), thereby +fixing reference leaks at interpreter shutdown. Patch by Bénédikt Tran. + +.. + +.. date: 2024-10-03-17-13-22 +.. gh-issue: 124944 +.. nonce: YyLAzf +.. section: Library + +Add ``SO_ORIGINAL_DST`` to the :mod:`socket` module. + +.. + +.. date: 2024-10-03-05-00-25 +.. gh-issue: 117151 +.. nonce: Prdw_W +.. section: Library + +The default buffer size used by :func:`shutil.copyfileobj` has been +increased from 64k to 256k on non-Windows platforms. It was already larger +on Windows. + +.. + +.. date: 2024-10-02-22-53-48 +.. gh-issue: 90102 +.. nonce: 4qX52R +.. section: Library + +Skip the ``isatty`` system call during open() when the file is known to not +be a character device. This provides a slight performance improvement when +reading whole files. + +.. + +.. date: 2024-10-02-21-11-18 +.. gh-issue: 124917 +.. nonce: Lnwh5b +.. section: Library + +Allow calling :func:`os.path.exists` and :func:`os.path.lexists` with +keyword arguments on Windows. Fixes a regression in 3.13.0. + +.. + +.. date: 2024-10-02-16-35-07 +.. gh-issue: 65865 +.. nonce: S2D4wq +.. section: Library + +:mod:`argparse` now raises early error for invalid ``help`` arguments to +:meth:`~argparse.ArgumentParser.add_argument`, +:meth:`~argparse.ArgumentParser.add_subparsers` and :meth:`!add_parser`. + +.. + +.. date: 2024-10-02-15-05-45 +.. gh-issue: 124653 +.. nonce: tqsTu9 +.. section: Library + +Fix detection of the minimal Queue API needed by the :mod:`logging` module. +Patch by Bénédikt Tran. + +.. + +.. date: 2024-10-01-23-29-09 +.. gh-issue: 91818 +.. nonce: Kz8cPI +.. section: Library + +The CLI of many modules (:mod:`ast`, :mod:`ensurepip`, :mod:`json`, +:mod:`pdb`, :mod:`sqlite3`, :mod:`tokenize`, :mod:`venv`) now uses the +actual executable name instead of simply "python" to display in the usage +message. + +.. + +.. date: 2024-10-01-17-12-20 +.. gh-issue: 124858 +.. nonce: Zy0tvT +.. section: Library + +Fix reference cycles left in tracebacks in :func:`asyncio.open_connection` +when used with ``happy_eyeballs_delay`` + +.. + +.. date: 2024-10-01-13-46-58 +.. gh-issue: 124390 +.. nonce: dK1Zcm +.. section: Library + +Fixed :exc:`AssertionError` when using +:func:`!asyncio.staggered.staggered_race` with +:attr:`asyncio.eager_task_factory`. + +.. + +.. date: 2024-10-01-13-11-53 +.. gh-issue: 85935 +.. nonce: CTwJUy +.. section: Library + +:meth:`argparse.ArgumentParser.add_argument` now raises an exception if an +:ref:`action` that does not consume arguments (like 'store_const' or +'store_true') or explicit ``nargs=0`` are specified for positional +arguments. + +.. + +.. date: 2024-10-01-12-43-42 +.. gh-issue: 124835 +.. nonce: SVyp3K +.. section: Library + +Make :func:`tomllib.loads` raise :exc:`TypeError` not :exc:`AttributeError` +on bad input types that do not have the ``replace`` attribute. Improve error +message when :class:`bytes` is received. + +.. + +.. date: 2024-10-01-02-31-13 +.. gh-issue: 124693 +.. nonce: qzbXKB +.. section: Library + +Fix a bug where :mod:`argparse` doesn't recognize negative complex numbers +or negative numbers using scientific notation. + +.. + +.. date: 2024-09-30-20-46-32 +.. gh-issue: 124787 +.. nonce: 3FnJnP +.. section: Library + +Fix :class:`typing.TypeAliasType` with incorrect ``type_params`` argument. +Now it raises a :exc:`TypeError` when a type parameter without a default +follows one with a default, and when an entry in the ``type_params`` tuple +is not a type parameter object. + +.. + +.. date: 2024-09-30-19-59-28 +.. gh-issue: 66436 +.. nonce: 4gYN_n +.. section: Library + +Improved :ref:`prog` default value for :class:`argparse.ArgumentParser`. It +will now include the name of the Python executable along with the module or +package name, or the path to a directory, ZIP file, or directory within a +ZIP file if the code was run that way. + +.. + +.. date: 2024-09-27-15-16-04 +.. gh-issue: 116850 +.. nonce: dBkR0- +.. section: Library + +Fix :mod:`argparse` for namespaces with not directly writable dict (e.g. +classes). + +.. + +.. date: 2024-09-27-06-39-32 +.. gh-issue: 101552 +.. nonce: xYkzag +.. section: Library + +Add an *annoation_format* parameter to :func:`inspect.signature`. Add an +*quote_annotation_strings* parameter to :meth:`inspect.Signature.format`. +Use the new functionality to improve the display of annotations in +signatures in :mod:`pydoc`. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-09-26-22-14-12 +.. gh-issue: 58573 +.. nonce: hozbm9 +.. section: Library + +Fix conflicts between abbreviated long options in the parent parser and +subparsers in :mod:`argparse`. + +.. + +.. date: 2024-09-26-13-43-39 +.. gh-issue: 124594 +.. nonce: peYhsP +.. section: Library + +All :mod:`asyncio` REPL prompts run in the same :class:`context +`. Contributed by Bartosz Sławecki. + +.. + +.. date: 2024-09-26-09-18-09 +.. gh-issue: 61181 +.. nonce: dwjmch +.. section: Library + +Fix support of :ref:`choices` with string value in :mod:`argparse`. +Substrings of the specified string no longer considered valid values. + +.. + +.. date: 2024-09-26-00-35-24 +.. gh-issue: 116750 +.. nonce: X1aMHI +.. section: Library + +Provide :func:`sys.monitoring.clear_tool_id` to unregister all events and +callbacks set by the tool. + +.. + +.. date: 2024-09-25-22-06-52 +.. gh-issue: 124552 +.. nonce: 1nQKNM +.. section: Library + +Improve the accuracy of :mod:`bdb`'s check for the possibility of breakpoint +in a frame. This makes it possible to disable unnecessary events in +functions. + +.. + +.. date: 2024-09-25-18-34-48 +.. gh-issue: 124538 +.. nonce: nXZk4R +.. section: Library + +Fixed crash when using :func:`gc.get_referents` on a capsule object. + +.. + +.. date: 2024-09-25-18-08-29 +.. gh-issue: 80259 +.. nonce: kO5Tw7 +.. section: Library + +Fix :mod:`argparse` support of positional arguments with ``nargs='?'``, +``default=argparse.SUPPRESS`` and specified ``type``. + +.. + +.. date: 2024-09-25-18-07-51 +.. gh-issue: 120378 +.. nonce: NlBSz_ +.. section: Library + +Fix a crash related to an integer overflow in :func:`curses.resizeterm` and +:func:`curses.resize_term`. + +.. + +.. date: 2024-09-25-12-14-58 +.. gh-issue: 124498 +.. nonce: Ozxs55 +.. section: Library + +Fix :class:`typing.TypeAliasType` not to be generic, when ``type_params`` is +an empty tuple. + +.. + +.. date: 2024-09-25-10-25-57 +.. gh-issue: 53834 +.. nonce: uyIckw +.. section: Library + +Fix support of arguments with :ref:`choices` in :mod:`argparse`. Positional +arguments with :ref:`nargs` equal to ``'?'`` or ``'*'`` no longer check +:ref:`default` against ``choices``. Optional arguments with ``nargs`` equal +to ``'?'`` no longer check :ref:`const` against ``choices``. + +.. + +.. date: 2024-09-24-22-38-51 +.. gh-issue: 123884 +.. nonce: iEPTK4 +.. section: Library + +Fixed bug in itertools.tee() handling of other tee inputs (a tee in a tee). +The output now has the promised *n* independent new iterators. Formerly, +the first iterator was identical (not independent) to the input iterator. +This would sometimes give surprising results. + +.. + +.. date: 2024-09-24-21-15-27 +.. gh-issue: 123017 +.. nonce: dSAr2f +.. section: Library + +Due to unreliable results on some devices, :func:`time.strftime` no longer +accepts negative years on Android. + +.. + +.. date: 2024-09-24-19-32-14 +.. gh-issue: 123014 +.. nonce: zVcfkZ +.. section: Library + +:func:`os.pidfd_open` and :func:`signal.pidfd_send_signal` are now +unavailable when building against Android API levels older than 31, since +the underlying system calls may cause a crash. + +.. + +.. date: 2024-09-24-13-32-16 +.. gh-issue: 124176 +.. nonce: 6hmOPz +.. section: Library + +Add support for :func:`dataclasses.dataclass` in +:func:`unittest.mock.create_autospec`. Now ``create_autospec`` will check +for potential dataclasses and use :func:`dataclasses.fields` function to +retrieve the spec information. + +.. + +.. date: 2024-09-24-12-34-48 +.. gh-issue: 124345 +.. nonce: s3vKql +.. section: Library + +:mod:`argparse` vim supports abbreviated single-dash long options separated +by ``=`` from its value. + +.. + +.. date: 2024-09-24-00-01-24 +.. gh-issue: 124400 +.. nonce: 0XCgfe +.. section: Library + +Fixed a :mod:`pdb` bug where ``until`` has no effect when it appears in a +``commands`` sequence. Also avoid printing the frame information at a +breakpoint that has a command list containing a command that resumes +execution. + +.. + +.. date: 2024-09-23-18-26-17 +.. gh-issue: 90562 +.. nonce: Yj566G +.. section: Library + +Modify dataclasses to support zero-argument super() when ``slots=True`` is +specified. This works by modifying all references to ``__class__`` to point +to the newly created class. + +.. + +.. date: 2024-09-23-17-33-47 +.. gh-issue: 104860 +.. nonce: O86OSc +.. section: Library + +Fix disallowing abbreviation of single-dash long options in :mod:`argparse` +with ``allow_abbrev=False``. + +.. + +.. date: 2024-09-21-23-56-41 +.. gh-issue: 63143 +.. nonce: YKu-LQ +.. section: Library + +Fix parsing mutually exclusive arguments in :mod:`argparse`. Arguments with +the value identical to the default value (e.g. booleans, small integers, +empty or 1-character strings) are no longer considered "not present". + +.. + +.. date: 2024-09-21-22-32-21 +.. gh-issue: 72795 +.. nonce: naLmkX +.. section: Library + +Positional arguments with :ref:`nargs` equal to ``'*'`` or +:data:`!argparse.REMAINDER` are no longer required. This allows to use +positional argument with ``nargs='*'`` and without ``default`` in mutually +exclusive group and improves error message about required arguments. + +.. + +.. date: 2024-09-21-19-02-37 +.. gh-issue: 59317 +.. nonce: OAhNZZ +.. section: Library + +Fix parsing positional argument with :ref:`nargs` equal to ``'?'`` or +``'*'`` if it is preceded by an option and another positional argument. + +.. + +.. date: 2024-09-20-18-23-19 +.. gh-issue: 100980 +.. nonce: 8nVAB6 +.. section: Library + +The :attr:`~ctypes.Structure._fields_` attribute of +:class:`ctypes.Structure` and :class:`~ctypes.Union` is no longer set if the +setattr operation raises an error. + +.. + +.. date: 2024-09-20-12-23-11 +.. gh-issue: 53780 +.. nonce: mrV1zi +.. section: Library + +:mod:`argparse` now ignores the first ``"--"`` (double dash) between an +option and command. + +.. + +.. date: 2024-09-19-20-15-00 +.. gh-issue: 124217 +.. nonce: j0KlQB +.. section: Library + +Add RFC 9637 reserved IPv6 block ``3fff::/20`` in :mod:`ipaddress` module. + +.. + +.. date: 2024-09-19-16-00-22 +.. gh-issue: 111513 +.. nonce: 6jHm02 +.. section: Library + +Improve the error message that may be raised by +:meth:`datetime.date.fromtimestamp`. + +.. + +.. date: 2024-09-19-11-47-39 +.. gh-issue: 124248 +.. nonce: g7rufd +.. section: Library + +Fixed potential crash when using :mod:`struct` to process zero-width 'Pascal +string' fields (``0p``). + +.. + +.. date: 2024-09-19-10-36-18 +.. gh-issue: 81691 +.. nonce: Hyhp_U +.. section: Library + +Fix handling of multiple ``"--"`` (double dashes) in :mod:`argparse`. Only +the first one has now been removed, all subsequent ones are now taken +literally. + +.. + +.. date: 2024-09-19-03-46-59 +.. gh-issue: 87041 +.. nonce: 9Ox7Bv +.. section: Library + +Fix a bug in :mod:`argparse` where lengthy subparser argument help is +incorrectly indented. + +.. + +.. date: 2024-09-19-00-09-48 +.. gh-issue: 84559 +.. nonce: IrxvQe +.. section: Library + +The default :mod:`multiprocessing` start method on Linux and other POSIX +systems has been changed away from often unsafe ``"fork"`` to +``"forkserver"`` (when the platform supports sending file handles over pipes +as most do) or ``"spawn"``. Mac and Windows are unchanged as they already +default to ``"spawn"``. + +.. + +.. date: 2024-09-18-17-45-52 +.. gh-issue: 124212 +.. nonce: n6kIby +.. section: Library + +Fix invalid variable in :mod:`venv` handling of failed symlink on Windows + +.. + +.. date: 2024-09-17-18-06-42 +.. gh-issue: 124171 +.. nonce: PHCvRJ +.. section: Library + +Add workaround for broken :c:func:`!fmod()` implementations on Windows, that +loose zero sign (e.g. ``fmod(-10, 1)`` returns ``0.0``). Patch by Sergey B +Kirpichev. + +.. + +.. date: 2024-09-16-12-31-48 +.. gh-issue: 123978 +.. nonce: z3smEu +.. section: Library + +Remove broken :func:`time.thread_time` and :func:`time.thread_time_ns` on +NetBSD. + +.. + +.. date: 2024-09-13-10-34-19 +.. gh-issue: 123934 +.. nonce: yMe7mL +.. section: Library + +Fix :class:`unittest.mock.MagicMock` resetting magic methods return values +after ``.reset_mock(return_value=True)`` was called. + +.. + +.. date: 2024-09-12-10-55-19 +.. gh-issue: 124016 +.. nonce: ncs0hd +.. section: Library + +Update :mod:`unicodedata` database to Unicode 16.0.0. + +.. + +.. date: 2024-09-11-19-12-23 +.. gh-issue: 123968 +.. nonce: OwHON_ +.. section: Library + +Fix the command-line interface for the :mod:`random` module to select floats +between 0 and N, not 1 and N. + +.. + +.. date: 2024-09-11-19-05-32 +.. gh-issue: 123945 +.. nonce: jLwybB +.. section: Library + +Fix a bug where :mod:`argparse` doesn't recognize negative numbers with +underscores + +.. + +.. date: 2024-09-11-13-33-19 +.. gh-issue: 123935 +.. nonce: fRZ_56 +.. section: Library + +Fix parent slots detection for dataclasses that inherit from classes with +``__dictoffset__``. + +.. + +.. date: 2024-09-10-11-26-14 +.. gh-issue: 123892 +.. nonce: 2gzIrz +.. section: Library + +Add ``"_wmi"`` to :data:`sys.stdlib_module_names`. Patch by Victor Stinner. + +.. + +.. date: 2024-09-06-10-17-54 +.. gh-issue: 84808 +.. nonce: ION67Z +.. section: Library + +Fix error handling in :py:class:`~socket.socket` method +:py:func:`~socket.socket.connect_ex` on platforms where :c:data:`errno` can +be negative. + +.. + +.. date: 2024-09-06-01-35-11 +.. gh-issue: 123756 +.. nonce: Ozbhke +.. section: Library + +Added a new argument ``mode`` to :class:`pdb.Pdb`. Only allow :mod:`pdb` +from command line to use ``restart`` command. + +.. + +.. date: 2024-09-06-00-00-43 +.. gh-issue: 122765 +.. nonce: tx4hsr +.. section: Library + +Fix unbalanced quote errors occurring when activate.csh in :mod:`venv` was +sourced with a custom prompt containing unpaired quotes or newlines. + +.. + +.. date: 2024-09-04-18-23-43 +.. gh-issue: 123657 +.. nonce: Oks4So +.. section: Library + +Fix crash and memory leak in :func:`decimal.getcontext`. It crashed when +using a thread-local context by ``--with-decimal-contextvar=no``. + +.. + +.. date: 2024-09-02-20-34-04 +.. gh-issue: 123339 +.. nonce: czgcSu +.. section: Library + +Fix :func:`inspect.getsource` for classes in :mod:`collections.abc` and +:mod:`decimal` (for pure Python implementation) modules. +:func:`inspect.getcomments` now raises OSError instead of IndexError if the +``__firstlineno__`` value for a class is out of bound. + +.. + +.. date: 2024-08-31-12-34-44 +.. gh-issue: 123374 +.. nonce: 3kE7rb +.. section: Library + +Remove check for redefined memo entry in :func:`pickletools.dis`. + +.. + +.. date: 2024-08-30-09-01-35 +.. gh-issue: 123504 +.. nonce: lJ9_BB +.. section: Library + +Fixed reference leak in the finalization of :mod:`tkinter`. + +.. + +.. date: 2024-08-29-14-51-36 +.. gh-issue: 123430 +.. nonce: M7wXl9 +.. section: Library + +Pages generated by the :mod:`http.server` module allow the browser to apply +its default dark mode. + +.. + +.. date: 2024-08-29-09-27-12 +.. gh-issue: 123446 +.. nonce: _I_mMr +.. section: Library + +Fix empty function name in :exc:`TypeError` when :func:`csv.reader`, +:func:`csv.writer`, or :func:`csv.register_dialect` are used without the +required args. + +.. + +.. date: 2024-08-28-20-08-19 +.. gh-issue: 123448 +.. nonce: tItJlp +.. section: Library + +Fixed memory leak of :class:`typing.NoDefault` by moving it to the static +types array. + +.. + +.. date: 2024-08-28-13-03-36 +.. gh-issue: 123409 +.. nonce: lW0YF- +.. section: Library + +Fix :attr:`ipaddress.IPv6Address.reverse_pointer` output according to +:rfc:`RFC 3596, §2.5 <3596#section-2.5>`. Patch by Bénédikt Tran. + +.. + +.. date: 2024-08-27-12-38-42 +.. gh-issue: 123089 +.. nonce: vA7iFR +.. section: Library + +Make :class:`weakref.WeakSet` safe against concurrent mutations while it is +being iterated. Patch by Kumar Aditya. + +.. + +.. date: 2024-08-27-12-11-00 +.. gh-issue: 123363 +.. nonce: gKuJp6 +.. section: Library + +Show string value of :opcode:`CONTAINS_OP` oparg in :mod:`dis` output. Patch +by Alexandr153. + +.. + +.. date: 2024-08-27-10-30-37 +.. gh-issue: 123341 +.. nonce: 5e-fjt +.. section: Library + +Add :meth:`~object.__class_getitem__` to :class:`!tkinter.Event` for type +subscript support at runtime. Patch by Adonis Rakateli. + +.. + +.. date: 2024-08-26-19-36-00 +.. gh-issue: 123340 +.. nonce: mQKI1H +.. section: Library + +Show string value of :opcode:`IS_OP` oparg in :mod:`dis` output. + +.. + +.. date: 2024-08-26-18-48-13 +.. gh-issue: 119518 +.. nonce: QFYH9q +.. section: Library + +Speed up normalization of :class:`pathlib.PurePath` and +:class:`~pathlib.Path` objects by not interning string parts. + +.. + +.. date: 2024-08-26-13-45-20 +.. gh-issue: 123270 +.. nonce: gXHvNJ +.. section: Library + +Applied a more surgical fix for malformed payloads in :class:`zipfile.Path` +causing infinite loops (gh-122905) without breaking contents using +legitimate characters. + +.. + +.. date: 2024-08-25-16-59-20 +.. gh-issue: 73991 +.. nonce: 1w8u3K +.. section: Library + +Add :meth:`pathlib.Path.copy_into` and :meth:`~pathlib.Path.move_into`, +which copy and move files and directories into *existing* directories. + +.. + +.. date: 2024-08-24-06-05-41 +.. gh-issue: 123228 +.. nonce: jR_5O5 +.. section: Library + +Fix return type for +:func:`!_pyrepl.readline._ReadlineWrapper.get_line_buffer` to be +:func:`str`. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-08-24-00-03-01 +.. gh-issue: 123240 +.. nonce: uFPG3l +.. section: Library + +Raise audit events for the :func:`input` in the new REPL. + +.. + +.. date: 2024-08-23-22-01-30 +.. gh-issue: 76960 +.. nonce: vsANPu +.. section: Library + +Fix :func:`urllib.parse.urljoin` and :func:`urllib.parse.urldefrag` for URIs +containing empty components. For example, :func:`!urljoin` with relative +reference "?" now sets empty query and removes fragment. Preserve empty +components (authority, params, query, fragment) in :func:`!urljoin`. +Preserve empty components (authority, params, query) in :func:`!urldefrag`. + +.. + +.. date: 2024-08-23-15-49-10 +.. gh-issue: 116810 +.. nonce: QLBUU8 +.. section: Library + +Resolve a memory leak introduced in CPython 3.10's :mod:`ssl` when the +:attr:`ssl.SSLSocket.session` property was accessed. Speeds up read and +write access to said property by no longer unnecessarily cloning session +objects via serialization. + +.. + +.. date: 2024-08-22-20-10-13 +.. gh-issue: 123243 +.. nonce: Kifj1L +.. section: Library + +Fix memory leak in :mod:`!_decimal`. + +.. + +.. date: 2024-08-22-11-25-19 +.. gh-issue: 122546 +.. nonce: BSmeE7 +.. section: Library + +Consistently use same file name for different exceptions in the new repl. +Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-08-22-09-37-48 +.. gh-issue: 123213 +.. nonce: owmXnP +.. section: Library + +:meth:`xml.etree.ElementTree.Element.extend` and +:class:`~xml.etree.ElementTree.Element` assignment no longer hide the +internal exception if an erroneous generator is passed. Patch by Bar Harel. + +.. + +.. date: 2024-08-20-18-02-27 +.. gh-issue: 85110 +.. nonce: 8_iDQy +.. section: Library + +Preserve relative path in URL without netloc in +:func:`urllib.parse.urlunsplit` and :func:`urllib.parse.urlunparse`. + +.. + +.. date: 2024-08-20-14-22-49 +.. gh-issue: 123165 +.. nonce: vOZZOA +.. section: Library + +Add support for rendering :class:`~dis.Positions` in :mod:`dis`. + +.. + +.. date: 2024-08-19-17-37-18 +.. gh-issue: 122909 +.. nonce: kP12SK +.. section: Library + +In urllib.request when URLError is raised opening an ftp URL, the exception +argument is now consistently a string. Earlier versions passed either a +string or an ftplib exception instance as the argument to URLError. + +.. + +.. date: 2024-08-18-08-25-32 +.. gh-issue: 123084 +.. nonce: rf8izX +.. section: Library + +Deprecate :class:`!shutil.ExecError`, which hasn't been raised by any +:mod:`shutil` function since Python 3.4. It's now an alias for +:exc:`RuntimeError`. + +.. + +.. date: 2024-08-17-08-17-20 +.. gh-issue: 123085 +.. nonce: 7Io2yH +.. section: Library + +In a bare call to :func:`importlib.resources.files`, ensure the caller's +frame is properly detected when ``importlib.resources`` is itself available +as a compiled module only (no source). + +.. + +.. date: 2024-08-16-19-13-21 +.. gh-issue: 123067 +.. nonce: Nx9O4R +.. section: Library + +Fix quadratic complexity in parsing ``"``-quoted cookie values with +backslashes by :mod:`http.cookies`. + +.. + +.. date: 2024-08-16-16-53-52 +.. gh-issue: 123049 +.. nonce: izx_fH +.. section: Library + +Add support for :const:`~configparser.UNNAMED_SECTION` in +:meth:`configparser.ConfigParser.add_section`. + +.. + +.. date: 2024-08-15-09-45-34 +.. gh-issue: 121735 +.. nonce: _1q0qf +.. section: Library + +When working with zip archives, importlib.resources now properly honors +module-adjacent references (e.g. ``files(pkg.mod)`` and not just +``files(pkg)``). + +.. + +.. date: 2024-08-14-10-41-11 +.. gh-issue: 122981 +.. nonce: BHV0Z9 +.. section: Library + +Fix :func:`inspect.getsource` for generated classes with Python base classes +(e.g. enums). + +.. + +.. date: 2024-08-11-14-23-07 +.. gh-issue: 122903 +.. nonce: xktZta +.. section: Library + +``zipfile.Path.glob`` now correctly matches directories instead of silently +omitting them. + +.. + +.. date: 2024-08-11-14-08-04 +.. gh-issue: 122905 +.. nonce: 7tDsxA +.. section: Library + +:class:`zipfile.Path` objects now sanitize names from the zipfile. + +.. + +.. date: 2024-08-10-14-16-59 +.. gh-issue: 122873 +.. nonce: XlHaUn +.. section: Library + +Enable :mod:`json` module to work as a script using the :option:`-m` switch: +``python -m json``. See the :ref:`JSON command-line interface +` documentation. Patch by Trey Hunner. + +.. + +.. date: 2024-08-10-10-21-44 +.. gh-issue: 122858 +.. nonce: ZC1rJD +.. section: Library + +Deprecate :func:`!asyncio.iscoroutinefunction` in favor of +:func:`inspect.iscoroutinefunction`. + +.. + +.. date: 2024-08-07-17-41-16 +.. gh-issue: 116263 +.. nonce: EcXir0 +.. section: Library + +:class:`logging.handlers.RotatingFileHandler` no longer rolls over empty log +files. + +.. + +.. date: 2024-08-07-14-12-19 +.. gh-issue: 105376 +.. nonce: QbGPdE +.. section: Library + +Restore the deprecated :mod:`logging` ``warn()`` method. It was removed in +Python 3.13 alpha 1. Keep the deprecated ``warn()`` method in Python 3.13. +Patch by Victor Stinner. + +.. + +.. date: 2024-08-07-11-57-41 +.. gh-issue: 122311 +.. nonce: LDExnJ +.. section: Library + +Improve errors in the :mod:`pickle` module. :exc:`~pickle.PicklingError` is +now raised more often instead of :exc:`UnicodeEncodeError`, +:exc:`ValueError` and :exc:`AttributeError`, and the original exception is +chained to it. Improve and unify error messages in Python and C +implementations. + +.. + +.. date: 2024-08-06-18-07-19 +.. gh-issue: 122744 +.. nonce: kCzNDI +.. section: Library + +Bump the version of pip bundled in ensurepip to version 24.2. + +.. + +.. date: 2024-08-06-10-36-55 +.. gh-issue: 118761 +.. nonce: q_x_1A +.. section: Library + +Improve import time of :mod:`pprint` by around seven times. Patch by Hugo +van Kemenade. + +.. + +.. date: 2024-08-06-07-24-00 +.. gh-issue: 118974 +.. nonce: qamsCQ +.. section: Library + +Add ``decorator`` parameter to :func:`dataclasses.make_dataclass` to +customize the functional creation of dataclasses. + +.. + +.. date: 2024-08-04-14-07-18 +.. gh-issue: 118814 +.. nonce: uiyks1 +.. section: Library + +Fix the :class:`typing.TypeVar` constructor when name is passed by keyword. + +.. + +.. date: 2024-08-03-06-51-08 +.. gh-issue: 122637 +.. nonce: gpas8J +.. section: Library + +Adjust ``cmath.tanh(nanj)`` and ``cmath.tanh(infj)`` for recent C standards. + +.. + +.. date: 2024-07-31-20-43-21 +.. gh-issue: 122478 +.. nonce: sCU2Le +.. section: Library + +Remove internal frames from tracebacks shown in +:class:`code.InteractiveInterpreter` with non-default +:func:`sys.excepthook`. Save correct tracebacks in +:attr:`sys.last_traceback` and update ``__traceback__`` attribute of +:attr:`sys.last_value` and :attr:`sys.last_exc`. + +.. + +.. date: 2024-07-31-15-08-42 +.. gh-issue: 116622 +.. nonce: aKxIQA +.. section: Library + +On Android, the ``FICLONE`` and ``FICLONERANGE`` constants are no longer +exposed by :mod:`fcntl`, as these ioctls are blocked by SELinux. + +.. + +.. date: 2024-07-31-14-55-41 +.. gh-issue: 82378 +.. nonce: eZvYmR +.. section: Library + +Make sure that the new :term:`REPL` interprets :data:`sys.tracebacklimit` in +the same way that the classic REPL did. + +.. + +.. date: 2024-07-30-21-29-30 +.. gh-issue: 122334 +.. nonce: LeoE1x +.. section: Library + +Fix crash when importing :mod:`ssl` after the main interpreter restarts. + +.. + +.. date: 2024-07-30-15-57-07 +.. gh-issue: 122459 +.. nonce: AYIoeN +.. section: Library + +Optimize :mod:`pickling ` by name objects without the ``__module__`` +attribute. + +.. + +.. date: 2024-07-30-14-46-16 +.. gh-issue: 87320 +.. nonce: -Yk1wb +.. section: Library + +In :class:`code.InteractiveInterpreter`, handle exceptions caused by calling +a non-default :func:`sys.excepthook`. Before, the exception bubbled up to +the caller, ending the :term:`REPL`. + +.. + +.. date: 2024-07-30-04-27-55 +.. gh-issue: 122272 +.. nonce: 6Wwa1V +.. section: Library + +On some platforms such as Linux, year with century was not 0-padded when +formatted by :meth:`~.datetime.strftime` with C99-specific specifiers +``'%C'`` or ``'%F'``. The 0-padding behavior is now guaranteed when the +format specifiers ``'%C'`` and ``'%F'`` are supported by the C library. +Patch by Ben Hsing + +.. + +.. date: 2024-07-29-16-47-08 +.. gh-issue: 122400 +.. nonce: fM0YSv +.. section: Library + +Handle :exc:`ValueError`\s raised by :func:`os.stat` in +:class:`filecmp.dircmp` and :func:`filecmp.cmpfiles`. Patch by Bénédikt +Tran. + +.. + +.. date: 2024-07-29-10-24-48 +.. gh-issue: 122311 +.. nonce: xChV1b +.. section: Library + +Fix some error messages in :mod:`pickle`. + +.. + +.. date: 2024-07-27-16-10-41 +.. gh-issue: 121650 +.. nonce: nf6oc9 +.. section: Library + +:mod:`email` headers with embedded newlines are now quoted on output. The +:mod:`~email.generator` will now refuse to serialize (write) headers that +are unsafely folded or delimited; see +:attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas +Bloemsaat and Petr Viktorin in :gh:`121650`.) + +.. + +.. date: 2024-07-26-21-21-13 +.. gh-issue: 122332 +.. nonce: fvw88r +.. section: Library + +Fixed segfault with :meth:`asyncio.Task.get_coro` when using an eager task +factory. + +.. + +.. date: 2024-07-25-15-41-14 +.. gh-issue: 105733 +.. nonce: o3koJA +.. section: Library + +:func:`ctypes.ARRAY` is now :term:`soft deprecated`: it no longer emits +deprecation warnings and is not scheduled for removal. + +.. + +.. date: 2024-07-24-08-48-22 +.. gh-issue: 122213 +.. nonce: o3pdgA +.. section: Library + +Add notes for pickle serialization errors that allow to identify the source +of the error. + +.. + +.. date: 2024-07-23-22-26-00 +.. gh-issue: 119180 +.. nonce: B2IVT8 +.. section: Library + +As part of :pep:`749`, add the following attributes for customizing +evaluation of annotation scopes: + +* ``evaluate_value`` on :class:`typing.TypeAliasType` +* ``evaluate_bound``, ``evaluate_constraints``, and ``evaluate_default`` on :class:`typing.TypeVar` +* ``evaluate_default`` on :class:`typing.ParamSpec` +* ``evaluate_default`` on :class:`typing.TypeVarTuple` + +.. + +.. date: 2024-07-23-17-13-10 +.. gh-issue: 119180 +.. nonce: 5PZELo +.. section: Library + +Fix handling of classes with custom metaclasses in +``annotationlib.get_annotations``. + +.. + +.. date: 2024-07-23-15-30-23 +.. gh-issue: 122170 +.. nonce: Z9gi3Y +.. section: Library + +Handle :exc:`ValueError`\s raised by :func:`os.stat` in :mod:`linecache`. +Patch by Bénédikt Tran. + +.. + +.. date: 2024-07-23-15-11-13 +.. gh-issue: 122163 +.. nonce: 4wRUuM +.. section: Library + +Add notes for JSON serialization errors that allow to identify the source of +the error. + +.. + +.. date: 2024-07-23-13-07-12 +.. gh-issue: 122129 +.. nonce: PwbC8q +.. section: Library + +Improve support of method descriptors and wrappers in the help title. + +.. + +.. date: 2024-07-23-12-38-14 +.. gh-issue: 122145 +.. nonce: sTO8nX +.. section: Library + +Fix an issue when reporting tracebacks corresponding to Python code emitting +an empty AST body. Patch by Nikita Sobolev and Bénédikt Tran. + +.. + +.. date: 2024-07-23-10-59-38 +.. gh-issue: 121723 +.. nonce: iJEf7e +.. section: Library + +Make :func:`logging.config.dictConfig` accept any object implementing the +Queue public API. See the :ref:`queue configuration ` +section for details. Patch by Bénédikt Tran. + +.. + +.. date: 2024-07-23-09-14-44 +.. gh-issue: 82951 +.. nonce: -F5p5A +.. section: Library + +Serializing objects with complex ``__qualname__`` (such as unbound methods +and nested classes) by name no longer involves serializing parent objects by +value in pickle protocols < 4. + +.. + +.. date: 2024-07-22-08-57-28 +.. gh-issue: 120754 +.. nonce: Eo5puP +.. section: Library + +``Pathlib.read_bytes`` no longer opens the file in Python's buffered I/O +mode. This reduces overheads as the code reads a file in whole leading to a +modest speedup. + +.. + +.. date: 2024-07-22-08-14-04 +.. gh-issue: 113785 +.. nonce: 6B_KNB +.. section: Library + +:mod:`csv` now correctly parses numeric fields (when used with +:const:`csv.QUOTE_NONNUMERIC` or :const:`csv.QUOTE_STRINGS`) which start +with an escape character. + +.. + +.. date: 2024-07-21-18-03-30 +.. gh-issue: 122088 +.. nonce: vi2bP- +.. section: Library + +:func:`@warnings.deprecated ` now copies the coroutine +status of functions and methods so that :func:`inspect.iscoroutinefunction` +returns the correct result. + +.. + +.. date: 2024-07-21-10-45-24 +.. gh-issue: 122081 +.. nonce: dNrYMq +.. section: Library + +Fix a crash in the :func:`!decimal.IEEEContext` optional function available +via the ``EXTRA_FUNCTIONALITY`` configuration flag. + +.. + +.. date: 2024-07-21-02-00-46 +.. gh-issue: 73991 +.. nonce: pLxdtJ +.. section: Library + +Add :meth:`pathlib.Path.move`, which moves a file or directory tree. + +.. + +.. date: 2024-07-17-12-55-22 +.. gh-issue: 121268 +.. nonce: 41RmjR +.. section: Library + +Remove workarounds for non-IEEE 754 systems in :mod:`cmath`. + +.. + +.. date: 2024-07-17-09-44-35 +.. gh-issue: 119698 +.. nonce: WlygzR +.. section: Library + +Due to the lack of interest for :meth:`symtable.Class.get_methods`, the +method is marked as deprecated and will be removed in Python 3.16. Patch by +Bénédikt Tran. + +.. + +.. date: 2024-07-17-09-23-03 +.. gh-issue: 121889 +.. nonce: 6se9jS +.. section: Library + +Adjusts ``cmath.acosh(complex('0+nanj'))`` for recent C standards. + +.. + +.. date: 2024-07-16-20-49-07 +.. gh-issue: 121804 +.. nonce: gYN-In +.. section: Library + +Correctly show error locations, when :exc:`SyntaxError` raised in new repl. +Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-07-15-19-34-56 +.. gh-issue: 121797 +.. nonce: qDqj59 +.. section: Library + +Add alternative :class:`~fractions.Fraction` constructor +:meth:`Fraction.from_number() `. + +.. + +.. date: 2024-07-15-19-25-25 +.. gh-issue: 121798 +.. nonce: GmuBDu +.. section: Library + +Add alternative :class:`~decimal.Decimal` constructor +:meth:`Decimal.from_number() `. + +.. + +.. date: 2024-07-14-11-18-28 +.. gh-issue: 120930 +.. nonce: Kuo4L0 +.. section: Library + +Fixed a bug introduced by gh-92081 that added an incorrect extra blank to +encoded words occurring in wrapped headers. + +.. + +.. date: 2024-07-14-06-24-02 +.. gh-issue: 57141 +.. nonce: C3jhDh +.. section: Library + +The *shallow* argument to :class:`filecmp.dircmp` (new in Python 3.13) is +now keyword-only. + +.. + +.. date: 2024-07-13-06-23-24 +.. gh-issue: 121245 +.. nonce: RfOgf4 +.. section: Library + +Simplify handling of the history file in ``site.register_readline()`` +helper. The ``CAN_USE_PYREPL`` variable now will be initialized, when +imported. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-07-10-08-13-34 +.. gh-issue: 121249 +.. nonce: W9Gd09 +.. section: Library + +Support the :c:expr:`float complex` and :c:expr:`double complex` C types in +the :mod:`struct` module if the compiler has C11 complex arithmetic. Patch +by Sergey B Kirpichev. + +.. + +.. date: 2024-07-09-12-23-32 +.. gh-issue: 121486 +.. nonce: Iultjh +.. section: Library + +:mod:`math` functions :func:`~math.isqrt`, :func:`~math.log`, +:func:`~math.log2` and :func:`~math.log10` now support integers larger than +``2**2**32`` on 32-bit platforms. + +.. + +.. date: 2024-07-08-03-45-34 +.. gh-issue: 121474 +.. nonce: NsvrUN +.. section: Library + +Fix missing sanity check for ``parties`` arg in :class:`threading.Barrier` +constructor. Patch by Clinton Christian (pygeek). + +.. + +.. date: 2024-07-06-23-39-38 +.. gh-issue: 121450 +.. nonce: vGqb3c +.. section: Library + +Hard-coded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace`) now +reuse the most recent ``Pdb`` instance that calls ``Pdb.set_trace()``, +instead of creating a new one each time. As a result, all the instance +specific data like ``display`` and ``commands`` are preserved across +Hard-coded breakpoints. + +.. + +.. date: 2024-07-06-16-08-39 +.. gh-issue: 119169 +.. nonce: o0YymL +.. section: Library + +Slightly speed up :func:`os.walk` by simplifying exception handling. + +.. + +.. date: 2024-07-06-12-37-10 +.. gh-issue: 121423 +.. nonce: vnxrl4 +.. section: Library + +Improve import time of :mod:`socket` by lazy importing modules and writing +:data:`!socket.errorTab` as a constant. + +.. + +.. date: 2024-07-04-17-36-03 +.. gh-issue: 59110 +.. nonce: IlI9Fz +.. section: Library + +:mod:`zipimport` supports now namespace packages when no directory entry +exists. + +.. + +.. date: 2024-07-03-14-23-04 +.. gh-issue: 119004 +.. nonce: L5MoUu +.. section: Library + +Fix a crash in :ref:`OrderedDict.__eq__ ` +when operands are mutated during the check. Patch by Bénédikt Tran. + +.. + +.. date: 2024-07-03-10-11-53 +.. gh-issue: 121313 +.. nonce: D7gARW +.. section: Library + +Limit the reading size in the :class:`multiprocessing.connection.Connection` +class to 64 KiB to prevent memory overallocation and unnecessary memory +management system calls. + +.. + +.. date: 2024-07-03-07-25-21 +.. gh-issue: 121332 +.. nonce: Iz6FEq +.. section: Library + +Fix constructor of :mod:`ast` nodes with custom ``_attributes``. Previously, +passing custom attributes would raise a :py:exc:`DeprecationWarning`. +Passing arguments to the constructor that are not in ``_fields`` or +``_attributes`` remains deprecated. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-07-02-11-34-06 +.. gh-issue: 121245 +.. nonce: sSkDAr +.. section: Library + +Fix a bug in the handling of the command history of the new :term:`REPL` +that caused the history file to be wiped at REPL exit. + +.. + +.. date: 2024-07-01-11-23-18 +.. gh-issue: 121210 +.. nonce: cD0zfn +.. section: Library + +Handle AST nodes with missing runtime fields or attributes in +:func:`ast.compare`. Patch by Bénédikt Tran. + +.. + +.. date: 2024-06-29-19-30-15 +.. gh-issue: 121163 +.. nonce: SJKDFq +.. section: Library + +Add support for ``all`` as an valid ``action`` for +:func:`warnings.simplefilter` and :func:`warnings.filterwarnings`. + +.. + +.. date: 2024-06-29-15-23-26 +.. gh-issue: 121151 +.. nonce: HeLEvq +.. section: Library + +Fix wrapping of long usage text of arguments inside a mutually exclusive +group in :mod:`argparse`. + +.. + +.. date: 2024-06-29-15-21-12 +.. gh-issue: 121141 +.. nonce: 4evD6q +.. section: Library + +Add support for :func:`copy.replace` to AST nodes. Patch by Bénédikt Tran. + +.. + +.. date: 2024-06-29-05-08-59 +.. gh-issue: 87744 +.. nonce: rpF6Jw +.. section: Library + +Fix waitpid race while calling +:meth:`~asyncio.subprocess.Process.send_signal` in asyncio. Patch by Kumar +Aditya. + +.. + +.. date: 2024-06-27-13-47-14 +.. gh-issue: 121027 +.. nonce: jh55EC +.. section: Library + +Add a future warning in :meth:`!functools.partial.__get__`. In future Python +versions :class:`functools.partial` will be a method descriptor. + +.. + +.. date: 2024-06-27-12-27-52 +.. gh-issue: 121027 +.. nonce: D4K1OX +.. section: Library + +Make the :class:`functools.partial` object a method descriptor. + +.. + +.. date: 2024-06-26-17-00-39 +.. gh-issue: 117784 +.. nonce: inCtAV +.. section: Library + +CPython now detects whether its linked TLS library supports TLSv1.3 +post-handshake authentication and disables that feature if support is +lacking. + +.. + +.. date: 2024-06-26-10-13-40 +.. gh-issue: 121025 +.. nonce: M-XXlV +.. section: Library + +Improve the :meth:`~object.__repr__` of :class:`functools.partialmethod`. +Patch by Bénédikt Tran. + +.. + +.. date: 2024-06-26-03-04-24 +.. gh-issue: 121018 +.. nonce: clVSc4 +.. section: Library + +Fixed issues where :meth:`!argparse.ArgumentParser.parse_args` did not honor +``exit_on_error=False``. Based on patch by Ben Hsing. + +.. + +.. date: 2024-06-23-17-50-40 +.. gh-issue: 119614 +.. nonce: vwPGLB +.. section: Library + +Fix truncation of strings with embedded null characters in some internal +operations in :mod:`tkinter`. + +.. + +.. date: 2024-06-23-11-21-27 +.. gh-issue: 120910 +.. nonce: t0QXdB +.. section: Library + +When reading installed files from an egg, use ``relative_to(walk_up=True)`` +to honor files installed outside of the installation root. + +.. + +.. date: 2024-06-23-07-23-08 +.. gh-issue: 61103 +.. nonce: ca_U_l +.. section: Library + +Support :c:expr:`float complex`, :c:expr:`double complex` and :c:expr:`long +double complex` C types in :mod:`ctypes` as +:class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and +:class:`~ctypes.c_longdouble_complex` if the compiler has C11 complex +arithmetic. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-06-22-22-52-24 +.. gh-issue: 120888 +.. nonce: sd8I3N +.. section: Library + +Upgrade pip wheel bundled with ensurepip (pip 24.1.1) + +.. + +.. date: 2024-06-22-22-23-56 +.. gh-issue: 101830 +.. nonce: 1BAoxH +.. section: Library + +Accessing the :mod:`tkinter` object's string representation no longer +converts the underlying Tcl object to a string on Windows. + +.. + +.. date: 2024-06-22-17-01-56 +.. gh-issue: 120678 +.. nonce: Ik8dCg +.. section: Library + +Fix regression in the new REPL that meant that globals from files passed +using the ``-i`` argument would not be included in the REPL's global +namespace. Patch by Alex Waygood. + +.. + +.. date: 2024-06-21-14-32-56 +.. gh-issue: 120811 +.. nonce: eBmVTV +.. section: Library + +Fix possible memory leak in :meth:`contextvars.Context.run`. + +.. + +.. date: 2024-06-21-12-00-16 +.. gh-issue: 120782 +.. nonce: LOE8tj +.. section: Library + +Fix wrong references of the :mod:`datetime` types after reloading the +module. + +.. + +.. date: 2024-06-21-06-37-46 +.. gh-issue: 120713 +.. nonce: WBbQx4 +.. section: Library + +:meth:`datetime.datetime.strftime` now 0-pads years with less than four +digits for the format specifiers ``%Y`` and ``%G`` on Linux. Patch by Ben +Hsing + +.. + +.. date: 2024-06-20-01-31-24 +.. gh-issue: 120769 +.. nonce: PfiMrc +.. section: Library + +Make empty line in :mod:`pdb` repeats the last command even when the command +is from ``cmdqueue``. + +.. + +.. date: 2024-06-19-23-08-25 +.. gh-issue: 120780 +.. nonce: 0Omopb +.. section: Library + +Show string value of LOAD_SPECIAL oparg in :mod:`dis` output. + +.. + +.. date: 2024-06-19-19-53-42 +.. gh-issue: 41431 +.. nonce: gnkUc5 +.. section: Library + +Add :meth:`datetime.time.strptime` and :meth:`datetime.date.strptime`. +Contributed by Wannes Boeykens. + +.. + +.. date: 2024-06-19-15-43-04 +.. gh-issue: 120743 +.. nonce: CMMl2P +.. section: Library + +:term:`Soft deprecate ` :func:`os.popen` and +:func:`os.spawn* ` functions. They should no longer be used to +write new code. The :mod:`subprocess` module is recommended instead. Patch +by Victor Stinner. + +.. + +.. date: 2024-06-19-15-06-58 +.. gh-issue: 120732 +.. nonce: OvYV9b +.. section: Library + +Fix ``name`` passing to :class:`unittest.mock.Mock` object when using +:func:`unittest.mock.create_autospec`. + +.. + +.. date: 2024-06-19-13-20-01 +.. gh-issue: 111259 +.. nonce: Wki5PV +.. section: Library + +:mod:`re` now handles patterns like ``"[\s\S]"`` or ``"\s|\S"`` which match +any character as effectively as a dot with the ``DOTALL`` modifier +(``"(?s:.)"``). + +.. + +.. date: 2024-06-18-19-18-10 +.. gh-issue: 120683 +.. nonce: xmRez7 +.. section: Library + +Fix an error in :class:`logging.LogRecord`, when the integer part of the +timestamp is rounded up, while the millisecond calculation truncates, +causing the log timestamp to be wrong by up to 999 ms (affected roughly 1 in +8 million timestamps). + +.. + +.. date: 2024-06-18-14-45-38 +.. gh-issue: 118710 +.. nonce: 5GZZPX +.. section: Library + +:class:`ipaddress.IPv4Address` and :class:`ipaddress.IPv6Address` attributes +``version`` and ``max_prefixlen`` are now available on the class. + +.. + +.. date: 2024-06-17-20-04-13 +.. gh-issue: 120633 +.. nonce: kZC5wt +.. section: Library + +Move scrollbar and remove tear-off menus in turtledemo. + +.. + +.. date: 2024-06-16-21-33-56 +.. gh-issue: 120606 +.. nonce: kugbwR +.. section: Library + +Allow users to use EOF to exit ``commands`` definition in :mod:`pdb` + +.. + +.. date: 2024-06-15-23-38-36 +.. gh-issue: 120284 +.. nonce: HwsAtY +.. section: Library + +Allow :meth:`asyncio.Runner.run` to accept :term:`awaitable` objects instead +of simply :term:`coroutine`\s. + +.. + +.. date: 2024-06-15-12-04-46 +.. gh-issue: 120541 +.. nonce: d3cc5y +.. section: Library + +Improve the prompt in the "less" pager when :func:`help` is called with +non-string argument. + +.. + +.. date: 2024-06-14-20-05-25 +.. gh-issue: 120495 +.. nonce: OxgZKB +.. section: Library + +Fix incorrect exception handling in Tab Nanny. Patch by Wulian233. + +.. + +.. date: 2024-06-12-15-07-58 +.. gh-issue: 120388 +.. nonce: VuTQMT +.. section: Library + +Improve a warning message when a test method in :mod:`unittest` returns +something other than ``None``. Now we show the returned object type and +optional asyncio-related tip. + +.. + +.. date: 2024-06-12-11-54-05 +.. gh-issue: 120381 +.. nonce: O-BNLs +.. section: Library + +Correct :func:`inspect.ismethoddescriptor` to check also for the lack of +:meth:`~object.__delete__`. Patch by Jan Kaliszewski. + +.. + +.. date: 2024-06-12-10-00-31 +.. gh-issue: 90425 +.. nonce: 5CfkKG +.. section: Library + +The OS byte in gzip headers is now always set to 255 when using +:func:`gzip.compress`. + +.. + +.. date: 2024-06-11-16-34-41 +.. gh-issue: 120343 +.. nonce: hdiXeU +.. section: Library + +Fix column offset reporting for tokens that come after multiline f-strings +in the :mod:`tokenize` module. + +.. + +.. date: 2024-06-11-07-17-25 +.. gh-issue: 119180 +.. nonce: iH-2zy +.. section: Library + +As part of implementing :pep:`649` and :pep:`749`, add a new module +``annotationlib``. Add support for unresolved forward references in +annotations to :mod:`dataclasses`, :class:`typing.TypedDict`, and +:class:`typing.NamedTuple`. + +.. + +.. date: 2024-06-10-14-00-40 +.. gh-issue: 119600 +.. nonce: jJMf4C +.. section: Library + +Fix :func:`unittest.mock.patch` to not read attributes of the target when +``new_callable`` is set. Patch by Robert Collins. + +.. + +.. date: 2024-06-09-19-53-11 +.. gh-issue: 120289 +.. nonce: s4HXR0 +.. section: Library + +Fixed the use-after-free issue in :mod:`cProfile` by disallowing +``disable()`` and ``clear()`` in external timers. + +.. + +.. date: 2024-06-08-17-41-11 +.. gh-issue: 82017 +.. nonce: WpSTGi +.. section: Library + +Added support for converting any objects that have the +:meth:`!as_integer_ratio` method to a :class:`~fractions.Fraction`. + +.. + +.. date: 2024-06-08-15-46-35 +.. gh-issue: 114053 +.. nonce: Ub2XgJ +.. section: Library + +Fix edge-case bug where :func:`typing.get_type_hints` would produce +incorrect results if type parameters in a class scope were overridden by +assignments in a class scope and ``from __future__ import annotations`` +semantics were enabled. Patch by Alex Waygood. + +.. + +.. date: 2024-06-08-15-15-29 +.. gh-issue: 114053 +.. nonce: WQLAFG +.. section: Library + +Fix erroneous :exc:`NameError` when calling :func:`inspect.get_annotations` +with ``eval_str=True``` on a class that made use of :pep:`695` type +parameters in a module that had ``from __future__ import annotations`` at +the top of the file. Patch by Alex Waygood. + +.. + +.. date: 2024-06-08-14-36-40 +.. gh-issue: 120268 +.. nonce: MNpd1q +.. section: Library + +Prohibit passing ``None`` to pure-Python :meth:`datetime.date.fromtimestamp` +to achieve consistency with C-extension implementation. + +.. + +.. date: 2024-06-08-09-45-31 +.. gh-issue: 120244 +.. nonce: 8o9Dzr +.. section: Library + +Fix memory leak in :func:`re.sub` when the replacement string contains +backreferences. + +.. + +.. date: 2024-06-08-03-29-01 +.. gh-issue: 120254 +.. nonce: h682ke +.. section: Library + +Added ``commands`` argument to :func:`pdb.set_trace` which allows users to +send debugger commands from the source file. + +.. + +.. date: 2024-06-07-13-21-11 +.. gh-issue: 120211 +.. nonce: Rws_gf +.. section: Library + +Fix :mod:`tkinter.ttk` with Tcl/Tk 9.0. + +.. + +.. date: 2024-06-07-11-23-31 +.. gh-issue: 71587 +.. nonce: IjFajE +.. section: Library + +Fix crash in C version of :meth:`datetime.datetime.strptime` when called +again on the restarted interpreter. + +.. + +.. date: 2024-06-07-10-10-32 +.. gh-issue: 117983 +.. nonce: NeMR9n +.. section: Library + +Defer the ``threading`` import in ``importlib.util`` until lazy loading is +used. + +.. + +.. date: 2024-06-07-02-00-31 +.. gh-issue: 120157 +.. nonce: HnWcF9 +.. section: Library + +Remove unused constant ``concurrent.futures._base._FUTURE_STATES`` in +:mod:`concurrent.futures`. Patch by Clinton Christian (pygeek). + +.. + +.. date: 2024-06-06-17-24-43 +.. gh-issue: 120161 +.. nonce: DahNXV +.. section: Library + +:mod:`datetime` no longer crashes in certain complex reference cycle +situations. + +.. + +.. date: 2024-06-06-12-07-57 +.. gh-issue: 119698 +.. nonce: rRrprk +.. section: Library + +Fix :meth:`symtable.Class.get_methods` and document its behaviour. Patch by +Bénédikt Tran. + +.. + +.. date: 2024-06-05-16-30-28 +.. gh-issue: 120121 +.. nonce: 9dz8i7 +.. section: Library + +Add :exc:`concurrent.futures.InvalidStateError` to module's ``__all__``. + +.. + +.. date: 2024-06-05-11-39-21 +.. gh-issue: 119933 +.. nonce: ooJXQV +.. section: Library + +Add the :class:`symtable.SymbolTableType` enumeration to represent the +possible outputs of the :class:`symtable.SymbolTable.get_type` method. Patch +by Bénédikt Tran. + +.. + +.. date: 2024-06-05-11-03-10 +.. gh-issue: 120029 +.. nonce: QBsw47 +.. section: Library + +Expose :class:`symtable.Symbol` methods +:meth:`~symtable.Symbol.is_free_class`, +:meth:`~symtable.Symbol.is_comp_iter` and +:meth:`~symtable.Symbol.is_comp_cell`. Patch by Bénédikt Tran. + +.. + +.. date: 2024-06-05-08-02-46 +.. gh-issue: 120108 +.. nonce: 4U9BL8 +.. section: Library + +Fix calling :func:`copy.deepcopy` on :mod:`ast` trees that have been +modified to have references to parent nodes. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-06-04-19-49-16 +.. gh-issue: 120056 +.. nonce: 5aqozw +.. section: Library + +Add :data:`!socket.IP_RECVERR` and :data:`!socket.IP_RECVTTL` constants +(both available since Linux 2.2). And :data:`!socket.IP_RECVORIGDSTADDR` +constant (available since Linux 2.6.29). + +.. + +.. date: 2024-06-04-19-03-25 +.. gh-issue: 112672 +.. nonce: K2XfZH +.. section: Library + +Support building :mod:`tkinter` with Tcl 9.0. + +.. + +.. date: 2024-06-04-18-53-10 +.. gh-issue: 120057 +.. nonce: RSD9_Z +.. section: Library + +Added the :data:`os.environ.refresh() ` method to update +:data:`os.environ` with changes to the environment made by +:func:`os.putenv`, by :func:`os.unsetenv`, or made outside Python in the +same process. Patch by Victor Stinner. + +.. + +.. date: 2024-06-04-14-54-46 +.. gh-issue: 120029 +.. nonce: _1YdTf +.. section: Library + +Expose :meth:`symtable.Symbol.is_type_parameter` in the :mod:`symtable` +module. Patch by Bénédikt Tran. + +.. + +.. date: 2024-06-04-12-23-01 +.. gh-issue: 119819 +.. nonce: WKKrYh +.. section: Library + +Fix regression to allow logging configuration with multiprocessing queue +types. + +.. + +.. date: 2024-06-04-08-57-02 +.. gh-issue: 65454 +.. nonce: o9j4wF +.. section: Library + +:func:`unittest.mock.Mock.attach_mock` no longer triggers a call to a +``PropertyMock`` being attached. + +.. + +.. date: 2024-06-03-11-18-16 +.. gh-issue: 117142 +.. nonce: kWTXQo +.. section: Library + +The :mod:`ctypes` module may now be imported in all subinterpreters, +including those that have their own GIL. + +.. + +.. date: 2024-06-02-15-09-17 +.. gh-issue: 118835 +.. nonce: KUAuz6 +.. section: Library + +Fix _pyrepl crash when using custom prompt with ANSI escape codes. + +.. + +.. date: 2024-06-02-13-35-11 +.. gh-issue: 81936 +.. nonce: ETeW9x +.. section: Library + +:meth:`!help` and :meth:`!showtopic` methods now respect a configured +*output* argument to :class:`!pydoc.Helper` and not use the pager in such +cases. Patch by Enrico Tröger. + +.. + +.. date: 2024-06-01-16-58-43 +.. gh-issue: 117398 +.. nonce: kR0RW7 +.. section: Library + +The ``_datetime`` module (C implementation for :mod:`datetime`) now supports +being imported in multiple interpreters. + +.. + +.. date: 2024-05-31-21-17-43 +.. gh-issue: 119824 +.. nonce: CQlxWV +.. section: Library + +Print stack entry in :mod:`pdb` when and only when user input is needed. + +.. + +.. date: 2024-05-31-13-56-21 +.. gh-issue: 119838 +.. nonce: H6XHlE +.. section: Library + +In mixed arithmetic operations with :class:`~fractions.Fraction` and +complex, the fraction is now converted to :class:`float` instead of +:class:`complex`. + +.. + +.. date: 2024-05-31-12-57-31 +.. gh-issue: 119770 +.. nonce: NCtels +.. section: Library + +Make :mod:`termios` ``ioctl()`` constants positive. Patch by Victor Stinner. + +.. + +.. date: 2024-05-30-21-37-05 +.. gh-issue: 89727 +.. nonce: D6S9ig +.. section: Library + +Fix issue with :func:`shutil.rmtree` where a :exc:`RecursionError` is raised +on deep directory trees. + +.. + +.. date: 2024-05-29-21-50-05 +.. gh-issue: 119577 +.. nonce: S3BlKJ +.. section: Library + +The :exc:`DeprecationWarning` emitted when testing the truth value of an +:class:`xml.etree.ElementTree.Element` now describes unconditionally +returning ``True`` in a future version rather than raising an exception in +Python 3.14. + +.. + +.. date: 2024-05-29-20-42-17 +.. gh-issue: 89727 +.. nonce: 5lPTTW +.. section: Library + +Partially fix issue with :func:`shutil.rmtree` where a :exc:`RecursionError` +is raised on deep directory trees. A recursion error is no longer raised +when :data:`!rmtree.avoids_symlink_attacks` is false. + +.. + +.. date: 2024-05-29-12-42-40 +.. gh-issue: 93963 +.. nonce: cb1oJS +.. section: Library + +Remove deprecated names from ``importlib.abc`` as found in +``importlib.resources.abc``. + +.. + +.. date: 2024-05-28-12-15-03 +.. gh-issue: 119118 +.. nonce: FMKz1F +.. section: Library + +Fix performance regression in the :mod:`tokenize` module by caching the +``line`` token attribute and calculating the column offset more efficiently. + +.. + +.. date: 2024-05-28-00-56-59 +.. gh-issue: 89727 +.. nonce: _bxoL3 +.. section: Library + +Fix issue with :func:`os.fwalk` where a :exc:`RecursionError` was raised on +deep directory trees by adjusting the implementation to be iterative instead +of recursive. + +.. + +.. date: 2024-05-26-22-22-51 +.. gh-issue: 119594 +.. nonce: fnQNM8 +.. section: Library + +If one calls pow(fractions.Fraction, x, module) with modulo not None, the +error message now says that the types are incompatible rather than saying +pow only takes 2 arguments. Patch by Wim Jeantine-Glenn and Mark Dickinson. + +.. + +.. date: 2024-05-26-21-28-11 +.. gh-issue: 119588 +.. nonce: wlLBK5 +.. section: Library + +``zipfile.Path.is_symlink`` now assesses if the given path is a symlink. + +.. + +.. date: 2024-05-25-20-20-42 +.. gh-issue: 119562 +.. nonce: DyplWc +.. section: Library + +Remove :class:`!ast.Num`, :class:`!ast.Str`, :class:`!ast.Bytes`, +:class:`!ast.NameConstant` and :class:`!ast.Ellipsis`. They had all emitted +deprecation warnings since Python 3.12. Patch by Alex Waygood. + +.. + +.. date: 2024-05-25-20-15-26 +.. gh-issue: 119555 +.. nonce: mvHbEL +.. section: Library + +Catch :exc:`SyntaxError` from :func:`compile` in the runsource() method of +the InteractiveColoredConsole. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-05-25-10-40-38 +.. gh-issue: 118908 +.. nonce: XcZiq4 +.. section: Library + +Limit exposed globals from internal imports and definitions on new REPL +startup. Patch by Eugene Triguba and Pablo Galindo. + +.. + +.. date: 2024-05-25-07-25-07 +.. gh-issue: 117865 +.. nonce: 1A0Xpi +.. section: Library + +Improve the import time of the :mod:`ast` module by deferring the import of +:mod:`re`. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-05-25-00-54-26 +.. gh-issue: 119127 +.. nonce: LpPvag +.. section: Library + +Positional arguments of :func:`functools.partial` objects now support +placeholders via :data:`functools.Placeholder`. + +.. + +.. date: 2024-05-24-21-54-55 +.. gh-issue: 113892 +.. nonce: JKDFqq +.. section: Library + +Now, the method ``sock_connect`` of :class:`asyncio.ProactorEventLoop` +raises a :exc:`ValueError` if given socket is not in non-blocking mode, as +well as in other loop implementations. + +.. + +.. date: 2024-05-24-14-32-24 +.. gh-issue: 119506 +.. nonce: -nMNqq +.. section: Library + +Fix :meth:`!io.TextIOWrapper.write` method breaks internal buffer when the +method is called again during flushing internal buffer. + +.. + +.. date: 2024-05-24-11-47-08 +.. gh-issue: 69214 +.. nonce: Grl6zF +.. section: Library + +Fix ``fcntl.ioctl()`` *request* parameter: use an ``unsigned long`` instead +of an ``unsigned int`` for the *request* parameter of :func:`fcntl.ioctl` to +support requests larger than ``UINT_MAX``. Patch by Victor Stinner. + +.. + +.. date: 2024-05-24-04-05-37 +.. gh-issue: 119105 +.. nonce: aDSRFn +.. section: Library + +``difflib``'s ``DIffer.compare()`` (and so also ``ndiff``) can no longer be +provoked into cubic-time behavior, or into unbounded recursion, and should +generally be faster in ordinary cases too. Results may change in some cases, +although that should be rare. Correctness of diffs is not affected. Some +similar lines far apart may be reported as deleting one and adding the +other, where before they were displayed on adjacent output lines with markup +showing the intraline differences. + +.. + +.. date: 2024-05-23-22-29-59 +.. gh-issue: 119443 +.. nonce: KAGz6S +.. section: Library + +The interactive REPL no longer runs with ``from __future__ import +annotations`` enabled. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-05-23-15-48-17 +.. gh-issue: 119461 +.. nonce: 82KqUW +.. section: Library + +Add ``socket.VMADDR_CID_LOCAL`` constant. Patch by Victor Stinner. + +.. + +.. date: 2024-05-23-11-52-36 +.. gh-issue: 117398 +.. nonce: 2FG1Mk +.. section: Library + +Objects in the datetime C-API are now all statically allocated, which means +better memory safety, especially when the module is reloaded. This should be +transparent to users. + +.. + +.. date: 2024-05-22-21-20-43 +.. gh-issue: 118894 +.. nonce: xHdxR_ +.. section: Library + +:mod:`asyncio` REPL now has the same capabilities as PyREPL. + +.. + +.. date: 2024-05-21-23-39-22 +.. gh-issue: 118830 +.. nonce: YTqvEo +.. section: Library + +Bump :mod:`pickle` default protocol to ``5``. + +.. + +.. date: 2024-05-21-20-13-23 +.. gh-issue: 118911 +.. nonce: iG8nMq +.. section: Library + +In PyREPL, updated ``maybe-accept``'s logic so that if the user hits +:kbd:`Enter` twice, they are able to terminate the block even if there's +trailing whitespace. Also, now when the user hits arrow up, the cursor is on +the last functional line. This matches IPython's behavior. Patch by Aya +Elsayed. + +.. + +.. date: 2024-05-21-19-10-30 +.. gh-issue: 115225 +.. nonce: eRmfJH +.. section: Library + +Raise error on certain technically valid but pathological ISO 8601 strings +passed to :meth:`datetime.time.fromisoformat` that were previously parsed +incorrectly. + +.. + +.. date: 2024-05-20-20-30-57 +.. gh-issue: 111201 +.. nonce: DAA5lC +.. section: Library + +Remove dependency to :mod:`readline` from the new Python REPL. + +.. + +.. date: 2024-05-20-13-48-37 +.. gh-issue: 119189 +.. nonce: dhJVs5 +.. section: Library + +When using the ``**`` operator or :func:`pow` with +:class:`~fractions.Fraction` as the base and an exponent that is not +rational, a float, or a complex, the fraction is no longer converted to a +float. + +.. + +.. date: 2024-05-19-18-49-04 +.. gh-issue: 119174 +.. nonce: 5GTv7d +.. section: Library + +Fix high DPI causes turtledemo(turtle-graphics examples) windows blurry +Patch by Wulian233 and Terry Jan Reedy + +.. + +.. date: 2024-05-19-13-05-59 +.. gh-issue: 119121 +.. nonce: P1gnh1 +.. section: Library + +Fix a NameError happening in ``asyncio.staggered.staggered_race``. This +function is now tested. + +.. + +.. date: 2024-05-19-12-25-36 +.. gh-issue: 119105 +.. nonce: VcR4ig +.. section: Library + +``difflib.Differ`` is much faster for some cases of diffs where many pairs +of lines are equally similar. + +.. + +.. date: 2024-05-17-17-32-12 +.. gh-issue: 119113 +.. nonce: kEv1Ll +.. section: Library + +Fix issue where :meth:`pathlib.PurePath.with_suffix` didn't raise +:exc:`TypeError` when given ``None`` as a suffix. + +.. + +.. date: 2024-05-16-17-31-46 +.. gh-issue: 118643 +.. nonce: hAWH4C +.. section: Library + +Fix an AttributeError in the :mod:`email` module when re-fold a long address +list. Also fix more cases of incorrect encoding of the address separator in +the address list. + +.. + +.. date: 2024-05-15-01-36-08 +.. gh-issue: 73991 +.. nonce: CGknDf +.. section: Library + +Add :meth:`pathlib.Path.copy`, which copies a file or directory to another. + +.. + +.. date: 2024-05-12-21-38-42 +.. gh-issue: 58933 +.. nonce: 0kgU2l +.. section: Library + +Make :mod:`pdb` return to caller frame correctly when ``f_trace`` of the +caller frame is not set + +.. + +.. date: 2024-05-11-20-23-45 +.. gh-issue: 82805 +.. nonce: F9bz4J +.. section: Library + +Support single-dot file extensions in :attr:`pathlib.PurePath.suffix` and +related attributes and methods. For example, the +:attr:`~pathlib.PurePath.suffixes` of ``PurePath('foo.bar.')`` are now +``['.bar', '.']`` rather than ``[]``. This brings file extension splitting +in line with :func:`os.path.splitext`. + +.. + +.. date: 2024-05-10-22-59-01 +.. gh-issue: 118924 +.. nonce: 9nyvSH +.. section: Library + +Remove :data:`!version` and :data:`!version_info` from :mod:`sqlite3`. Patch +by Hugo van Kemenade. + +.. + +.. date: 2024-05-10-22-36-01 +.. gh-issue: 118928 +.. nonce: IW7Ukv +.. section: Library + +Disallow using a sequence of parameters with named placeholders in +:mod:`sqlite3` queries. Patch by Erlend E. Aasland. + +.. + +.. date: 2024-05-10-05-24-32 +.. gh-issue: 118895 +.. nonce: wUm5r2 +.. section: Library + +Setting attributes on :data:`typing.NoDefault` now raises +:exc:`AttributeError` instead of :exc:`TypeError`. + +.. + +.. date: 2024-05-09-21-36-11 +.. gh-issue: 118868 +.. nonce: uckxxP +.. section: Library + +Fixed issue where kwargs were no longer passed to the logging handler +QueueHandler + +.. + +.. date: 2024-05-09-12-33-25 +.. gh-issue: 118827 +.. nonce: JrzHz1 +.. section: Library + +Remove deprecated :class:`!Quoter` class from :mod:`urllib.parse`. It had +previously raised a :exc:`DeprecationWarning` since Python 3.11. Patch by +Nikita Sobolev. + +.. + +.. date: 2024-05-09-11-50-26 +.. gh-issue: 118824 +.. nonce: -jBJQC +.. section: Library + +Remove deprecated :func:`!pty.master_open` and :func:`!pty.slave_open`. Use +:func:`pty.openpty` instead. Patch by Nikita Sobolev. + +.. + +.. date: 2024-05-09-08-46-12 +.. gh-issue: 118851 +.. nonce: aPAoJw +.. section: Library + +``ctx`` arguments to the constructors of :mod:`ast` node classes now default +to :class:`ast.Load() `. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-05-09-02-43-37 +.. gh-issue: 101588 +.. nonce: 30bNAr +.. section: Library + +Remove copy, deepcopy, and pickle from itertools. These had previously +raised a DeprecationWarning since Python 3.12. + +.. + +.. date: 2024-05-09-01-05-52 +.. gh-issue: 118805 +.. nonce: N7dm07 +.. section: Library + +Remove *type*, *choices*, and *metavar* parameters of +:class:`!argparse.BooleanOptionalAction`. They were deprecated since Python +3.12. + +.. + +.. date: 2024-05-09-00-52-30 +.. gh-issue: 118803 +.. nonce: Wv3AvU +.. section: Library + +:class:`!typing.ByteString` and :class:`!collections.abc.ByteString` are +removed. They had previously raised a :exc:`DeprecationWarning` since Python +3.12. + +.. + +.. date: 2024-05-08-23-16-50 +.. gh-issue: 118798 +.. nonce: Q_ybqP +.. section: Library + +The *isdst* parameter has been removed from :func:`email.utils.localtime`. +Patch by Hugo van Kemenade. + +.. + +.. date: 2024-05-08-21-30-33 +.. gh-issue: 118760 +.. nonce: XvyMHn +.. section: Library + +Restore the default value of ``tkiter.wantobjects`` to ``1``. + +.. + +.. date: 2024-05-08-21-13-56 +.. gh-issue: 118760 +.. nonce: mdmH3T +.. section: Library + +Fix errors in calling Tkinter bindings on Windows. + +.. + +.. date: 2024-05-08-20-41-48 +.. gh-issue: 74033 +.. nonce: YebHZj +.. section: Library + +Drop support for passing keyword arguments to :class:`pathlib.Path`. + +.. + +.. date: 2024-05-08-19-47-34 +.. gh-issue: 101357 +.. nonce: e4R_9x +.. section: Library + +Suppress all :exc:`OSError` exceptions from :meth:`pathlib.Path.exists` and +``is_*()`` methods, rather than a selection of more common errors. The new +behaviour is consistent with :func:`os.path.exists`, :func:`os.path.isdir`, +etc. Use :meth:`pathlib.Path.stat` to retrieve the file status without +suppressing exceptions. + +.. + +.. date: 2024-05-08-18-59-19 +.. gh-issue: 78707 +.. nonce: _Lz1sw +.. section: Library + +Drop support for passing additional positional arguments to +:meth:`pathlib.PurePath.relative_to` and +:meth:`~pathlib.PurePath.is_relative_to`. + +.. + +.. date: 2024-05-08-18-33-07 +.. gh-issue: 118507 +.. nonce: OCQsAY +.. section: Library + +Fix :func:`os.path.isfile` on Windows for pipes. Speedup +:func:`os.path.isjunction` and :func:`os.path.lexists` on Windows with a +native implementation. + +.. + +.. date: 2024-05-08-09-21-49 +.. gh-issue: 118772 +.. nonce: c16E8X +.. section: Library + +Allow :class:`typing.TypeVar` instances without a default to follow +instances without a default in some cases. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-05-07-17-38-53 +.. gh-issue: 118714 +.. nonce: XXKpVZ +.. section: Library + +Allow ``restart`` in post-mortem debugging of :mod:`pdb`. Removed restart +message when the user quits pdb from post-mortem mode. + +.. + +.. date: 2024-05-06-17-39-52 +.. gh-issue: 118673 +.. nonce: sTXBit +.. section: Library + +Removed executable bits and shebang from stdlib modules. + +.. + +.. date: 2024-05-01-22-24-05 +.. gh-issue: 110863 +.. nonce: GjYBbq +.. section: Library + +:func:`os.path.realpath` now suppresses any :exc:`OSError` from +:func:`os.readlink` when *strict* mode is disabled (the default). + +.. + +.. date: 2024-04-28-19-51-00 +.. gh-issue: 118263 +.. nonce: Gaap3S +.. section: Library + +Speed up :func:`os.path.splitroot` & :func:`os.path.normpath` with a direct +C call. + +.. + +.. date: 2024-04-24-16-23-04 +.. gh-issue: 110190 +.. nonce: TGd5qx +.. section: Library + +Fix ctypes structs with array on SPARC by setting ``MAX_STRUCT_SIZE`` to 32 +in stgdict. Patch by Jakub Kulik + +.. + +.. date: 2024-04-19-14-59-53 +.. gh-issue: 118033 +.. nonce: amS4Gw +.. section: Library + +Fix :func:`dataclasses.dataclass` not creating a ``__weakref__`` slot when +subclassing :class:`typing.Generic`. + +.. + +.. date: 2024-04-19-05-58-50 +.. gh-issue: 117766 +.. nonce: J3xepp +.. section: Library + +Always use :func:`str` to print ``choices`` in :mod:`argparse`. + +.. + +.. date: 2024-03-19-21-41-31 +.. gh-issue: 106531 +.. nonce: Mgd--6 +.. section: Library + +In :mod:`importlib.resources`, sync with `importlib_resources 6.3.2 +`_, +including: ``MultiplexedPath`` now expects ``Traversable`` paths, +deprecating string arguments to ``MultiplexedPath``; Enabled support for +resources in namespace packages in zip files; Fixed ``NotADirectoryError`` +when calling files on a subdirectory of a namespace package. + +.. + +.. date: 2024-02-27-10-22-15 +.. gh-issue: 115937 +.. nonce: 0cVNur +.. section: Library + +Removed extra preprocessing for the ``__signature__`` attribute: the code +just check if it's a :class:`inspect.Signature` instance. Patch by Sergey B +Kirpichev. + +.. + +.. date: 2024-02-22-10-12-59 +.. gh-issue: 115808 +.. nonce: F2g2Ku +.. section: Library + +Add :func:`operator.is_none` and :func:`operator.is_not_none` functions. + +.. + +.. date: 2024-01-18-21-44-23 +.. gh-issue: 114264 +.. nonce: DBKn29 +.. section: Library + +Improve performance of :func:`copy.deepcopy` by adding a fast path for +atomic types. + +.. + +.. date: 2024-01-14-11-43-31 +.. gh-issue: 113878 +.. nonce: dmEIN3 +.. section: Library + +Add *doc* parameter to :func:`dataclasses.field`, so it can be stored and +shown as a documentation / metadata. If ``@dataclass(slots=True)`` is used, +then the supplied string is availabl in the :attr:`~object.__slots__` dict. +Otherwise, the supplied string is only available in the corresponding +:class:`dataclasses.Field` object. + +In order to support this feature we are changing the ``__slots__`` format in +dataclasses from :class:`tuple` to :class:`dict` when documentation / +metadata is present. + +.. + +.. date: 2024-01-12-08-51-03 +.. gh-issue: 113978 +.. nonce: MqTgB0 +.. section: Library + +Ignore warnings on text completion inside REPL. + +.. + +.. date: 2023-12-14-13-43-27 +.. gh-issue: 113008 +.. nonce: jWYn8T +.. section: Library + +Correct argparse usage output for required, mutually exclusive groups +containing a positional argument + +.. + +.. date: 2023-12-12-15-19-58 +.. gh-issue: 108172 +.. nonce: KyDPuG +.. section: Library + +``webbrowser`` honors OS preferred browser on Linux when its desktop entry +name contains the text of a known browser name. + +.. + +.. date: 2023-09-19-17-56-24 +.. gh-issue: 109109 +.. nonce: WJvvX2 +.. section: Library + +You can now get the raw TLS certificate chains from TLS connections via +:meth:`ssl.SSLSocket.get_verified_chain` and +:meth:`ssl.SSLSocket.get_unverified_chain` methods. + +Contributed by Mateusz Nowak. + +.. + +.. date: 2023-06-17-09-07-06 +.. gh-issue: 105623 +.. nonce: 5G06od +.. section: Library + +Fix performance degradation in +:class:`logging.handlers.RotatingFileHandler`. Patch by Craig Robson. + +.. + +.. date: 2023-06-16-14-52-00 +.. gh-issue: 102450 +.. nonce: MfeR6A +.. section: Library + +Add missing ISO-8601 24:00 alternative to midnight of next day to +:meth:`datetime.datetime.fromisoformat` and +:meth:`datetime.time.fromisoformat`. Patch by Izan "TizzySaurus" Robinson +(tizzysaurus@gmail.com) + +.. + +.. date: 2023-04-28-09-54-15 +.. gh-issue: 103956 +.. nonce: EyLDPS +.. section: Library + +Fix lack of newline characters in :mod:`trace` module output when line +tracing is enabled but source code line for current frame is not available. + +.. + +.. date: 2023-04-26-22-24-17 +.. gh-issue: 92081 +.. nonce: V8xMot +.. section: Library + +Fix missing spaces in email headers when the spaces are mixed with encoded +8-bit characters. + +.. + +.. date: 2023-04-24-05-34-23 +.. gh-issue: 103194 +.. nonce: GwBwWL +.. section: Library + +Prepare Tkinter for C API changes in Tcl 8.7/9.0 to avoid +:class:`!_tkinter.Tcl_Obj` being unexpectedly returned instead of +:class:`bool`, :class:`str`, :class:`bytearray`, or :class:`int`. + +.. + +.. date: 2023-04-10-00-04-37 +.. gh-issue: 87106 +.. nonce: UyBnPQ +.. section: Library + +Fixed handling in :meth:`inspect.Signature.bind` of keyword arguments having +the same name as positional-only arguments when a variadic keyword argument +(e.g. ``**kwargs``) is present. + +.. + +.. date: 2023-03-30-18-19-53 +.. gh-issue: 103134 +.. nonce: bHrn91 +.. section: Library + +Add additional methods to :ref:`proxy objects +` in the :mod:`!multiprocessing` module: + +* :meth:`!clear` and :meth:`!copy` for proxies of :class:`list` +* :meth:`~dict.fromkeys`, ``reversed(d)``, ``d | {}``, ``{} | d``, + ``d |= {'b': 2}`` for proxies of :class:`dict` + +.. + +.. bpo: 45767 +.. date: 2022-03-10-16-47-57 +.. nonce: ywmyo1 +.. section: Library + +Fix integer conversion in :func:`os.major`, :func:`os.minor`, and +:func:`os.makedev`. Support device numbers larger than ``2**63-1``. Support +non-existent device number (``NODEV``). + +.. + +.. bpo: 44864 +.. date: 2021-08-24-19-37-46 +.. nonce: KzxaDh +.. section: Library + +Do not translate user-provided strings in :class:`argparse.ArgumentParser`. + +.. + +.. bpo: 41843 +.. date: 2020-12-22-18-08-12 +.. nonce: q9Nh2r +.. section: Library + +Solaris now uses :func:`os.sendfile` fast-copy syscall for more efficient +:mod:`shutil` file copy related functions. + +.. + +.. bpo: 15987 +.. date: 2020-03-28-21-00-54 +.. nonce: aBL8XS +.. section: Library + +Implemented :func:`ast.compare` for comparing two ASTs. Patch by Batuhan +Taskaya with some help from Jeremy Hylton. + +.. + +.. date: 2019-08-27-01-16-50 +.. gh-issue: 67693 +.. nonce: 4NIAiy +.. section: Library + +Fix :func:`urllib.parse.urlunparse` and :func:`urllib.parse.urlunsplit` for +URIs with path starting with multiple slashes and no authority. Based on +patch by Ashwin Ramaswami. + +.. + +.. bpo: 14074 +.. date: 2018-12-04-07-36-27 +.. nonce: fMLKCu +.. section: Library + +Fix :mod:`argparse` metavar processing to allow positional arguments to have +a tuple metavar. + +.. + +.. date: 2024-10-04-15-34-34 +.. gh-issue: 122392 +.. nonce: V8K3w2 +.. section: IDLE + +Increase currently inadequate vertical spacing for the IDLE browsers (path, +module, and stack) on high-resolution monitors. + +.. + +.. date: 2024-09-21-23-12-18 +.. gh-issue: 112938 +.. nonce: OeiDru +.. section: IDLE + +Fix uninteruptable hang when Shell gets rapid continuous output. + +.. + +.. date: 2024-07-30-18-02-55 +.. gh-issue: 122482 +.. nonce: TerE0g +.. section: IDLE + +Change About IDLE to direct users to discuss.python.org instead of the now +unused idle-dev email and mailing list. + +.. + +.. date: 2024-07-16-16-57-03 +.. gh-issue: 78889 +.. nonce: U7ghFD +.. section: IDLE + +Stop Shell freezes by blocking user access to non-method sys.stdout.shell +attributes, which are all private. + +.. + +.. date: 2024-06-16-21-42-45 +.. gh-issue: 120083 +.. nonce: nczuyv +.. section: IDLE + +Add explicit black IDLE Hovertip foreground color needed for recent macOS. +Fixes Sonoma showing unreadable white on pale yellow. Patch by John +Riggles. + +.. + +.. date: 2024-06-05-14-54-24 +.. gh-issue: 120104 +.. nonce: j_thj4 +.. section: IDLE + +Fix padding in config and search dialog windows in IDLE. + +.. + +.. date: 2024-10-10-02-56-24 +.. gh-issue: 124872 +.. nonce: 0mDDOq +.. section: Documentation + +Added definitions for :term:`context`, :term:`current context`, and +:term:`context management protocol`, updated related definitions to be +consistent, and expanded the documentation for :class:`contextvars.Context`. + +.. + +.. date: 2024-10-07-00-31-17 +.. gh-issue: 125018 +.. nonce: yKnymn +.. section: Documentation + +The :mod:`importlib.metadata` documentation now includes semantic +cross-reference targets for the significant documented APIs. This means +intersphinx references like :func:`importlib.metadata.version` will now work +as expected. + +.. + +.. date: 2024-09-27-16-47-48 +.. gh-issue: 124720 +.. nonce: nVSTVb +.. section: Documentation + +Update "Using Python on a Mac" section of the "Python Setup and Usage" +document and include information on installing free-threading support. + +.. + +.. date: 2024-09-24-11-52-36 +.. gh-issue: 124457 +.. nonce: yrCjSV +.. section: Documentation + +Remove coverity scan from the CPython repo. It has not been used since 2020 +and is currently unmaintained. + +.. + +.. date: 2024-09-19-19-33-25 +.. gh-issue: 116622 +.. nonce: M65UZ6 +.. section: Documentation + +Add an Android platform guide, and flag modules not available on Android. + +.. + +.. date: 2024-09-11-16-52-08 +.. gh-issue: 123976 +.. nonce: jhOfNR +.. section: Documentation + +Refresh docs around custom providers. + +.. + +.. date: 2024-08-01-17-18-21 +.. gh-issue: 70870 +.. nonce: fZnBM9 +.. section: Documentation + +Clarified the dual usage of the term "free variable" (both the formal +meaning of any reference to names defined outside the local scope, and the +narrower pragmatic meaning of nonlocal variables named in ``co_freevars``). + +.. + +.. date: 2024-07-19-12-22-48 +.. gh-issue: 121277 +.. nonce: wF_zKd +.. section: Documentation + +Writers of CPython's documentation can now use ``next`` as the version for +the ``versionchanged``, ``versionadded``, ``deprecated`` directives. + +.. + +.. date: 2024-07-14-12-25-53 +.. gh-issue: 117765 +.. nonce: YFMOUv +.. section: Documentation + +Improved documentation for :func:`unittest.mock.patch.dict` + +.. + +.. date: 2024-07-14-11-48-10 +.. gh-issue: 121749 +.. nonce: nxHoTk +.. section: Documentation + +Fix documentation for :c:func:`PyModule_AddObjectRef`. + +.. + +.. date: 2024-06-05-12-36-18 +.. gh-issue: 120012 +.. nonce: f14DbQ +.. section: Documentation + +Clarify the behaviours of :meth:`multiprocessing.Queue.empty` and +:meth:`multiprocessing.SimpleQueue.empty` on closed queues. Patch by +Bénédikt Tran. + +.. + +.. date: 2024-06-03-22-06-26 +.. gh-issue: 119574 +.. nonce: Ik9kOO +.. section: Documentation + +Added some missing environment variables to the output of +:option:`--help-env`. + +.. + +.. bpo: 34008 +.. date: 2018-07-04-20-35-25 +.. nonce: bqecIb +.. section: Documentation + +The :c:func:`Py_Main` documentation moved from the "Very High Level API" +section to the "Initialization and Finalization" section. + +Also make it explicit that we expect ``Py_Main`` to typically be called +instead of ``Py_Initialize`` rather than after it (since ``Py_Main`` makes +its own call to ``Py_Initialize``). Document that calling both is supported +but is version dependent on which settings will be applied correctly. + +.. + +.. date: 2024-10-15-15-29-41 +.. gh-issue: 124375 +.. nonce: wNrWVa +.. section: Core and Builtins + +Fix a crash in the free threading build when the GC runs concurrently with a +new thread starting. + +.. + +.. date: 2024-10-10-14-47-13 +.. gh-issue: 125221 +.. nonce: nfSQzT +.. section: Core and Builtins + +Fix possible race condition when calling :meth:`~object.__reduce_ex__` for +the first time in the free threading build. + +.. + +.. date: 2024-10-10-12-04-56 +.. gh-issue: 125174 +.. nonce: _8h6T7 +.. section: Core and Builtins + +Make the handling of reference counts of immortal objects more robust. +Immortal objects with reference counts that deviate from their original +reference count by up to a billion (half a billion on 32 bit builds) are +still counted as immortal. + +.. + +.. date: 2024-10-07-23-33-18 +.. gh-issue: 125039 +.. nonce: MKTyNI +.. section: Core and Builtins + +Make ``this_instr`` and ``prev_instr`` const in cases generator. + +.. + +.. date: 2024-10-05-23-53-06 +.. gh-issue: 125008 +.. nonce: ETANpd +.. section: Core and Builtins + +Fix :func:`tokenize.untokenize` producing invalid syntax for double braces +preceded by certain escape characters. + +.. + +.. date: 2024-10-03-22-26-39 +.. gh-issue: 124871 +.. nonce: tAMF47 +.. section: Core and Builtins + +Fix compiler bug (in some versions of 3.13) where an assertion fails during +reachability analysis. + +.. + +.. date: 2024-10-03-14-39-41 +.. gh-issue: 123378 +.. nonce: dCxANf +.. section: Core and Builtins + +Fix a crash in the :meth:`~object.__str__` method of :exc:`UnicodeError` +objects when the :attr:`UnicodeError.start` and :attr:`UnicodeError.end` +values are invalid or out-of-range. Patch by Bénédikt Tran. + +.. + +.. date: 2024-09-30-16-39-37 +.. gh-issue: 118093 +.. nonce: J2A3gz +.. section: Core and Builtins + +Improve the experimental JIT compiler's ability to stay "on trace" when +encountering highly-biased branches. + +.. + +.. date: 2024-09-27-17-18-53 +.. gh-issue: 124642 +.. nonce: OCjhBJ +.. section: Core and Builtins + +Fixed scalability issue in free-threaded builds for lock-free reads from +dictionaries in multi-threaded scenarios + +.. + +.. date: 2024-09-26-18-21-06 +.. gh-issue: 116510 +.. nonce: FacUWO +.. section: Core and Builtins + +Fix a crash caused by immortal interned strings being shared between +sub-interpreters that use basic single-phase init. In that case, the string +can be used by an interpreter that outlives the interpreter that created and +interned it. For interpreters that share obmalloc state, also share the +interned dict with the main interpreter. + +.. + +.. date: 2024-09-26-17-55-34 +.. gh-issue: 116510 +.. nonce: dhn8w8 +.. section: Core and Builtins + +Fix a bug that can cause a crash when sub-interpreters use "basic" +single-phase extension modules. Shared objects could refer to PyGC_Head +nodes that had been freed as part of interpreter cleanup. + +.. + +.. date: 2024-09-26-13-25-01 +.. gh-issue: 119180 +.. nonce: k_JCX0 +.. section: Core and Builtins + +The ``__main__`` module no longer always contains an ``__annotations__`` +dictionary in its global namespace. + +.. + +.. date: 2024-09-26-12-19-13 +.. gh-issue: 124547 +.. nonce: P_SHfU +.. section: Core and Builtins + +When deallocating an object with inline values whose ``__dict__`` is still +live: if memory allocation for the inline values fails, clear the +dictionary. Prevents an interpreter crash. + +.. + +.. date: 2024-09-25-14-45-56 +.. gh-issue: 124513 +.. nonce: ywiXtr +.. section: Core and Builtins + +Fix a crash in FrameLocalsProxy constructor: check the number of arguments. +Patch by Victor Stinner. + +.. + +.. date: 2024-09-25-11-53-22 +.. gh-issue: 124442 +.. nonce: EXC1Ve +.. section: Core and Builtins + +Fix nondeterminism in compilation by sorting the value of +:attr:`~type.__static_attributes__`. Patch by kp2pml30. + +.. + +.. date: 2024-09-23-23-06-19 +.. gh-issue: 124285 +.. nonce: mahGTg +.. section: Core and Builtins + +Fix bug where ``bool(a)`` can be invoked more than once during the +evaluation of a compound boolean expression. + +.. + +.. date: 2024-09-23-15-23-14 +.. gh-issue: 123856 +.. nonce: yrgJ9m +.. section: Core and Builtins + +Fix PyREPL failure when a keyboard interrupt is triggered after using a +history search + +.. + +.. date: 2024-09-23-13-25-27 +.. gh-issue: 65961 +.. nonce: LDqXV2 +.. section: Core and Builtins + +Deprecate the setting and using ``__package__`` and ``__cached__``. + +.. + +.. date: 2024-09-19-16-57-34 +.. gh-issue: 119726 +.. nonce: DseseK +.. section: Core and Builtins + +The JIT now generates more efficient code for calls to C functions resulting +in up to 0.8% memory savings and 1.5% speed improvement on AArch64. Patch by +Diego Russo. + +.. + +.. date: 2024-09-19-13-17-31 +.. gh-issue: 122878 +.. nonce: 4iFpsB +.. section: Core and Builtins + +Use the ``pager`` binary, if available (e.g. on Debian and derivatives), to +display REPL ``help()``. + +.. + +.. date: 2024-09-17-22-06-01 +.. gh-issue: 124188 +.. nonce: aFqNAB +.. section: Core and Builtins + +Fix reading and decoding a line from the source file witn non-UTF-8 encoding +for syntax errors raised in the compiler. + +.. + +.. date: 2024-09-13-02-25-06 +.. gh-issue: 124027 +.. nonce: to_9DY +.. section: Core and Builtins + +Support ````, ````, and ```` keys in the Python +REPL when ``$TERM`` is set to ``vt100``. + +.. + +.. date: 2024-09-12-21-53-26 +.. gh-issue: 124022 +.. nonce: fQzUiW +.. section: Core and Builtins + +Fix bug where docstring is removed from classes in interactive mode. + +.. + +.. date: 2024-09-11-15-48-36 +.. gh-issue: 123958 +.. nonce: 5VW2r0 +.. section: Core and Builtins + +docstrings are now removed from the optimized AST in optimization level 2. + +.. + +.. date: 2024-09-10-20-25-00 +.. gh-issue: 123923 +.. nonce: A7uxqa +.. section: Core and Builtins + +The ``f_executable`` field in the internal :c:struct:`_PyInterpreterFrame` +struct now uses a tagged pointer. Profilers and debuggers that uses this +field should clear the least significant bit to recover the +:c:expr:`PyObject*` pointer. + +.. + +.. date: 2024-09-10-13-27-16 +.. gh-issue: 77894 +.. nonce: ZC-Olu +.. section: Core and Builtins + +Fix possible crash in the garbage collector when it tries to break a +reference loop containing a :class:`memoryview` object. Now a +:class:`!memoryview` object can only be cleared if there are no buffers that +refer it. + +.. + +.. date: 2024-09-06-19-23-44 +.. gh-issue: 120221 +.. nonce: giJEDT +.. section: Core and Builtins + +asyncio REPL is now again properly recognizing KeyboardInterrupts. Display +of exceptions raised in secondary threads is fixed. + +.. + +.. date: 2024-09-06-14-13-01 +.. gh-issue: 119310 +.. nonce: WQxyDF +.. section: Core and Builtins + +Allow the new interactive shell to read history files written with the +editline library that use unicode-escaped entries. Patch by aorcajo and +Łukasz Langa. + +.. + +.. date: 2024-09-03-13-34-35 +.. gh-issue: 123572 +.. nonce: uuqoYV +.. section: Core and Builtins + +Fix key mappings for various F-keys in Windows for the new REPL. Patch by +devdanzin + +.. + +.. date: 2024-09-02-20-39-10 +.. gh-issue: 123614 +.. nonce: 26TMHp +.. section: Core and Builtins + +Add :func:`turtle.save` to easily save Turtle drawings as PostScript files. +Patch by Marie Roald and Yngve Mardal Moe. + +.. + +.. date: 2024-09-02-20-36-45 +.. gh-issue: 123339 +.. nonce: QcmpSs +.. section: Core and Builtins + +Setting the :attr:`!__module__` attribute for a class now removes the +``__firstlineno__`` item from the type's dict, so they will no longer be +inconsistent. + +.. + +.. date: 2024-09-02-17-32-15 +.. gh-issue: 119034 +.. nonce: HYh5Vj +.. section: Core and Builtins + +Change ```` and ```` keys of the Python REPL to history +search forward/backward. Patch by Victor Stinner. + +.. + +.. date: 2024-09-01-12-08-39 +.. gh-issue: 123562 +.. nonce: aJPKVu +.. section: Core and Builtins + +Improve :exc:`SyntaxError` message for using ``case ... as ...`` with not a +name. + +.. + +.. date: 2024-09-01-00-02-05 +.. gh-issue: 123545 +.. nonce: 8nQNbL +.. section: Core and Builtins + +Fix a double decref in rare cases on experimental JIT builds. + +.. + +.. date: 2024-08-29-19-46-07 +.. gh-issue: 123484 +.. nonce: rjUn_F +.. section: Core and Builtins + +Fix ``_Py_DebugOffsets`` for long objects to be relative to the start of the +object rather than the start of a subobject. + +.. + +.. date: 2024-08-29-13-18-18 +.. gh-issue: 123446 +.. nonce: KWDrgq +.. section: Core and Builtins + +Fix empty function name in :exc:`TypeError` when builtin magic methods are +used without the required args. + +.. + +.. date: 2024-08-28-22-42-51 +.. gh-issue: 123440 +.. nonce: yOFB0N +.. section: Core and Builtins + +Improve :exc:`SyntaxError` message for using ``except as`` with not a name. + +.. + +.. date: 2024-08-27-21-44-14 +.. gh-issue: 116017 +.. nonce: ZY3yBY +.. section: Core and Builtins + +Improved JIT memory consumption by periodically freeing memory used by +infrequently-executed code. This change is especially likely to improve the +memory footprint of long-running programs. + +.. + +.. date: 2024-08-27-13-16-40 +.. gh-issue: 123344 +.. nonce: 56Or78 +.. section: Core and Builtins + +Add AST optimizations for type parameter defaults. + +.. + +.. date: 2024-08-26-00-58-26 +.. gh-issue: 123321 +.. nonce: ApxcnE +.. section: Core and Builtins + +Prevent Parser/myreadline race condition from segfaulting on multi-threaded +use. Patch by Bar Harel and Amit Wienner. + +.. + +.. date: 2024-08-25-18-27-49 +.. gh-issue: 123177 +.. nonce: yLuyqE +.. section: Core and Builtins + +Fix a bug causing stray prompts to appear in the middle of wrapped lines in +the new REPL. + +.. + +.. date: 2024-08-25-10-54-22 +.. gh-issue: 122982 +.. nonce: KLD91q +.. section: Core and Builtins + +Extend the deprecation period for bool inversion (``~``) by two years. + +.. + +.. date: 2024-08-23-21-20-34 +.. gh-issue: 123271 +.. nonce: xeVViR +.. section: Core and Builtins + +Make concurrent iterations over the same :func:`zip` iterator safe under +free-threading. + +.. + +.. date: 2024-08-23-18-31-10 +.. gh-issue: 123275 +.. nonce: DprIrj +.. section: Core and Builtins + +Support :option:`-X gil=1 <-X>` and :envvar:`PYTHON_GIL=1 ` on +non-free-threaded builds. + +.. + +.. date: 2024-08-23-15-59-54 +.. gh-issue: 123177 +.. nonce: OLcaC5 +.. section: Core and Builtins + +Deactivate line wrap in the Apple Terminal via a ANSI escape code. Patch by +Pablo Galindo + +.. + +.. date: 2024-08-23-13-08-27 +.. gh-issue: 123229 +.. nonce: aHm-dw +.. section: Core and Builtins + +Fix valgrind warning by initializing the f-string buffers to 0 in the +tokenizer. Patch by Pablo Galindo + +.. + +.. date: 2024-08-23-11-26-54 +.. gh-issue: 122298 +.. nonce: ZMyln4 +.. section: Core and Builtins + +Restore printout of GC stats when ``gc.set_debug(gc.DEBUG_STATS)`` is +called. This feature was accidentally removed when implementing incremental +GC. + +.. + +.. date: 2024-08-21-15-22-53 +.. gh-issue: 121804 +.. nonce: r5K3PS +.. section: Core and Builtins + +Correctly show error locations when a :exc:`SyntaxError` is raised in the +basic REPL. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-08-21-08-53-00 +.. gh-issue: 115776 +.. nonce: 9A7Dv_ +.. section: Core and Builtins + +Enables inline values (Python's equivalent of hidden classes) on any class +who's instances are of a fixed size. + +.. + +.. date: 2024-08-20-12-29-52 +.. gh-issue: 123142 +.. nonce: 3PXiNb +.. section: Core and Builtins + +Fix too-wide source location in exception tracebacks coming from broken +iterables in comprehensions. + +.. + +.. date: 2024-08-20-11-09-16 +.. gh-issue: 123048 +.. nonce: 2TISpv +.. section: Core and Builtins + +Fix a bug where pattern matching code could emit a :opcode:`JUMP_FORWARD` +with no source location. + +.. + +.. date: 2024-08-19-15-13-13 +.. gh-issue: 118093 +.. nonce: dLZ8qS +.. section: Core and Builtins + +Break up ``CALL_ALLOC_AND_ENTER_INIT`` into micro-ops and relax requirement +for exact args, in order to increase the amount of code supported by tier 2. + +.. + +.. date: 2024-08-18-18-25-54 +.. gh-issue: 123123 +.. nonce: 0ZcaEB +.. section: Core and Builtins + +Fix displaying :exc:`SyntaxError` exceptions covering multiple lines. Patch +by Pablo Galindo + +.. + +.. date: 2024-08-17-17-26-25 +.. gh-issue: 123083 +.. nonce: 9xWLJ- +.. section: Core and Builtins + +Fix a potential use-after-free in ``STORE_ATTR_WITH_HINT``. + +.. + +.. date: 2024-08-15-19-28-43 +.. gh-issue: 123022 +.. nonce: m3EF9E +.. section: Core and Builtins + +Fix crash in free-threaded build when calling :c:func:`Py_Initialize` from a +non-main thread. + +.. + +.. date: 2024-08-14-11-38-56 +.. gh-issue: 118093 +.. nonce: 3BywDP +.. section: Core and Builtins + +Add three specializations for :opcode:`CALL_KW`: + +* :opcode:`!CALL_KW_PY` for calls to Python functions +* :opcode:`!CALL_KW_BOUND_METHOD` for calls to bound methods +* :opcode:`!CALL_KW_NON_PY` for all other calls + +.. + +.. date: 2024-08-12-11-45-47 +.. gh-issue: 122821 +.. nonce: WnAzTK +.. section: Core and Builtins + +Make sure that branches in :keyword:`while` statements have consistent +offsets for :mod:`sys.monitoring`. :keyword:`!while` statements are now +compiled with a simple jump at the end of the body, instead of duplicating +the test. + +.. + +.. date: 2024-08-12-11-19-37 +.. gh-issue: 122907 +.. nonce: q68096 +.. section: Core and Builtins + +Building with ``HAVE_DYNAMIC_LOADING`` now works as well as it did in 3.12. +Existing deficiences will be addressed separately. (See +https://github.com/python/cpython/issues/122950.) + +.. + +.. date: 2024-08-10-12-44-03 +.. gh-issue: 122888 +.. nonce: TUyu9r +.. section: Core and Builtins + +Fix crash on certain calls to ``str()`` with positional arguments of the +wrong type. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-08-08-16-02-28 +.. gh-issue: 118093 +.. nonce: m6Mrvy +.. section: Core and Builtins + +Improve the experimental JIT's handling of polymorphic code. + +.. + +.. date: 2024-08-05-19-28-12 +.. gh-issue: 122697 +.. nonce: 17MvYl +.. section: Core and Builtins + +Fixed memory leaks at interpreter shutdown in the free-threaded build, and +also reporting of leaked memory blocks via :option:`-X showrefcount <-X>`. + +.. + +.. date: 2024-08-05-19-04-06 +.. gh-issue: 116622 +.. nonce: 3LWUzE +.. section: Core and Builtins + +Fix Android stdout and stderr messages being truncated or lost. + +.. + +.. date: 2024-08-01-19-13-58 +.. gh-issue: 122527 +.. nonce: eztso6 +.. section: Core and Builtins + +Fix a crash that occurred when a ``PyStructSequence`` was deallocated after +its type's dictionary was cleared by the GC. The type's +:c:member:`~PyTypeObject.tp_basicsize` now accounts for non-sequence fields +that aren't included in the :c:macro:`Py_SIZE` of the sequence. + +.. + +.. date: 2024-07-30-11-41-35 +.. gh-issue: 122445 +.. nonce: Rq0bjS +.. section: Core and Builtins + +Add only fields which are modified via self.* to +:attr:`~type.__static_attributes__`. + +.. + +.. date: 2024-07-29-19-20-25 +.. gh-issue: 122417 +.. nonce: NVgs0a +.. section: Core and Builtins + +In the free-threaded build, the reference counts for heap type objects are +now partially stored in a distributed manner in per-thread arrays. This +reduces contention on the heap type's reference count fields when creating +or destroying instances of the same type from multiple threads concurrently. + +.. + +.. date: 2024-07-29-10-55-46 +.. gh-issue: 116090 +.. nonce: p1MhU0 +.. section: Core and Builtins + +Fix an issue in JIT builds that prevented some :keyword:`for` loops from +correctly firing :monitoring-event:`RAISE` monitoring events. + +.. + +.. date: 2024-07-26-14-05-51 +.. gh-issue: 122300 +.. nonce: SVIF-l +.. section: Core and Builtins + +Preserve AST nodes for f-string with single-element format specifiers. Patch +by Pablo Galindo + +.. + +.. date: 2024-07-26-13-56-32 +.. gh-issue: 120906 +.. nonce: qBh2I9 +.. section: Core and Builtins + +:attr:`frame.f_locals` now supports arbitrary hashable objects as keys. + +.. + +.. date: 2024-07-25-01-45-21 +.. gh-issue: 122239 +.. nonce: 7zh-sW +.. section: Core and Builtins + +When a :class:`list`, :class:`tuple` or :class:`dict` with too many elements +is unpacked, show the actual length in the error message. + +.. + +.. date: 2024-07-24-22-39-07 +.. gh-issue: 122245 +.. nonce: LVa9v8 +.. section: Core and Builtins + +Detection of writes to ``__debug__`` is moved from the compiler's codegen +stage to the symtable. This means that these errors are now detected even in +code that is optimized away before codegen (such as assertions with the +:option:`-O` command line option). + +.. + +.. date: 2024-07-24-17-11-51 +.. gh-issue: 122234 +.. nonce: VxsP_F +.. section: Core and Builtins + +Specializations for sums with float and complex inputs in :func:`sum` now +always use compensated summation. Also, for integer items in above +specializations: :c:func:`PyLong_AsDouble` is used, instead of +:c:func:`PyLong_AsLongAndOverflow`. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-07-23-23-59-04 +.. gh-issue: 122208 +.. nonce: z8KHsY +.. section: Core and Builtins + +Dictionary watchers now only deliver the PyDict_EVENT_ADDED event when the +insertion is in a known good state to succeed. + +.. + +.. date: 2024-07-23-11-57-36 +.. gh-issue: 122160 +.. nonce: HSnrAP +.. section: Core and Builtins + +Remove the ``BUILD_CONST_KEY_MAP`` opcode. Use :opcode:`BUILD_MAP` instead. + +.. + +.. date: 2024-07-21-01-23-54 +.. gh-issue: 122029 +.. nonce: gKv-e2 +.. section: Core and Builtins + +Emit ``c_call`` events in :func:`sys.setprofile` when a ``PyMethodObject`` +pointing to a ``PyCFunction`` is called. + +.. + +.. date: 2024-07-19-15-28-05 +.. gh-issue: 122026 +.. nonce: sta2Ca +.. section: Core and Builtins + +Fix a bug that caused the tokenizer to not correctly identify mismatched +parentheses inside f-strings in some situations. Patch by Pablo Galindo + +.. + +.. date: 2024-07-19-09-38-01 +.. gh-issue: 99108 +.. nonce: qzM6gl +.. section: Core and Builtins + +Python's hashlib now unconditionally uses the vendored HACL* library for +Blake2. Python no longer accepts libb2 as an optional dependency for Blake2. + +We refreshed HACL* to the latest version, and now vendor HACL*'s 128-bit and +256-bit wide vector implementations for Blake2, which are used on x86/x64 +toolchains when the required CPU features are available at runtime. + +HACL*'s 128-bit wide vector implementation of Blake2 can also run on ARM +NEON and Power8, but lacking evidence of a performance gain, these are not +enabled (yet). + +.. + +.. date: 2024-07-18-21-19-04 +.. gh-issue: 121999 +.. nonce: 8IBbTK +.. section: Core and Builtins + +The default extraction filter for the :mod:`tarfile` module is now set to +:func:`'data' `. + +.. + +.. date: 2024-07-16-18-23-22 +.. gh-issue: 121860 +.. nonce: -FTauD +.. section: Core and Builtins + +Fix crash when rematerializing a managed dictionary after it was deleted. + +.. + +.. date: 2024-07-16-15-11-51 +.. gh-issue: 121795 +.. nonce: xkIHrI +.. section: Core and Builtins + +Improve performance of set membership testing, ``set.remove()`` and +``set.discard()`` when the argument is a set. + +.. + +.. date: 2024-07-15-20-41-06 +.. gh-issue: 121814 +.. nonce: oR2ixR +.. section: Core and Builtins + +Fixed the SegFault when :c:func:`PyEval_SetTrace` is used with no Python +frame on stack. + +.. + +.. date: 2024-07-15-20-03-29 +.. gh-issue: 121295 +.. nonce: w53ucI +.. section: Core and Builtins + +Fix PyREPL console getting into a blocked state after interrupting a long +paste + +.. + +.. date: 2024-07-15-16-26-32 +.. gh-issue: 121794 +.. nonce: fhBtiQ +.. section: Core and Builtins + +Fix bug in free-threaded Python where a resurrected object could lead to a +negative ref count assertion failure. + +.. + +.. date: 2024-07-13-12-27-31 +.. gh-issue: 121657 +.. nonce: wgOYLw +.. section: Core and Builtins + +Improve the :exc:`SyntaxError` message if the user tries to use +:keyword:`yield from ` outside a function. + +.. + +.. date: 2024-07-13-09-51-44 +.. gh-issue: 121609 +.. nonce: jWsE5t +.. section: Core and Builtins + +Fix pasting of characters containing unicode character joiners in the new +REPL. Patch by Marta Gomez Macias + +.. + +.. date: 2024-07-12-18-18-44 +.. gh-issue: 121297 +.. nonce: 67VE7b +.. section: Core and Builtins + +Previously, incorrect usage of :keyword:`await` or asynchronous +comprehensions in code removed by the :option:`-O` option was not flagged by +the Python compiler. Now, such code raises :exc:`SyntaxError`. Patch by +Jelle Zijlstra. + +.. + +.. date: 2024-07-10-15-43-54 +.. gh-issue: 117482 +.. nonce: 5WYaXR +.. section: Core and Builtins + +Unexpected slot wrappers are no longer created for builtin static types in +subinterpreters. + +.. + +.. date: 2024-07-10-02-02-32 +.. gh-issue: 121562 +.. nonce: 8beIMi +.. section: Core and Builtins + +Optimized performance of hex_from_char by replacing switch-case with a +lookup table + +.. + +.. date: 2024-07-09-13-53-18 +.. gh-issue: 121499 +.. nonce: rpp7il +.. section: Core and Builtins + +Fix a bug affecting how multi-line history was being rendered in the new +REPL after interacting with the new screen cache. Patch by Pablo Galindo + +.. + +.. date: 2024-07-08-17-15-14 +.. gh-issue: 121497 +.. nonce: I8hMDC +.. section: Core and Builtins + +Fix a bug that was preventing the REPL to correctly respect the history when +an input hook was set. Patch by Pablo Galindo + +.. + +.. date: 2024-07-08-10-31-08 +.. gh-issue: 121012 +.. nonce: M5hHk- +.. section: Core and Builtins + +Tier 2 execution now ensures that list iterators remain exhausted, once they +become exhausted. + +.. + +.. date: 2024-07-08-02-24-55 +.. gh-issue: 121439 +.. nonce: jDHod3 +.. section: Core and Builtins + +Allow tuples of length 20 in the freelist to be reused. + +.. + +.. date: 2024-07-05-11-29-27 +.. gh-issue: 121288 +.. nonce: lYKYYP +.. section: Core and Builtins + +:exc:`ValueError` messages for :meth:`!list.index`, :meth:`!range.index`, +:meth:`!deque.index`, :meth:`!deque.remove` and :meth:`!ShareableList.index` +no longer contain the repr of the searched value (which can be arbitrary +large) and are consistent with error messages for other :meth:`!index` and +:meth:`!remove` methods. + +.. + +.. date: 2024-07-04-23-38-30 +.. gh-issue: 121368 +.. nonce: m3EF9E +.. section: Core and Builtins + +Fix race condition in ``_PyType_Lookup`` in the free-threaded build due to a +missing memory fence. This could lead to ``_PyType_Lookup`` returning +incorrect results on arm64. + +.. + +.. date: 2024-06-30-03-48-10 +.. gh-issue: 121149 +.. nonce: lLBMKe +.. section: Core and Builtins + +Added specialization for summation of complexes, this also improves accuracy +of builtin :func:`sum` for such inputs. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-06-29-10-46-14 +.. gh-issue: 121130 +.. nonce: Rj66Xs +.. section: Core and Builtins + +Fix f-strings with debug expressions in format specifiers. Patch by Pablo +Galindo + +.. + +.. date: 2024-06-28-23-17-22 +.. gh-issue: 121381 +.. nonce: i2xL7P +.. section: Core and Builtins + +Remove ``subprocess._USE_VFORK`` escape hatch code and documentation. It was +added just in case, and doesn't have any known cases that require it. + +.. + +.. date: 2024-06-28-18-34-49 +.. gh-issue: 119726 +.. nonce: Fjv_Ab +.. section: Core and Builtins + +Optimize code layout for calls to C functions from the JIT on AArch64. Patch +by Diego Russo. + +.. + +.. date: 2024-06-28-10-02-58 +.. gh-issue: 121115 +.. nonce: EeSLfc +.. section: Core and Builtins + +:c:func:`PyLong_AsNativeBytes` no longer uses :meth:`~object.__index__` +methods by default. The ``Py_ASNATIVEBYTES_ALLOW_INDEX`` flag has been added +to allow it. + +.. + +.. date: 2024-06-26-14-09-31 +.. gh-issue: 120838 +.. nonce: nFeTL9 +.. section: Core and Builtins + +:c:func:`Py_Finalize()` and :c:func:`Py_FinalizeEx()` now always run with +the main interpreter active. + +.. + +.. date: 2024-06-26-13-42-36 +.. gh-issue: 113433 +.. nonce: xKAtLB +.. section: Core and Builtins + +Subinterpreters now get cleaned up automatically during runtime +finalization. + +.. + +.. date: 2024-06-25-16-26-44 +.. gh-issue: 119726 +.. nonce: WqvHxB +.. section: Core and Builtins + +Improve the speed and memory use of C function calls from JIT code on +AArch64. Patch by Diego Russo + +.. + +.. date: 2024-06-24-08-39-23 +.. gh-issue: 116017 +.. nonce: -Bw2UY +.. section: Core and Builtins + +Simplify the warmup mechanism used for "side exits" in JIT code, resulting +in slightly better performance and slightly lower memory usage for most +platforms. + +.. + +.. date: 2024-06-19-21-34-21 +.. gh-issue: 98442 +.. nonce: cqhjkN +.. section: Core and Builtins + +Fix too wide source locations of the cleanup instructions of a with +statement. + +.. + +.. date: 2024-06-19-19-54-35 +.. gh-issue: 120754 +.. nonce: uF29sj +.. section: Core and Builtins + +Reduce the number of system calls invoked when reading a whole file (ex. +``open('a.txt').read()``). For a sample program that reads the contents of +the 400+ ``.rst`` files in the cpython repository ``Doc`` folder, there is +an over 10% reduction in system call count. + +.. + +.. date: 2024-06-19-11-10-50 +.. gh-issue: 119462 +.. nonce: DpcqSe +.. section: Core and Builtins + +Make sure that invariants of type versioning are maintained: * Superclasses +always have their version number assigned before subclasses * The version +tag is always zero if the tag is not valid. * The version tag is always +non-if the tag is valid. + +.. + +.. date: 2024-06-19-01-58-54 +.. gh-issue: 120437 +.. nonce: nCkIoI +.. section: Core and Builtins + +Fix ``_CHECK_STACK_SPACE`` optimization problems introduced in :gh:`118322`. + +.. + +.. date: 2024-06-18-22-41-05 +.. gh-issue: 120722 +.. nonce: rS7tkE +.. section: Core and Builtins + +Correctly set the bytecode position on return instructions within lambdas. +Patch by Jelle Zijlstra. + +.. + +.. date: 2024-06-18-21-34-30 +.. gh-issue: 120367 +.. nonce: zDwffP +.. section: Core and Builtins + +Fix bug where compiler creates a redundant jump during pseudo-op +replacement. Can only happen with a synthetic AST that has a try on the same +line as the instruction following the exception handler. + +.. + +.. date: 2024-06-17-12-20-20 +.. gh-issue: 120507 +.. nonce: 94lz2J +.. section: Core and Builtins + +Remove the ``BEFORE_WITH`` and ``BEFORE_ASYNC_WITH`` instructions. Add the +new :opcode:`LOAD_SPECIAL` instruction. Generate code for ``with`` and +``async with`` statements using the new instruction. + +.. + +.. date: 2024-06-14-22-02-25 +.. gh-issue: 113993 +.. nonce: MiA0vX +.. section: Core and Builtins + +Strings interned with :func:`sys.intern` are again garbage-collected when no +longer used, as per the documentation. Strings interned with the C function +:c:func:`PyUnicode_InternInPlace` are still immortal. Internals of the +string interning mechanism have been changed. This may affect performance +and identities of :class:`str` objects. + +.. + +.. date: 2024-06-14-07-52-00 +.. gh-issue: 120485 +.. nonce: yy4K4b +.. section: Core and Builtins + +Add an override of ``allow_reuse_port`` on classes subclassing +``socketserver.TCPServer`` where ``allow_reuse_address`` is also overridden. + +.. + +.. date: 2024-06-13-12-17-52 +.. gh-issue: 120384 +.. nonce: w1UBGl +.. section: Core and Builtins + +Fix an array out of bounds crash in ``list_ass_subscript``, which could be +invoked via some specifically tailored input: including concurrent +modification of a list object, where one thread assigns a slice and another +clears it. + +.. + +.. date: 2024-06-12-18-50-29 +.. gh-issue: 120367 +.. nonce: LmXx2y +.. section: Core and Builtins + +Fix crash in compiler on code with redundant NOPs and JUMPs which show up +after exception handlers are moved to the end of the code. + +.. + +.. date: 2024-06-12-18-23-15 +.. gh-issue: 120380 +.. nonce: edtqjq +.. section: Core and Builtins + +Fix Python implementation of :class:`pickle.Pickler` for :class:`bytes` and +:class:`bytearray` objects when using protocol version 5. Patch by Bénédikt +Tran. + +.. + +.. date: 2024-06-12-13-47-25 +.. gh-issue: 120397 +.. nonce: n-I_cc +.. section: Core and Builtins + +Improve the throughput by up to two times for the :meth:`str.count`, +:meth:`bytes.count` and :meth:`bytearray.count` methods for counting single +characters. + +.. + +.. date: 2024-06-11-17-56-12 +.. gh-issue: 120221 +.. nonce: si9hM9 +.. section: Core and Builtins + +Deliver real signals on Ctrl-C and Ctrl-Z in the new REPL. Patch by Pablo +Galindo + +.. + +.. date: 2024-06-11-12-47-54 +.. gh-issue: 120346 +.. nonce: hhn_6X +.. section: Core and Builtins + +Respect :envvar:`PYTHON_BASIC_REPL` when running in interactive inspect mode +(``python -i``). Patch by Pablo Galindo + +.. + +.. date: 2024-06-10-22-30-26 +.. gh-issue: 93691 +.. nonce: 68WOTS +.. section: Core and Builtins + +Fix source locations of instructions generated for the iterator of a for +statement. + +.. + +.. date: 2024-06-10-15-07-16 +.. gh-issue: 120198 +.. nonce: WW_pjO +.. section: Core and Builtins + +Fix a crash when multiple threads read and write to the same ``__class__`` +of an object concurrently. + +.. + +.. date: 2024-06-10-10-42-48 +.. gh-issue: 120298 +.. nonce: napREA +.. section: Core and Builtins + +Fix use-after free in ``list_richcompare_impl`` which can be invoked via +some specifically tailored evil input. + +.. + +.. date: 2024-06-09-19-13-38 +.. gh-issue: 119666 +.. nonce: S0G4rZ +.. section: Core and Builtins + +Fix a compiler crash in the case where two comprehensions in class scope +both reference ``__class__``. + +.. + +.. date: 2024-06-07-22-54-15 +.. gh-issue: 119726 +.. nonce: D9EE-o +.. section: Core and Builtins + +JIT: Re-use trampolines on AArch64 when creating stencils. Patch by Diego +Russo + +.. + +.. date: 2024-06-07-16-09-04 +.. gh-issue: 120225 +.. nonce: kuYf9t +.. section: Core and Builtins + +Fix crash in compiler on empty block at end of exception handler. + +.. + +.. date: 2024-06-05-18-29-18 +.. gh-issue: 93691 +.. nonce: 6OautB +.. section: Core and Builtins + +Fix source locations of instructions generated for with statements. + +.. + +.. date: 2024-06-05-10-32-44 +.. gh-issue: 120097 +.. nonce: 9S2klk +.. section: Core and Builtins + +``FrameLocalsProxy`` now subclasses ``collections.abc.Mapping`` and can be +matched as a mapping in ``match`` statements + +.. + +.. date: 2024-06-05-08-39-40 +.. gh-issue: 120080 +.. nonce: DJFK11 +.. section: Core and Builtins + +Direct call to the :meth:`!int.__round__` now accepts ``None`` as a valid +argument. + +.. + +.. date: 2024-06-03-13-48-44 +.. gh-issue: 119933 +.. nonce: Kc0HG5 +.. section: Core and Builtins + +Improve :exc:`SyntaxError` messages for invalid expressions in a type +parameters bound, a type parameter constraint tuple or a default type +parameter. Patch by Bénédikt Tran. + +.. + +.. date: 2024-06-03-13-25-04 +.. gh-issue: 119724 +.. nonce: EH1dkA +.. section: Core and Builtins + +Reverted improvements to error messages for ``elif``/``else`` statements not +matching any valid statements, which made in hard to locate the syntax +errors inside those ``elif``/``else`` blocks. + +.. + +.. date: 2024-06-02-06-12-35 +.. gh-issue: 119879 +.. nonce: Jit951 +.. section: Core and Builtins + +String search is now slightly faster for certain cases. It now utilizes last +character gap (good suffix rule) for two-way periodic needles. + +.. + +.. date: 2024-05-31-12-06-11 +.. gh-issue: 119842 +.. nonce: tCGVsv +.. section: Core and Builtins + +Honor :c:func:`PyOS_InputHook` in the new REPL. Patch by Pablo Galindo + +.. + +.. date: 2024-05-31-08-23-41 +.. gh-issue: 119180 +.. nonce: KL4VxZ +.. section: Core and Builtins + +:func:`classmethod` and :func:`staticmethod` now wrap the +:attr:`~object.__annotations__` and :attr:`~object.__annotate__` attributes +of their underlying callable lazily. See :pep:`649`. Patch by Jelle +Zijlstra. + +.. + +.. date: 2024-05-30-23-01-00 +.. gh-issue: 119821 +.. nonce: jPGfvt +.. section: Core and Builtins + +Fix execution of :ref:`annotation scopes ` within classes +when ``globals`` is set to a non-dict. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-05-30-04-11-36 +.. gh-issue: 118934 +.. nonce: fbDqve +.. section: Core and Builtins + +Make ``PyEval_GetLocals`` return borrowed reference + +.. + +.. date: 2024-05-29-18-53-43 +.. gh-issue: 119740 +.. nonce: zP2JNM +.. section: Core and Builtins + +Remove the previously-deprecated delegation of :func:`int` to +:meth:`~object.__trunc__`. + +.. + +.. date: 2024-05-28-22-49-56 +.. gh-issue: 119689 +.. nonce: VwLFD5 +.. section: Core and Builtins + +Generate stack effect metadata for pseudo instructions from bytecodes.c. + +.. + +.. date: 2024-05-27-19-13-49 +.. gh-issue: 109218 +.. nonce: -sdDg0 +.. section: Core and Builtins + +:func:`complex` accepts now a string only as a positional argument. Passing +a complex number as the "real" or "imag" argument is deprecated; it should +only be passed as a single positional argument. + +.. + +.. date: 2024-05-25-16-45-27 +.. gh-issue: 119548 +.. nonce: pqF9Y6 +.. section: Core and Builtins + +Add a ``clear`` command to the REPL. Patch by Pablo Galindo + +.. + +.. date: 2024-05-25-13-51-48 +.. gh-issue: 111999 +.. nonce: L0q1gh +.. section: Core and Builtins + +Fix the signature of :meth:`str.format_map`. + +.. + +.. date: 2024-05-25-12-52-25 +.. gh-issue: 119560 +.. nonce: wSlm8q +.. section: Core and Builtins + +An invalid assert in beta 1 has been removed. The assert would fail if +``PyState_FindModule()`` was used in an extension module's init function +before the module def had been initialized. + +.. + +.. date: 2024-05-24-21-16-52 +.. gh-issue: 119369 +.. nonce: qBThho +.. section: Core and Builtins + +Fix deadlock during thread deletion in free-threaded build, which could +occur when the GIL was enabled at runtime. + +.. + +.. date: 2024-05-24-21-04-00 +.. gh-issue: 119525 +.. nonce: zLFLf1 +.. section: Core and Builtins + +Fix deadlock involving ``_PyType_Lookup()`` cache in the free-threaded build +when the GIL is dynamically enabled at runtime. + +.. + +.. date: 2024-05-23-20-17-37 +.. gh-issue: 119258 +.. nonce: wZFIpt +.. section: Core and Builtins + +Eliminate type version guards in the tier two interpreter. + +Note that setting the ``tp_version_tag`` manually (which has never been +supported) may result in crashes. + +.. + +.. date: 2024-05-23-06-34-45 +.. gh-issue: 119311 +.. nonce: 2DBwKR +.. section: Core and Builtins + +Fix bug where names are unexpectedly mangled in the bases of generic +classes. + +.. + +.. date: 2024-05-23-06-34-14 +.. gh-issue: 119395 +.. nonce: z-Hsqb +.. section: Core and Builtins + +Fix bug where names appearing after a generic class are mangled as if they +are in the generic class. + +.. + +.. date: 2024-05-22-12-49-03 +.. gh-issue: 119372 +.. nonce: PXig1R +.. section: Core and Builtins + +Correct invalid corner cases in complex division (resulted in ``(nan+nanj)`` +output), e.g. ``1/complex('(inf+infj)')``. Patch by Sergey B Kirpichev. + +.. + +.. date: 2024-05-22-06-22-47 +.. gh-issue: 119180 +.. nonce: vZMiXm +.. section: Core and Builtins + +Evaluation of annotations is now deferred. See :pep:`649` for details. + +.. + +.. date: 2024-05-21-12-17-02 +.. gh-issue: 119180 +.. nonce: UNDUb9 +.. section: Core and Builtins + +Replace :opcode:`!LOAD_ASSERTION_ERROR` opcode with +:opcode:`LOAD_COMMON_CONSTANT` and add support for +:exc:`NotImplementedError`. + +.. + +.. date: 2024-05-21-11-27-14 +.. gh-issue: 119213 +.. nonce: nxjxrt +.. section: Core and Builtins + +Non-builtin modules built with argument clinic were crashing if used in a +subinterpreter before the main interpreter. The objects that were causing +the problem by leaking between interpreters carelessly have been fixed. + +.. + +.. date: 2024-05-21-09-46-51 +.. gh-issue: 119011 +.. nonce: WOe3bu +.. section: Core and Builtins + +Fixes ``type.__type_params__`` to return an empty tuple instead of a +descriptor. + +.. + +.. date: 2024-05-20-14-57-39 +.. gh-issue: 118692 +.. nonce: Qadm7F +.. section: Core and Builtins + +Avoid creating unnecessary :exc:`StopIteration` instances for monitoring. + +.. + +.. date: 2024-05-20-10-10-51 +.. gh-issue: 119180 +.. nonce: 35xqpu +.. section: Core and Builtins + +Add an ``__annotate__`` attribute to functions, classes, and modules as part +of :pep:`649`. Patch by Jelle Zijlstra. + +.. + +.. date: 2024-05-16-23-02-03 +.. gh-issue: 119049 +.. nonce: qpd_S- +.. section: Core and Builtins + +Fix displaying the source line for warnings created by the C API if the +:mod:`warnings` module had not yet been imported. + +.. + +.. date: 2024-05-15-12-15-58 +.. gh-issue: 119057 +.. nonce: P3G9G2 +.. section: Core and Builtins + +Improve :exc:`ZeroDivisionError` error message. Now, all error messages are +harmonized: all ``/``, ``//``, and ``%`` operations just use "division by +zero" message. And ``0 ** -1`` operation uses "zero to a negative power". + +.. + +.. date: 2024-05-11-21-44-17 +.. gh-issue: 118844 +.. nonce: q2H_km +.. section: Core and Builtins + +Fix build failures when configuring with both ``--disable-gil`` and +``--enable-experimental-jit``. + +.. + +.. date: 2024-05-10-19-54-18 +.. gh-issue: 118921 +.. nonce: O4ztZG +.. section: Core and Builtins + +Add ``copy()`` method for ``FrameLocalsProxy`` which returns a snapshot +``dict`` for local variables. + +.. + +.. date: 2024-05-09-19-47-12 +.. gh-issue: 117657 +.. nonce: Vn0Yey +.. section: Core and Builtins + +Fix data races on the field that stores a pointer to the interpreter's main +thread that occur in free-threaded builds. + +.. + +.. date: 2024-05-09-02-37-25 +.. gh-issue: 118750 +.. nonce: 7aLfT- +.. section: Core and Builtins + +If the C version of the ``decimal`` module is available, ``int(str)`` now +uses it to supply an asymptotically much faster conversion. However, this +only applies if the string contains over about 2 million digits. + +.. + +.. date: 2024-05-08-09-44-15 +.. gh-issue: 118767 +.. nonce: iFF5F5 +.. section: Core and Builtins + +Using :data:`NotImplemented` in a boolean context now raises +:exc:`TypeError`. Contributed by Jelle Zijlstra. + +.. + +.. date: 2024-05-07-16-57-56 +.. gh-issue: 118561 +.. nonce: wNMKVd +.. section: Core and Builtins + +Fix race condition in free-threaded build where :meth:`!list.extend` could +expose uninitialised memory to concurrent readers. + +.. + +.. date: 2024-05-01-05-09-16 +.. gh-issue: 117139 +.. nonce: t41w_D +.. section: Core and Builtins + +Convert the Python evaluation stack to use internal stack references. The +purpose is to support tagged pointers. In :pep:`703`, this will allow for +its form of deferred reference counting. For both the default and +free-threaded builds, this sets up the infrastructure for unboxed integers +in the future. + +.. + +.. date: 2024-04-27-18-36-46 +.. gh-issue: 115801 +.. nonce: SVeHSy +.. section: Core and Builtins + +Raise ``TypeError`` when passing a string to :func:`difflib.unified_diff` +and :func:`difflib.context_diff`. + +.. + +.. date: 2024-04-08-13-49-02 +.. gh-issue: 117558 +.. nonce: 9lSEpR +.. section: Core and Builtins + +Improve error messages when a string, bytes or bytearray object of length 1 +is expected. + +.. + +.. date: 2024-03-25-15-07-01 +.. gh-issue: 117195 +.. nonce: OWakgD +.. section: Core and Builtins + +Avoid assertion failure for debug builds when calling +``object.__sizeof__(1)`` + +.. + +.. date: 2024-03-19-22-21-22 +.. gh-issue: 116022 +.. nonce: iyHENN +.. section: Core and Builtins + +Improve the :meth:`~object.__repr__` output of :class:`~ast.AST` nodes. + +.. + +.. date: 2024-01-15-21-51-26 +.. gh-issue: 114091 +.. nonce: VOtSJl +.. section: Core and Builtins + +Changed the error message for awaiting something that can't be awaited from +"object can't be used in an await expression" to "'' object +can't be awaited". + +.. + +.. date: 2024-01-15-18-11-48 +.. gh-issue: 113190 +.. nonce: OwQX64 +.. section: Core and Builtins + +:c:func:`Py_Finalize` now deletes all interned strings. + +.. + +.. date: 2023-10-14-23-05-40 +.. gh-issue: 84978 +.. nonce: Z0t6dg +.. section: Core and Builtins + +Add class methods :meth:`float.from_number` and :meth:`complex.from_number`. + +.. + +.. date: 2022-07-22-15-56-35 +.. gh-issue: 95144 +.. nonce: FZYWX- +.. section: Core and Builtins + +Improve the error message from ``a in b`` when ``b`` is not a container to +mention the term "container". + +.. + +.. bpo: 24766 +.. date: 2018-10-09-15-14-53 +.. nonce: c_C1Wc +.. section: Core and Builtins + +Fix handling of ``doc`` argument to subclasses of ``property``. + +.. + +.. date: 2024-10-03-14-06-08 +.. gh-issue: 123961 +.. nonce: uwJQTY +.. section: C API + +Convert the :ref:`curses.window ` static type exposed +by the :c:macro:`!PyCursesWindow_Type` macro in ``Include/py_curses.h`` to a +:ref:`heap type `. Patch by Bénédikt Tran. + +.. + +.. date: 2024-09-25-11-44-02 +.. gh-issue: 124502 +.. nonce: qWuDjT +.. section: C API + +Add :c:func:`PyUnicode_Equal` function to the limited C API: test if two +strings are equal. Patch by Victor Stinner. + +.. + +.. date: 2024-09-24-20-34-21 +.. gh-issue: 124296 +.. nonce: S4QoS1 +.. section: C API + +:c:type:`PyDictObject` no longer maintains a private version tag field +``ma_version_tag`` per :pep:`699`. This field was originally added in +Python 3.6 (:pep:`509`) and deprecated in Python 3.12. + +.. + +.. date: 2024-09-18-18-40-30 +.. gh-issue: 124160 +.. nonce: Zy-VKi +.. section: C API + +Fix crash when importing modules containing state and single-phase +initialization in a subinterpreter. + +.. + +.. date: 2024-09-17-05-23-35 +.. gh-issue: 124153 +.. nonce: L8TWmx +.. section: C API + +Add :c:func:`PyType_GetBaseByToken` and :c:data:`Py_tp_token` slot for +easier type checking, related to :pep:`489` and :pep:`630`. + +.. + +.. date: 2024-09-16-16-21-39 +.. gh-issue: 124127 +.. nonce: LB8DBU +.. section: C API + +In the limited C API 3.14 and newer, :c:func:`Py_REFCNT` is now implemented +as an opaque function call to hide implementation details. Patch by Victor +Stinner. + +.. + +.. date: 2024-09-12-16-16-24 +.. gh-issue: 123880 +.. nonce: 2-8vcj +.. section: C API + +Fixed a bug that prevented circular imports of extension modules that use +single-phase initialization. + +.. + +.. date: 2024-09-10-16-54-27 +.. gh-issue: 123909 +.. nonce: CTGxDR +.. section: C API + +:c:func:`PyType_FromSpec`, :c:func:`PyType_FromSpecWithBases` and +:c:func:`PyType_FromModuleAndSpec` will now fail if the metaclass of the new +type has custom :c:member:`~PyTypeObject.tp_new`. + +.. + +.. date: 2024-08-30-14-02-17 +.. gh-issue: 107954 +.. nonce: TPvj4u +.. section: C API + +Add functions to configure the Python initialization (:pep:`741`): + +* :c:func:`PyInitConfig_Create` +* :c:func:`PyInitConfig_Free` +* :c:func:`PyInitConfig_GetError` +* :c:func:`PyInitConfig_GetExitCode` +* :c:func:`PyInitConfig_HasOption` +* :c:func:`PyInitConfig_GetInt` +* :c:func:`PyInitConfig_GetStr` +* :c:func:`PyInitConfig_GetStrList` +* :c:func:`PyInitConfig_FreeStrList` +* :c:func:`PyInitConfig_SetInt` +* :c:func:`PyInitConfig_SetStr` +* :c:func:`PyInitConfig_SetStrList` +* :c:func:`PyInitConfig_AddModule` +* :c:func:`Py_InitializeFromInitConfig` + +Patch by Victor Stinner. + +.. + +.. date: 2024-08-29-15-55-55 +.. gh-issue: 107954 +.. nonce: pr2O50 +.. section: C API + +Add functions to get and set the current runtime Python configuration: + +* :c:func:`PyConfig_Get` +* :c:func:`PyConfig_GetInt` +* :c:func:`PyConfig_Set` +* :c:func:`PyConfig_Names` + +Patch by Victor Stinner. + +.. + +.. date: 2024-08-29-15-05-19 +.. gh-issue: 123465 +.. nonce: eqwNWq +.. section: C API + +:c:macro:`Py_RELATIVE_OFFSET` is now allowed in :c:type:`PyMemberDef` for +the special offset member ``"__vectorcalloffset__"``, as well as the +discouraged special offset members ``"__dictoffset__"`` and +``"__weaklistoffset__"`` + +.. + +.. date: 2024-08-26-13-01-20 +.. gh-issue: 100554 +.. nonce: 0ku85o +.. section: C API + +Added a slot ``Py_tp_vectorcall`` to set +:c:member:`~PyTypeObject.tp_vectorcall` via the :c:func:`PyType_FromSpec` +function family. Limited API extensions can use this feature to provide more +efficient vector call-based implementation of ``__new__`` and ``__init__``. + +.. + +.. date: 2024-08-09-13-12-20 +.. gh-issue: 122854 +.. nonce: -1OgvU +.. section: C API + +Add :c:func:`Py_HashBuffer` to compute and return the hash value of a +buffer. Patch by Antoine Pitrou and Victor Stinner. + +.. + +.. date: 2024-08-06-14-23-11 +.. gh-issue: 122728 +.. nonce: l-fQ-v +.. section: C API + +Fix :c:func:`PyEval_GetLocals` to avoid :exc:`SystemError` ("bad argument to +internal function"). Patch by Victor Stinner. + +.. + +.. date: 2024-07-30-23-48-26 +.. gh-issue: 116622 +.. nonce: yTTtil +.. section: C API + +Make :any:`PyObject_Print` work around a bug in Android and OpenBSD which +prevented it from throwing an exception when trying to write to a read-only +stream. + +.. + +.. date: 2024-07-27-00-28-35 +.. gh-issue: 105201 +.. nonce: 0-xUWq +.. section: C API + +Add :c:func:`PyIter_NextItem` to replace :c:func:`PyIter_Next`, which has an +ambiguous return value. Patch by Irit Katriel and Erlend Aasland. + +.. + +.. date: 2024-07-21-17-40-07 +.. gh-issue: 121489 +.. nonce: SUMFCr +.. section: C API + +Export private :c:func:`!_PyBytes_Join` again. + +.. + +.. date: 2024-07-12-13-40-59 +.. gh-issue: 121645 +.. nonce: 96QvD3 +.. section: C API + +Add :c:func:`PyBytes_Join(sep, iterable) ` function, similar +to ``sep.join(iterable)`` in Python. Patch by Victor Stinner. + +.. + +.. date: 2024-07-09-15-55-20 +.. gh-issue: 89364 +.. nonce: yYYroI +.. section: C API + +Export the :c:func:`PySignal_SetWakeupFd` function. Previously, the function +was documented but it couldn't be used in 3rd party code. Patch by Victor +Stinner. + +.. + +.. date: 2024-07-04-15-41-10 +.. gh-issue: 113993 +.. nonce: cLSiWV +.. section: C API + +:c:func:`PyUnicode_InternInPlace` no longer prevents its argument from being +garbage collected. + +Several functions that take ``char *`` are now documented as possibly +preventing string objects from being garbage collected; refer to their +documentation for details: :c:func:`PyUnicode_InternFromString`, +:c:func:`PyDict_SetItemString`, :c:func:`PyObject_SetAttrString`, +:c:func:`PyObject_DelAttrString`, :c:func:`PyUnicode_InternFromString`, and +``PyModule_Add*`` convenience functions. + +.. + +.. date: 2024-07-04-13-23-27 +.. gh-issue: 113601 +.. nonce: K3RLqp +.. section: C API + +Removed debug build assertions related to interning strings, which were +falsely triggered by stable ABI extensions. + +.. + +.. date: 2024-07-02-11-03-40 +.. gh-issue: 112136 +.. nonce: f3fiY8 +.. section: C API + +Restore the private ``_PyArg_Parser`` structure and the private +``_PyArg_ParseTupleAndKeywordsFast()`` function, previously removed in +Python 3.13 alpha 1. Patch by Victor Stinner. + +.. + +.. date: 2024-06-26-11-29-01 +.. gh-issue: 120642 +.. nonce: H7P9qK +.. section: C API + +Remove the private ``_Py_CODEUNIT`` type from the public C API. The internal +``pycore_code.h`` header should now be used to get this internal type. Patch +by Victor Stinner. + +.. + +.. date: 2024-06-21-16-41-21 +.. gh-issue: 120858 +.. nonce: Z5_-Mn +.. section: C API + +:c:func:`PyDict_Next` no longer locks the dictionary in the free-threaded +build. The locking needs to be done by the caller around the entire +iteration loop. + +.. + +.. date: 2024-06-19-21-27-42 +.. gh-issue: 120642 +.. nonce: UlKClN +.. section: C API + +Remove the following unstable functions: + +* ``PyUnstable_Replace_Executor()`` +* ``PyUnstable_SetOptimizer()`` +* ``PyUnstable_GetOptimizer()`` +* ``PyUnstable_GetExecutor()`` +* ``PyUnstable_Optimizer_NewCounter()`` +* ``PyUnstable_Optimizer_NewUOpOptimizer()`` + +Patch by Victor Stinner. + +.. + +.. date: 2024-06-19-17-27-22 +.. gh-issue: 120389 +.. nonce: GSZeHF +.. section: C API + +Add new functions to convert C ```` numbers from/to Python +:class:`int`: + +* :c:func:`PyLong_FromInt32` +* :c:func:`PyLong_FromUInt32` +* :c:func:`PyLong_FromInt64` +* :c:func:`PyLong_FromUInt64` +* :c:func:`PyLong_AsInt32` +* :c:func:`PyLong_AsUInt32` +* :c:func:`PyLong_AsInt64` +* :c:func:`PyLong_AsUInt64` + +Patch by Victor Stinner. + +.. + +.. date: 2024-06-16-22-58-47 +.. gh-issue: 120600 +.. nonce: TJdf0w +.. section: C API + +In the limited C API 3.14 and newer, :c:func:`Py_TYPE` is now implemented as +an opaque function call to hide implementation details. Patch by Victor +Stinner. + +.. + +.. date: 2024-06-11-21-38-32 +.. gh-issue: 70278 +.. nonce: WDE4zM +.. section: C API + +:c:func:`PyUnicode_FromFormat` no longer produces the ending ``\ufffd`` +character for truncated C string when use precision with ``%s`` and ``%V``. +It now truncates the string before the start of truncated multibyte +sequences. + +.. + +.. date: 2024-06-08-08-33-40 +.. gh-issue: 119771 +.. nonce: Oip2dL +.. section: C API + +Set :data:`errno` in :c:func:`_Py_c_pow` on overflows. Patch by Sergey B +Kirpichev. + +.. + +.. date: 2024-06-07-22-12-30 +.. gh-issue: 119182 +.. nonce: yt8Ar7 +.. section: C API + +Add a new :c:type:`PyUnicodeWriter` API to create a Python :class:`str` +object: + +* :c:func:`PyUnicodeWriter_Create`. +* :c:func:`PyUnicodeWriter_Discard`. +* :c:func:`PyUnicodeWriter_Finish`. +* :c:func:`PyUnicodeWriter_WriteChar`. +* :c:func:`PyUnicodeWriter_WriteUTF8`. +* :c:func:`PyUnicodeWriter_WriteUCS4`. +* :c:func:`PyUnicodeWriter_WriteWideChar`. +* :c:func:`PyUnicodeWriter_WriteStr`. +* :c:func:`PyUnicodeWriter_WriteRepr`. +* :c:func:`PyUnicodeWriter_WriteSubstring`. +* :c:func:`PyUnicodeWriter_Format`. +* :c:func:`PyUnicodeWriter_DecodeUTF8Stateful`. + +Patch by Victor Stinner. + +.. + +.. date: 2024-06-04-10-58-20 +.. gh-issue: 119613 +.. nonce: qOr9GF +.. section: C API + +Soft deprecate the :c:macro:`!Py_MEMCPY` macro: use directly ``memcpy()`` +instead. Patch by Victor Stinner. + +.. + +.. date: 2024-05-30-12-51-21 +.. gh-issue: 119775 +.. nonce: CBq9IG +.. section: C API + +Creating :c:data:`immutable types ` with mutable +bases was deprecated since 3.12 and now raises a :exc:`TypeError`. + +.. + +.. date: 2024-05-29-21-05-59 +.. gh-issue: 119585 +.. nonce: Sn7JL3 +.. section: C API + +Fix crash when a thread state that was created by +:c:func:`PyGILState_Ensure` calls a destructor that during +:c:func:`PyThreadState_Clear` that calls back into +:c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release`. This might +occur when in the free-threaded build or when using thread-local variables +whose destructors call :c:func:`PyGILState_Ensure`. + +.. + +.. date: 2024-05-29-09-21-37 +.. gh-issue: 119613 +.. nonce: J2xfrC +.. section: C API + +Macros ``Py_IS_NAN``, ``Py_IS_INFINITY`` and ``Py_IS_FINITE`` are +:term:`soft deprecated`. + +.. + +.. date: 2024-05-22-17-50-48 +.. gh-issue: 119336 +.. nonce: ff3qnS +.. section: C API + +Restore the removed ``_PyLong_NumBits()`` function. It is used by the +pywin32 project. Patch by Ethan Smith + +.. + +.. date: 2024-05-21-19-41-41 +.. gh-issue: 119344 +.. nonce: QKvzQb +.. section: C API + +The critical section API is now public as part of the non-limited C API. + +.. + +.. date: 2024-05-21-18-28-44 +.. gh-issue: 119333 +.. nonce: OTsYVX +.. section: C API + +Add :c:func:`PyContext_AddWatcher` and :c:func:`PyContext_ClearWatcher` APIs +to register callbacks to receive notification on enter and exit of context +objects. + +.. + +.. date: 2024-05-21-11-35-11 +.. gh-issue: 119247 +.. nonce: U6n6mh +.. section: C API + +Added ``Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST`` and +``Py_END_CRITICAL_SECTION_SEQUENCE_FAST`` macros to make it possible to use +PySequence_Fast APIs safely when free-threaded, and update str.join to work +without the GIL using them. + +.. + +.. date: 2024-05-20-10-35-22 +.. gh-issue: 111389 +.. nonce: a6axBk +.. section: C API + +Add :c:macro:`PyHASH_MULTIPLIER` constant: prime multiplier used in string +and various other hashes. Patch by Victor Stinner. + +.. + +.. date: 2024-05-10-15-43-14 +.. gh-issue: 118771 +.. nonce: 5KVglT +.. section: C API + +Several C declarations with names that didn't start with the ``Py`` or +``_Py`` prefixes, which were added by mistake in 3.13 alpha and beta +releases, were moved to internal headers. + +.. + +.. date: 2024-05-08-23-14-06 +.. gh-issue: 116984 +.. nonce: 5sgcDo +.. section: C API + +Make mimalloc includes relative to the current file to avoid embedders or +extensions needing to include ``Internal/mimalloc`` if they are already +including internal CPython headers. + +.. + +.. date: 2024-05-08-21-57-50 +.. gh-issue: 118789 +.. nonce: Ni4UQx +.. section: C API + +Add :c:func:`PyUnstable_Object_ClearWeakRefsNoCallbacks`, which clears +weakrefs without calling their callbacks. + +.. + +.. date: 2024-05-08-20-13-00 +.. gh-issue: 118789 +.. nonce: m88uUa +.. section: C API + +Restore ``_PyWeakref_ClearRef`` that was previously removed in Python 3.13 +alpha 1. + +.. + +.. date: 2024-04-10-16-48-04 +.. gh-issue: 117511 +.. nonce: RZtBRK +.. section: C API + +Make the :c:type:`PyMutex` public in the non-limited C API. + +.. + +.. date: 2024-03-10-14-55-51 +.. gh-issue: 116560 +.. nonce: x2mZaO +.. section: C API + +Add :c:func:`PyLong_GetSign` function. Patch by Sergey B Kirpichev. + +.. + +.. date: 2022-10-01-09-56-27 +.. gh-issue: 97588 +.. nonce: Gvg54o +.. section: C API + +Fix creating bitfields in :mod:`ctypes` structures and unions. Fields no +longer overlap. + +.. + +.. date: 2022-08-05-19-41-20 +.. gh-issue: 87135 +.. nonce: SCNBYj +.. section: C API + +Attempting to acquire the GIL after runtime finalization has begun in a +different thread now causes the thread to hang rather than terminate, which +avoids potential crashes or memory corruption caused by attempting to +terminate a thread that is running code not specifically designed to support +termination. In most cases this hanging is harmless since the process will +soon exit anyway. + +The ``PyThread_exit_thread`` function is now deprecated. Its behavior is +inconsistent across platforms, and it can only be used safely in the +unlikely case that every function in the entire call stack has been designed +to support the platform-dependent termination mechanism. It is recommended +that users of this function change their design to not require thread +termination. In the unlikely case that thread termination is needed and can +be done safely, users may migrate to calling platform-specific APIs such as +``pthread_exit`` (POSIX) or ``_endthreadex`` (Windows) directly. + +.. + +.. bpo: 34008 +.. date: 2018-06-30-21-48-16 +.. nonce: 2Wjtm0 +.. section: C API + +Added ``Py_IsInitialized`` to the list of APIs that are safe to call before +the interpreter is initialized, and updated the embedding tests to cover it. + +.. + +.. date: 2024-10-13-21-11-30 +.. gh-issue: 125269 +.. nonce: BC-fdo +.. section: Build + +Fix detection of whether ``-latomic`` is needed when cross-compiling CPython +using the configure script. + +.. + +.. date: 2024-09-23-11-27-25 +.. gh-issue: 123990 +.. nonce: d6HrYC +.. section: Build + +Remove ``WITH_FREELISTS`` macro and ``--without-freelists`` build +configuration + +.. + +.. date: 2024-09-16-09-42-05 +.. gh-issue: 124102 +.. nonce: Ow254j +.. section: Build + +Update internal documentation under PCbuild, so it now correctly states that +Windows requires VS2017 or later and Python 3.10 or later + +.. + +.. date: 2024-09-13-17-48-37 +.. gh-issue: 124043 +.. nonce: Bruxpq +.. section: Build + +Building using :option:`--with-trace-refs` is (temporarily) disallowed when +the GIL is disabled. + +.. + +.. date: 2024-09-04-12-01-43 +.. gh-issue: 123418 +.. nonce: ynzspB +.. section: Build + +Updated Android build to use OpenSSL 3.0.15. + +.. + +.. date: 2024-08-24-19-09-31 +.. gh-issue: 123297 +.. nonce: fdtXoe +.. section: Build + +Propagate the value of ``LDFLAGS`` to ``LDCXXSHARED`` in :mod:`sysconfig`. +Patch by Pablo Galindo + +.. + +.. date: 2024-08-14-19-17-34 +.. gh-issue: 121634 +.. nonce: eOMfHG +.. section: Build + +Allow for specifying the target compile triple for WASI. + +.. + +.. date: 2024-08-12-15-48-49 +.. gh-issue: 122578 +.. nonce: YJ3xEa +.. section: Build + +Use WASI SDK 24 for testing. + +.. + +.. date: 2024-08-07-00-20-18 +.. gh-issue: 116622 +.. nonce: U9cxHM +.. section: Build + +Rename build variable ``MODULE_LDFLAGS`` back to ``LIBPYTHON``, as it's used +by package build systems (e.g. Meson). + +.. + +.. date: 2024-08-02-12-59-15 +.. gh-issue: 118943 +.. nonce: vZQtET +.. section: Build + +Fix an issue where the experimental JIT could be built several times by the +``make regen-all`` target, leading to possible race conditions on heavily +parallelized builds. + +.. + +.. date: 2024-07-19-10-14-31 +.. gh-issue: 121996 +.. nonce: IEb2sz +.. section: Build + +Introduce ./configure --disable-safety and --enable-slower-safety options. +Patch by Donghee Na. + +.. + +.. date: 2024-07-18-07-53-07 +.. gh-issue: 120522 +.. nonce: dg3o5A +.. section: Build + +Added a :option:`--with-app-store-compliance` option to patch out known +issues with macOS/iOS App Store review processes. + +.. + +.. date: 2024-07-16-12-29-54 +.. gh-issue: 120371 +.. nonce: E7x858 +.. section: Build + +Support WASI SDK 22 by explicitly skipping functions that are just stubs in +wasi-libc. + +.. + +.. date: 2024-07-14-01-29-47 +.. gh-issue: 121731 +.. nonce: RMPGP3 +.. section: Build + +Fix mimalloc compile error on GNU/Hurd + +.. + +.. date: 2024-07-08-14-01-17 +.. gh-issue: 121487 +.. nonce: ekHmpR +.. section: Build + +Fix deprecation warning for ATOMIC_VAR_INIT in mimalloc. + +.. + +.. date: 2024-07-08-01-11-54 +.. gh-issue: 121467 +.. nonce: 3qWRQj +.. section: Build + +Fix a Makefile bug that prevented mimalloc header files from being +installed. + +.. + +.. date: 2024-07-02-20-16-09 +.. gh-issue: 121103 +.. nonce: TMef9j +.. section: Build + +On POSIX systems, excluding macOS framework installs, the lib directory for +the free-threaded build now includes a "t" suffix to avoid conflicts with a +co-located default build installation. + +.. + +.. date: 2024-07-02-12-42-25 +.. gh-issue: 120831 +.. nonce: i3eIjg +.. section: Build + +The default minimum iOS version was increased to 13.0. + +.. + +.. date: 2024-06-27-18-03-20 +.. gh-issue: 121082 +.. nonce: w3AfRx +.. section: Build + +Fix build failure when the developer use ``--enable-pystats`` arguments in +configuration command after #118450. + +.. + +.. date: 2024-06-21-09-24-03 +.. gh-issue: 120671 +.. nonce: Z8sBQB +.. section: Build + +Fix failing configure tests due to a missing space when appending to CFLAGS. + +.. + +.. date: 2024-06-19-21-05-15 +.. gh-issue: 120602 +.. nonce: UyDARz +.. section: Build + +Correctly handle LLVM installs with ``LLVM_VERSION_SUFFIX`` when building +with ``--enable-experimental-jit``. + +.. + +.. date: 2024-06-18-15-32-36 +.. gh-issue: 120688 +.. nonce: tjIPLD +.. section: Build + +On WASI in debug mode, Python is now built with compiler flag ``-O3`` +instead of ``-Og``, to support more recursive calls. Patch by Victor +Stinner. + +.. + +.. date: 2024-06-18-15-28-25 +.. gh-issue: 118943 +.. nonce: aie7nn +.. section: Build + +Fix a possible race condition affecting parallel builds configured with +``--enable-experimental-jit``, in which :exc:`FileNotFoundError` could be +caused by another process already moving ``jit_stencils.h.new`` to +``jit_stencils.h``. + +.. + +.. date: 2024-06-11-00-38-05 +.. gh-issue: 120326 +.. nonce: JHSDF1 +.. section: Build + +On Windows, fix build error when ``--disable-gil`` and +``--experimental-jit`` options are combined. + +.. + +.. date: 2024-06-09-15-54-22 +.. gh-issue: 120291 +.. nonce: IpfHzE +.. section: Build + +Make the ``python-config`` shell script compatible with non-bash shells. + +.. + +.. date: 2024-06-02-13-23-26 +.. gh-issue: 113565 +.. nonce: 8xBlId +.. section: Build + +Improve :mod:`curses` and :mod:`curses.panel` dependency checks in +:program:`configure`. + +.. + +.. date: 2024-05-29-17-40-50 +.. gh-issue: 119729 +.. nonce: k0xJ5U +.. section: Build + +On POSIX systems, the pkg-config (``.pc``) filenames now include the ABI +flags, which may include debug ("d") and free-threaded ("t"). For example: +* ``python-3.14.pc`` (default, non-debug build) * ``python-3.14d.pc`` +(default, debug build) * ``python-3.14t.pc`` (free-threaded build) + +.. + +.. date: 2024-05-22-13-18-02 +.. gh-issue: 119400 +.. nonce: WEt83v +.. section: Build + +``make_ssl_certs``, the script that prepares certificate data for the test +suite, now allows specifying expiration dates. + +.. + +.. date: 2024-05-19-22-54-55 +.. gh-issue: 115119 +.. nonce: DwMwev +.. section: Build + +Fall back to the bundled libmpdec if a system version cannot be found. + +.. + +.. date: 2024-05-17-19-53-27 +.. gh-issue: 119132 +.. nonce: wepPgM +.. section: Build + +Update :data:`sys.version` to identify whether the build is default build or +free-threading build. Patch By Donghee Na. + +.. + +.. date: 2024-05-13-15-57-58 +.. gh-issue: 118836 +.. nonce: 7yN1iB +.. section: Build + +Fix an ``AssertionError`` when building with ``--enable-experimental-jit`` +and the compiler emits a ``SHT_NOTE`` section. + +.. + +.. date: 2024-05-11-15-11-30 +.. gh-issue: 118943 +.. nonce: VI_MnY +.. section: Build + +Fix a possible race condition affecting parallel builds configured with +``--enable-experimental-jit``, in which compilation errors could be caused +by an incompletely-generated header file. diff --git a/Misc/NEWS.d/next/Build/2024-05-11-15-11-30.gh-issue-118943.VI_MnY.rst b/Misc/NEWS.d/next/Build/2024-05-11-15-11-30.gh-issue-118943.VI_MnY.rst deleted file mode 100644 index 4e886be034fb82..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-05-11-15-11-30.gh-issue-118943.VI_MnY.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a possible race condition affecting parallel builds configured with -``--enable-experimental-jit``, in which compilation errors could be caused -by an incompletely-generated header file. diff --git a/Misc/NEWS.d/next/Build/2024-05-13-15-57-58.gh-issue-118836.7yN1iB.rst b/Misc/NEWS.d/next/Build/2024-05-13-15-57-58.gh-issue-118836.7yN1iB.rst deleted file mode 100644 index 5212af7b32b940..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-05-13-15-57-58.gh-issue-118836.7yN1iB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an ``AssertionError`` when building with ``--enable-experimental-jit`` -and the compiler emits a ``SHT_NOTE`` section. diff --git a/Misc/NEWS.d/next/Build/2024-05-17-19-53-27.gh-issue-119132.wepPgM.rst b/Misc/NEWS.d/next/Build/2024-05-17-19-53-27.gh-issue-119132.wepPgM.rst deleted file mode 100644 index 44fe2a1a1f6725..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-05-17-19-53-27.gh-issue-119132.wepPgM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update :data:`sys.version` to identify whether the build is default build or -free-threading build. Patch By Donghee Na. diff --git a/Misc/NEWS.d/next/Build/2024-05-19-22-54-55.gh-issue-115119.DwMwev.rst b/Misc/NEWS.d/next/Build/2024-05-19-22-54-55.gh-issue-115119.DwMwev.rst deleted file mode 100644 index acaca9e0ebbdfb..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-05-19-22-54-55.gh-issue-115119.DwMwev.rst +++ /dev/null @@ -1 +0,0 @@ -Fall back to the bundled libmpdec if a system version cannot be found. diff --git a/Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst b/Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst deleted file mode 100644 index b4029f205797e4..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-05-22-13-18-02.gh-issue-119400.WEt83v.rst +++ /dev/null @@ -1,2 +0,0 @@ -``make_ssl_certs``, the script that prepares certificate data for the -test suite, now allows specifying expiration dates. diff --git a/Misc/NEWS.d/next/Build/2024-05-29-17-40-50.gh-issue-119729.k0xJ5U.rst b/Misc/NEWS.d/next/Build/2024-05-29-17-40-50.gh-issue-119729.k0xJ5U.rst deleted file mode 100644 index 7ac300ecf40326..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-05-29-17-40-50.gh-issue-119729.k0xJ5U.rst +++ /dev/null @@ -1,5 +0,0 @@ -On POSIX systems, the pkg-config (``.pc``) filenames now include the ABI -flags, which may include debug ("d") and free-threaded ("t"). For example: -* ``python-3.14.pc`` (default, non-debug build) -* ``python-3.14d.pc`` (default, debug build) -* ``python-3.14t.pc`` (free-threaded build) diff --git a/Misc/NEWS.d/next/Build/2024-06-02-13-23-26.gh-issue-113565.8xBlId.rst b/Misc/NEWS.d/next/Build/2024-06-02-13-23-26.gh-issue-113565.8xBlId.rst deleted file mode 100644 index e26509cd434110..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-02-13-23-26.gh-issue-113565.8xBlId.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve :mod:`curses` and :mod:`curses.panel` dependency checks in -:program:`configure`. diff --git a/Misc/NEWS.d/next/Build/2024-06-09-15-54-22.gh-issue-120291.IpfHzE.rst b/Misc/NEWS.d/next/Build/2024-06-09-15-54-22.gh-issue-120291.IpfHzE.rst deleted file mode 100644 index d0bb297b51dc6e..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-09-15-54-22.gh-issue-120291.IpfHzE.rst +++ /dev/null @@ -1 +0,0 @@ -Make the ``python-config`` shell script compatible with non-bash shells. diff --git a/Misc/NEWS.d/next/Build/2024-06-11-00-38-05.gh-issue-120326.JHSDF1.rst b/Misc/NEWS.d/next/Build/2024-06-11-00-38-05.gh-issue-120326.JHSDF1.rst deleted file mode 100644 index 25cbdf6ba50ab8..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-11-00-38-05.gh-issue-120326.JHSDF1.rst +++ /dev/null @@ -1,2 +0,0 @@ -On Windows, fix build error when ``--disable-gil`` and ``--experimental-jit`` -options are combined. diff --git a/Misc/NEWS.d/next/Build/2024-06-18-15-28-25.gh-issue-118943.aie7nn.rst b/Misc/NEWS.d/next/Build/2024-06-18-15-28-25.gh-issue-118943.aie7nn.rst deleted file mode 100644 index 997c990a96e476..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-18-15-28-25.gh-issue-118943.aie7nn.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a possible race condition affecting parallel builds configured with -``--enable-experimental-jit``, in which :exc:`FileNotFoundError` could be caused by -another process already moving ``jit_stencils.h.new`` to ``jit_stencils.h``. diff --git a/Misc/NEWS.d/next/Build/2024-06-18-15-32-36.gh-issue-120688.tjIPLD.rst b/Misc/NEWS.d/next/Build/2024-06-18-15-32-36.gh-issue-120688.tjIPLD.rst deleted file mode 100644 index 90f1f9138b6b58..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-18-15-32-36.gh-issue-120688.tjIPLD.rst +++ /dev/null @@ -1,3 +0,0 @@ -On WASI in debug mode, Python is now built with compiler flag ``-O3`` -instead of ``-Og``, to support more recursive calls. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Build/2024-06-19-21-05-15.gh-issue-120602.UyDARz.rst b/Misc/NEWS.d/next/Build/2024-06-19-21-05-15.gh-issue-120602.UyDARz.rst deleted file mode 100644 index f0d90ec3bb5089..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-19-21-05-15.gh-issue-120602.UyDARz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly handle LLVM installs with ``LLVM_VERSION_SUFFIX`` when building -with ``--enable-experimental-jit``. diff --git a/Misc/NEWS.d/next/Build/2024-06-21-09-24-03.gh-issue-120671.Z8sBQB.rst b/Misc/NEWS.d/next/Build/2024-06-21-09-24-03.gh-issue-120671.Z8sBQB.rst deleted file mode 100644 index bbe4a3038bc0ff..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-21-09-24-03.gh-issue-120671.Z8sBQB.rst +++ /dev/null @@ -1 +0,0 @@ -Fix failing configure tests due to a missing space when appending to CFLAGS. diff --git a/Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst b/Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst deleted file mode 100644 index 7657672ba880c8..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-06-27-18-03-20.gh-issue-121082.w3AfRx.rst +++ /dev/null @@ -1 +0,0 @@ -Fix build failure when the developer use ``--enable-pystats`` arguments in configuration command after #118450. diff --git a/Misc/NEWS.d/next/Build/2024-07-02-12-42-25.gh-issue-120831.i3eIjg.rst b/Misc/NEWS.d/next/Build/2024-07-02-12-42-25.gh-issue-120831.i3eIjg.rst deleted file mode 100644 index 3784cc66c41219..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-02-12-42-25.gh-issue-120831.i3eIjg.rst +++ /dev/null @@ -1 +0,0 @@ -The default minimum iOS version was increased to 13.0. diff --git a/Misc/NEWS.d/next/Build/2024-07-02-20-16-09.gh-issue-121103.TMef9j.rst b/Misc/NEWS.d/next/Build/2024-07-02-20-16-09.gh-issue-121103.TMef9j.rst deleted file mode 100644 index 4bc8c6de0b7733..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-02-20-16-09.gh-issue-121103.TMef9j.rst +++ /dev/null @@ -1,3 +0,0 @@ -On POSIX systems, excluding macOS framework installs, the lib directory -for the free-threaded build now includes a "t" suffix to avoid conflicts -with a co-located default build installation. diff --git a/Misc/NEWS.d/next/Build/2024-07-08-01-11-54.gh-issue-121467.3qWRQj.rst b/Misc/NEWS.d/next/Build/2024-07-08-01-11-54.gh-issue-121467.3qWRQj.rst deleted file mode 100644 index a2238475546eaa..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-08-01-11-54.gh-issue-121467.3qWRQj.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a Makefile bug that prevented mimalloc header files from being installed. diff --git a/Misc/NEWS.d/next/Build/2024-07-08-14-01-17.gh-issue-121487.ekHmpR.rst b/Misc/NEWS.d/next/Build/2024-07-08-14-01-17.gh-issue-121487.ekHmpR.rst deleted file mode 100644 index e30d4dcdbfe779..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-08-14-01-17.gh-issue-121487.ekHmpR.rst +++ /dev/null @@ -1 +0,0 @@ -Fix deprecation warning for ATOMIC_VAR_INIT in mimalloc. diff --git a/Misc/NEWS.d/next/Build/2024-07-14-01-29-47.gh-issue-121731.RMPGP3.rst b/Misc/NEWS.d/next/Build/2024-07-14-01-29-47.gh-issue-121731.RMPGP3.rst deleted file mode 100644 index 36e0f86a0ae455..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-14-01-29-47.gh-issue-121731.RMPGP3.rst +++ /dev/null @@ -1 +0,0 @@ -Fix mimalloc compile error on GNU/Hurd diff --git a/Misc/NEWS.d/next/Build/2024-07-16-12-29-54.gh-issue-120371.E7x858.rst b/Misc/NEWS.d/next/Build/2024-07-16-12-29-54.gh-issue-120371.E7x858.rst deleted file mode 100644 index d57266dafd8d67..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-16-12-29-54.gh-issue-120371.E7x858.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support WASI SDK 22 by explicitly skipping functions that are just stubs in -wasi-libc. diff --git a/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst b/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst deleted file mode 100644 index e90c625a886b65..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added a :option:`--with-app-store-compliance` option to patch out known -issues with macOS/iOS App Store review processes. diff --git a/Misc/NEWS.d/next/Build/2024-07-19-10-14-31.gh-issue-121996.IEb2sz.rst b/Misc/NEWS.d/next/Build/2024-07-19-10-14-31.gh-issue-121996.IEb2sz.rst deleted file mode 100644 index 171efe8388bc0d..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-07-19-10-14-31.gh-issue-121996.IEb2sz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Introduce ./configure --disable-safety and --enable-slower-safety options. -Patch by Donghee Na. diff --git a/Misc/NEWS.d/next/Build/2024-08-02-12-59-15.gh-issue-118943.vZQtET.rst b/Misc/NEWS.d/next/Build/2024-08-02-12-59-15.gh-issue-118943.vZQtET.rst deleted file mode 100644 index 42cda69e01cd4c..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-08-02-12-59-15.gh-issue-118943.vZQtET.rst +++ /dev/null @@ -1 +0,0 @@ -Fix an issue where the experimental JIT could be built several times by the ``make regen-all`` target, leading to possible race conditions on heavily parallelized builds. diff --git a/Misc/NEWS.d/next/Build/2024-08-07-00-20-18.gh-issue-116622.U9cxHM.rst b/Misc/NEWS.d/next/Build/2024-08-07-00-20-18.gh-issue-116622.U9cxHM.rst deleted file mode 100644 index c9a56d65ad0cd3..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-08-07-00-20-18.gh-issue-116622.U9cxHM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Rename build variable ``MODULE_LDFLAGS`` back to ``LIBPYTHON``, as it's used by -package build systems (e.g. Meson). diff --git a/Misc/NEWS.d/next/Build/2024-08-12-15-48-49.gh-issue-122578.YJ3xEa.rst b/Misc/NEWS.d/next/Build/2024-08-12-15-48-49.gh-issue-122578.YJ3xEa.rst deleted file mode 100644 index 5c1b9079909ff4..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-08-12-15-48-49.gh-issue-122578.YJ3xEa.rst +++ /dev/null @@ -1 +0,0 @@ -Use WASI SDK 24 for testing. diff --git a/Misc/NEWS.d/next/Build/2024-08-14-19-17-34.gh-issue-121634.eOMfHG.rst b/Misc/NEWS.d/next/Build/2024-08-14-19-17-34.gh-issue-121634.eOMfHG.rst deleted file mode 100644 index 025b6bca809898..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-08-14-19-17-34.gh-issue-121634.eOMfHG.rst +++ /dev/null @@ -1 +0,0 @@ -Allow for specifying the target compile triple for WASI. diff --git a/Misc/NEWS.d/next/Build/2024-08-24-19-09-31.gh-issue-123297.fdtXoe.rst b/Misc/NEWS.d/next/Build/2024-08-24-19-09-31.gh-issue-123297.fdtXoe.rst deleted file mode 100644 index d2c831b27be237..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-08-24-19-09-31.gh-issue-123297.fdtXoe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Propagate the value of ``LDFLAGS`` to ``LDCXXSHARED`` in :mod:`sysconfig`. -Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Build/2024-09-04-12-01-43.gh-issue-123418.ynzspB.rst b/Misc/NEWS.d/next/Build/2024-09-04-12-01-43.gh-issue-123418.ynzspB.rst deleted file mode 100644 index 38d0e02f3ce404..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-09-04-12-01-43.gh-issue-123418.ynzspB.rst +++ /dev/null @@ -1 +0,0 @@ -Updated Android build to use OpenSSL 3.0.15. diff --git a/Misc/NEWS.d/next/Build/2024-09-13-17-48-37.gh-issue-124043.Bruxpq.rst b/Misc/NEWS.d/next/Build/2024-09-13-17-48-37.gh-issue-124043.Bruxpq.rst deleted file mode 100644 index 8111b76f95fad6..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-09-13-17-48-37.gh-issue-124043.Bruxpq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Building using :option:`--with-trace-refs` is (temporarily) disallowed when the -GIL is disabled. diff --git a/Misc/NEWS.d/next/Build/2024-09-16-09-42-05.gh-issue-124102.Ow254j.rst b/Misc/NEWS.d/next/Build/2024-09-16-09-42-05.gh-issue-124102.Ow254j.rst deleted file mode 100644 index 6edc9a6abbced4..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-09-16-09-42-05.gh-issue-124102.Ow254j.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update internal documentation under PCbuild, so it now correctly states that -Windows requires VS2017 or later and Python 3.10 or later diff --git a/Misc/NEWS.d/next/Build/2024-09-23-11-27-25.gh-issue-123990.d6HrYC.rst b/Misc/NEWS.d/next/Build/2024-09-23-11-27-25.gh-issue-123990.d6HrYC.rst deleted file mode 100644 index 2b4f993323297a..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-09-23-11-27-25.gh-issue-123990.d6HrYC.rst +++ /dev/null @@ -1 +0,0 @@ -Remove ``WITH_FREELISTS`` macro and ``--without-freelists`` build configuration diff --git a/Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst b/Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst deleted file mode 100644 index 24f5469e8a664b..00000000000000 --- a/Misc/NEWS.d/next/Build/2024-10-13-21-11-30.gh-issue-125269.BC-fdo.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix detection of whether ``-latomic`` is needed when cross-compiling CPython -using the configure script. diff --git a/Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst b/Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst deleted file mode 100644 index 1a01dafc758004..00000000000000 --- a/Misc/NEWS.d/next/C API/2018-06-30-21-48-16.bpo-34008.2Wjtm0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added ``Py_IsInitialized`` to the list of APIs that are safe to call before -the interpreter is initialized, and updated the embedding tests to cover it. diff --git a/Misc/NEWS.d/next/C API/2022-08-05-19-41-20.gh-issue-87135.SCNBYj.rst b/Misc/NEWS.d/next/C API/2022-08-05-19-41-20.gh-issue-87135.SCNBYj.rst deleted file mode 100644 index 6387d69bc267c6..00000000000000 --- a/Misc/NEWS.d/next/C API/2022-08-05-19-41-20.gh-issue-87135.SCNBYj.rst +++ /dev/null @@ -1,15 +0,0 @@ -Attempting to acquire the GIL after runtime finalization has begun in a -different thread now causes the thread to hang rather than terminate, which -avoids potential crashes or memory corruption caused by attempting to -terminate a thread that is running code not specifically designed to support -termination. In most cases this hanging is harmless since the process will -soon exit anyway. - -The ``PyThread_exit_thread`` function is now deprecated. Its behavior is -inconsistent across platforms, and it can only be used safely in the -unlikely case that every function in the entire call stack has been designed -to support the platform-dependent termination mechanism. It is recommended -that users of this function change their design to not require thread -termination. In the unlikely case that thread termination is needed and can -be done safely, users may migrate to calling platform-specific APIs such as -``pthread_exit`` (POSIX) or ``_endthreadex`` (Windows) directly. diff --git a/Misc/NEWS.d/next/C API/2022-10-01-09-56-27.gh-issue-97588.Gvg54o.rst b/Misc/NEWS.d/next/C API/2022-10-01-09-56-27.gh-issue-97588.Gvg54o.rst deleted file mode 100644 index 0bb0f5bcd501ef..00000000000000 --- a/Misc/NEWS.d/next/C API/2022-10-01-09-56-27.gh-issue-97588.Gvg54o.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix creating bitfields in :mod:`ctypes` structures and unions. Fields -no longer overlap. diff --git a/Misc/NEWS.d/next/C API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst b/Misc/NEWS.d/next/C API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst deleted file mode 100644 index 9bcadfd9247f78..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst +++ /dev/null @@ -1 +0,0 @@ -Add :c:func:`PyLong_GetSign` function. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/C API/2024-04-10-16-48-04.gh-issue-117511.RZtBRK.rst b/Misc/NEWS.d/next/C API/2024-04-10-16-48-04.gh-issue-117511.RZtBRK.rst deleted file mode 100644 index 586685a3407a3d..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-04-10-16-48-04.gh-issue-117511.RZtBRK.rst +++ /dev/null @@ -1 +0,0 @@ -Make the :c:type:`PyMutex` public in the non-limited C API. diff --git a/Misc/NEWS.d/next/C API/2024-05-08-20-13-00.gh-issue-118789.m88uUa.rst b/Misc/NEWS.d/next/C API/2024-05-08-20-13-00.gh-issue-118789.m88uUa.rst deleted file mode 100644 index a2acc16b2c1d01..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-08-20-13-00.gh-issue-118789.m88uUa.rst +++ /dev/null @@ -1,2 +0,0 @@ -Restore ``_PyWeakref_ClearRef`` that was previously removed in Python 3.13 -alpha 1. diff --git a/Misc/NEWS.d/next/C API/2024-05-08-21-57-50.gh-issue-118789.Ni4UQx.rst b/Misc/NEWS.d/next/C API/2024-05-08-21-57-50.gh-issue-118789.Ni4UQx.rst deleted file mode 100644 index 32a9ec6d0710f6..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-08-21-57-50.gh-issue-118789.Ni4UQx.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyUnstable_Object_ClearWeakRefsNoCallbacks`, which clears -weakrefs without calling their callbacks. diff --git a/Misc/NEWS.d/next/C API/2024-05-08-23-14-06.gh-issue-116984.5sgcDo.rst b/Misc/NEWS.d/next/C API/2024-05-08-23-14-06.gh-issue-116984.5sgcDo.rst deleted file mode 100644 index 561417b80d444d..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-08-23-14-06.gh-issue-116984.5sgcDo.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make mimalloc includes relative to the current file to avoid embedders or -extensions needing to include ``Internal/mimalloc`` if they are already -including internal CPython headers. diff --git a/Misc/NEWS.d/next/C API/2024-05-10-15-43-14.gh-issue-118771.5KVglT.rst b/Misc/NEWS.d/next/C API/2024-05-10-15-43-14.gh-issue-118771.5KVglT.rst deleted file mode 100644 index 2ed8089dfe8444..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-10-15-43-14.gh-issue-118771.5KVglT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Several C declarations with names that didn't start with the ``Py`` or ``_Py`` -prefixes, which were added by mistake in 3.13 alpha and beta releases, were -moved to internal headers. diff --git a/Misc/NEWS.d/next/C API/2024-05-20-10-35-22.gh-issue-111389.a6axBk.rst b/Misc/NEWS.d/next/C API/2024-05-20-10-35-22.gh-issue-111389.a6axBk.rst deleted file mode 100644 index f47662f2e0a778..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-20-10-35-22.gh-issue-111389.a6axBk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:macro:`PyHASH_MULTIPLIER` constant: prime multiplier used in string -and various other hashes. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-05-21-11-35-11.gh-issue-119247.U6n6mh.rst b/Misc/NEWS.d/next/C API/2024-05-21-11-35-11.gh-issue-119247.U6n6mh.rst deleted file mode 100644 index 3b2cdc8cf2dc5c..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-21-11-35-11.gh-issue-119247.U6n6mh.rst +++ /dev/null @@ -1,4 +0,0 @@ -Added ``Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST`` and -``Py_END_CRITICAL_SECTION_SEQUENCE_FAST`` macros to make it possible to use -PySequence_Fast APIs safely when free-threaded, and update str.join to work -without the GIL using them. diff --git a/Misc/NEWS.d/next/C API/2024-05-21-18-28-44.gh-issue-119333.OTsYVX.rst b/Misc/NEWS.d/next/C API/2024-05-21-18-28-44.gh-issue-119333.OTsYVX.rst deleted file mode 100644 index 6fb6013c4d442d..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-21-18-28-44.gh-issue-119333.OTsYVX.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyContext_AddWatcher` and :c:func:`PyContext_ClearWatcher` APIs to -register callbacks to receive notification on enter and exit of context objects. diff --git a/Misc/NEWS.d/next/C API/2024-05-21-19-41-41.gh-issue-119344.QKvzQb.rst b/Misc/NEWS.d/next/C API/2024-05-21-19-41-41.gh-issue-119344.QKvzQb.rst deleted file mode 100644 index 5a2e4d980b59be..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-21-19-41-41.gh-issue-119344.QKvzQb.rst +++ /dev/null @@ -1 +0,0 @@ -The critical section API is now public as part of the non-limited C API. diff --git a/Misc/NEWS.d/next/C API/2024-05-22-17-50-48.gh-issue-119336.ff3qnS.rst b/Misc/NEWS.d/next/C API/2024-05-22-17-50-48.gh-issue-119336.ff3qnS.rst deleted file mode 100644 index e530bb45d35e76..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-22-17-50-48.gh-issue-119336.ff3qnS.rst +++ /dev/null @@ -1 +0,0 @@ -Restore the removed ``_PyLong_NumBits()`` function. It is used by the pywin32 project. Patch by Ethan Smith diff --git a/Misc/NEWS.d/next/C API/2024-05-29-09-21-37.gh-issue-119613.J2xfrC.rst b/Misc/NEWS.d/next/C API/2024-05-29-09-21-37.gh-issue-119613.J2xfrC.rst deleted file mode 100644 index 196a4722a98c70..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-29-09-21-37.gh-issue-119613.J2xfrC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Macros ``Py_IS_NAN``, ``Py_IS_INFINITY`` and ``Py_IS_FINITE`` -are :term:`soft deprecated`. diff --git a/Misc/NEWS.d/next/C API/2024-05-29-21-05-59.gh-issue-119585.Sn7JL3.rst b/Misc/NEWS.d/next/C API/2024-05-29-21-05-59.gh-issue-119585.Sn7JL3.rst deleted file mode 100644 index 038dec2dbf90d1..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-29-21-05-59.gh-issue-119585.Sn7JL3.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix crash when a thread state that was created by :c:func:`PyGILState_Ensure` -calls a destructor that during :c:func:`PyThreadState_Clear` that -calls back into :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release`. -This might occur when in the free-threaded build or when using thread-local -variables whose destructors call :c:func:`PyGILState_Ensure`. diff --git a/Misc/NEWS.d/next/C API/2024-05-30-12-51-21.gh-issue-119775.CBq9IG.rst b/Misc/NEWS.d/next/C API/2024-05-30-12-51-21.gh-issue-119775.CBq9IG.rst deleted file mode 100644 index c342a3814ed5db..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-05-30-12-51-21.gh-issue-119775.CBq9IG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Creating :c:data:`immutable types ` with mutable -bases was deprecated since 3.12 and now raises a :exc:`TypeError`. diff --git a/Misc/NEWS.d/next/C API/2024-06-04-10-58-20.gh-issue-119613.qOr9GF.rst b/Misc/NEWS.d/next/C API/2024-06-04-10-58-20.gh-issue-119613.qOr9GF.rst deleted file mode 100644 index 11f075b79e6f67..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-04-10-58-20.gh-issue-119613.qOr9GF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Soft deprecate the :c:macro:`!Py_MEMCPY` macro: use directly ``memcpy()`` -instead. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-06-07-22-12-30.gh-issue-119182.yt8Ar7.rst b/Misc/NEWS.d/next/C API/2024-06-07-22-12-30.gh-issue-119182.yt8Ar7.rst deleted file mode 100644 index 243f290fbd47e2..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-07-22-12-30.gh-issue-119182.yt8Ar7.rst +++ /dev/null @@ -1,16 +0,0 @@ -Add a new :c:type:`PyUnicodeWriter` API to create a Python :class:`str` object: - -* :c:func:`PyUnicodeWriter_Create`. -* :c:func:`PyUnicodeWriter_Discard`. -* :c:func:`PyUnicodeWriter_Finish`. -* :c:func:`PyUnicodeWriter_WriteChar`. -* :c:func:`PyUnicodeWriter_WriteUTF8`. -* :c:func:`PyUnicodeWriter_WriteUCS4`. -* :c:func:`PyUnicodeWriter_WriteWideChar`. -* :c:func:`PyUnicodeWriter_WriteStr`. -* :c:func:`PyUnicodeWriter_WriteRepr`. -* :c:func:`PyUnicodeWriter_WriteSubstring`. -* :c:func:`PyUnicodeWriter_Format`. -* :c:func:`PyUnicodeWriter_DecodeUTF8Stateful`. - -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-06-08-08-33-40.gh-issue-119771.Oip2dL.rst b/Misc/NEWS.d/next/C API/2024-06-08-08-33-40.gh-issue-119771.Oip2dL.rst deleted file mode 100644 index 61619082487c3b..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-08-08-33-40.gh-issue-119771.Oip2dL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Set :data:`errno` in :c:func:`_Py_c_pow` on overflows. Patch by Sergey B -Kirpichev. diff --git a/Misc/NEWS.d/next/C API/2024-06-11-21-38-32.gh-issue-70278.WDE4zM.rst b/Misc/NEWS.d/next/C API/2024-06-11-21-38-32.gh-issue-70278.WDE4zM.rst deleted file mode 100644 index 1eca36a86bc97e..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-11-21-38-32.gh-issue-70278.WDE4zM.rst +++ /dev/null @@ -1,4 +0,0 @@ -:c:func:`PyUnicode_FromFormat` no longer produces the ending ``\ufffd`` -character for truncated C string when use precision with ``%s`` and ``%V``. -It now truncates the string before the start of truncated multibyte -sequences. diff --git a/Misc/NEWS.d/next/C API/2024-06-16-22-58-47.gh-issue-120600.TJdf0w.rst b/Misc/NEWS.d/next/C API/2024-06-16-22-58-47.gh-issue-120600.TJdf0w.rst deleted file mode 100644 index 12ffd9b348d2b7..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-16-22-58-47.gh-issue-120600.TJdf0w.rst +++ /dev/null @@ -1,2 +0,0 @@ -In the limited C API 3.14 and newer, :c:func:`Py_TYPE` is now implemented as an -opaque function call to hide implementation details. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-06-19-17-27-22.gh-issue-120389.GSZeHF.rst b/Misc/NEWS.d/next/C API/2024-06-19-17-27-22.gh-issue-120389.GSZeHF.rst deleted file mode 100644 index 094c8b00ac6859..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-19-17-27-22.gh-issue-120389.GSZeHF.rst +++ /dev/null @@ -1,13 +0,0 @@ -Add new functions to convert C ```` numbers from/to Python -:class:`int`: - -* :c:func:`PyLong_FromInt32` -* :c:func:`PyLong_FromUInt32` -* :c:func:`PyLong_FromInt64` -* :c:func:`PyLong_FromUInt64` -* :c:func:`PyLong_AsInt32` -* :c:func:`PyLong_AsUInt32` -* :c:func:`PyLong_AsInt64` -* :c:func:`PyLong_AsUInt64` - -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-06-19-21-27-42.gh-issue-120642.UlKClN.rst b/Misc/NEWS.d/next/C API/2024-06-19-21-27-42.gh-issue-120642.UlKClN.rst deleted file mode 100644 index a61224ec8ef119..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-19-21-27-42.gh-issue-120642.UlKClN.rst +++ /dev/null @@ -1,10 +0,0 @@ -Remove the following unstable functions: - -* ``PyUnstable_Replace_Executor()`` -* ``PyUnstable_SetOptimizer()`` -* ``PyUnstable_GetOptimizer()`` -* ``PyUnstable_GetExecutor()`` -* ``PyUnstable_Optimizer_NewCounter()`` -* ``PyUnstable_Optimizer_NewUOpOptimizer()`` - -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-06-21-16-41-21.gh-issue-120858.Z5_-Mn.rst b/Misc/NEWS.d/next/C API/2024-06-21-16-41-21.gh-issue-120858.Z5_-Mn.rst deleted file mode 100644 index b5df2a567b9da8..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-21-16-41-21.gh-issue-120858.Z5_-Mn.rst +++ /dev/null @@ -1,3 +0,0 @@ -:c:func:`PyDict_Next` no longer locks the dictionary in the free-threaded -build. The locking needs to be done by the caller around the entire iteration -loop. diff --git a/Misc/NEWS.d/next/C API/2024-06-26-11-29-01.gh-issue-120642.H7P9qK.rst b/Misc/NEWS.d/next/C API/2024-06-26-11-29-01.gh-issue-120642.H7P9qK.rst deleted file mode 100644 index 24fb6ca569f4f3..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-06-26-11-29-01.gh-issue-120642.H7P9qK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the private ``_Py_CODEUNIT`` type from the public C API. The internal -``pycore_code.h`` header should now be used to get this internal type. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-07-02-11-03-40.gh-issue-112136.f3fiY8.rst b/Misc/NEWS.d/next/C API/2024-07-02-11-03-40.gh-issue-112136.f3fiY8.rst deleted file mode 100644 index a240b4e852c4d1..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-07-02-11-03-40.gh-issue-112136.f3fiY8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Restore the private ``_PyArg_Parser`` structure and the private -``_PyArg_ParseTupleAndKeywordsFast()`` function, previously removed in Python -3.13 alpha 1. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst b/Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst deleted file mode 100644 index 009cc2bf017180..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed debug build assertions related to interning strings, which were -falsely triggered by stable ABI extensions. diff --git a/Misc/NEWS.d/next/C API/2024-07-04-15-41-10.gh-issue-113993.cLSiWV.rst b/Misc/NEWS.d/next/C API/2024-07-04-15-41-10.gh-issue-113993.cLSiWV.rst deleted file mode 100644 index 9b7f2082065eaa..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-07-04-15-41-10.gh-issue-113993.cLSiWV.rst +++ /dev/null @@ -1,12 +0,0 @@ -:c:func:`PyUnicode_InternInPlace` no longer prevents its argument from being -garbage collected. - -Several functions that take ``char *`` are now -documented as possibly preventing string objects from being garbage -collected; refer to their documentation for details: -:c:func:`PyUnicode_InternFromString`, -:c:func:`PyDict_SetItemString`, -:c:func:`PyObject_SetAttrString`, -:c:func:`PyObject_DelAttrString`, -:c:func:`PyUnicode_InternFromString`, -and ``PyModule_Add*`` convenience functions. diff --git a/Misc/NEWS.d/next/C API/2024-07-21-17-40-07.gh-issue-121489.SUMFCr.rst b/Misc/NEWS.d/next/C API/2024-07-21-17-40-07.gh-issue-121489.SUMFCr.rst deleted file mode 100644 index 8c18a49c05d547..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-07-21-17-40-07.gh-issue-121489.SUMFCr.rst +++ /dev/null @@ -1 +0,0 @@ -Export private :c:func:`!_PyBytes_Join` again. diff --git a/Misc/NEWS.d/next/C API/2024-07-30-23-48-26.gh-issue-116622.yTTtil.rst b/Misc/NEWS.d/next/C API/2024-07-30-23-48-26.gh-issue-116622.yTTtil.rst deleted file mode 100644 index 7ae0f83f37bd62..00000000000000 --- a/Misc/NEWS.d/next/C API/2024-07-30-23-48-26.gh-issue-116622.yTTtil.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make :any:`PyObject_Print` work around a bug in Android and OpenBSD which -prevented it from throwing an exception when trying to write to a read-only -stream. diff --git a/Misc/NEWS.d/next/C_API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst b/Misc/NEWS.d/next/C_API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst deleted file mode 100644 index b82e78446e4e87..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst +++ /dev/null @@ -1,3 +0,0 @@ -Export the :c:func:`PySignal_SetWakeupFd` function. Previously, the function -was documented but it couldn't be used in 3rd party code. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-07-12-13-40-59.gh-issue-121645.96QvD3.rst b/Misc/NEWS.d/next/C_API/2024-07-12-13-40-59.gh-issue-121645.96QvD3.rst deleted file mode 100644 index 1cca9b2230c3f4..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-07-12-13-40-59.gh-issue-121645.96QvD3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyBytes_Join(sep, iterable) ` function, similar to -``sep.join(iterable)`` in Python. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-07-27-00-28-35.gh-issue-105201.0-xUWq.rst b/Misc/NEWS.d/next/C_API/2024-07-27-00-28-35.gh-issue-105201.0-xUWq.rst deleted file mode 100644 index bf5300b1c5d5f8..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-07-27-00-28-35.gh-issue-105201.0-xUWq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyIter_NextItem` to replace :c:func:`PyIter_Next`, which has an -ambiguous return value. Patch by Irit Katriel and Erlend Aasland. diff --git a/Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst b/Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst deleted file mode 100644 index a128d6aef34dfc..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :c:func:`PyEval_GetLocals` to avoid :exc:`SystemError` ("bad argument to -internal function"). Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-08-09-13-12-20.gh-issue-122854.-1OgvU.rst b/Misc/NEWS.d/next/C_API/2024-08-09-13-12-20.gh-issue-122854.-1OgvU.rst deleted file mode 100644 index b94d8f4e483bda..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-08-09-13-12-20.gh-issue-122854.-1OgvU.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`Py_HashBuffer` to compute and return the hash value of a buffer. -Patch by Antoine Pitrou and Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-08-26-13-01-20.gh-issue-100554.0ku85o.rst b/Misc/NEWS.d/next/C_API/2024-08-26-13-01-20.gh-issue-100554.0ku85o.rst deleted file mode 100644 index 97138dedf26b6f..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-08-26-13-01-20.gh-issue-100554.0ku85o.rst +++ /dev/null @@ -1,4 +0,0 @@ -Added a slot ``Py_tp_vectorcall`` to set -:c:member:`~PyTypeObject.tp_vectorcall` via the :c:func:`PyType_FromSpec` -function family. Limited API extensions can use this feature to provide more -efficient vector call-based implementation of ``__new__`` and ``__init__``. diff --git a/Misc/NEWS.d/next/C_API/2024-08-29-15-05-19.gh-issue-123465.eqwNWq.rst b/Misc/NEWS.d/next/C_API/2024-08-29-15-05-19.gh-issue-123465.eqwNWq.rst deleted file mode 100644 index 1935adfad8885b..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-08-29-15-05-19.gh-issue-123465.eqwNWq.rst +++ /dev/null @@ -1,4 +0,0 @@ -:c:macro:`Py_RELATIVE_OFFSET` is now allowed in :c:type:`PyMemberDef` for -the special offset member ``"__vectorcalloffset__"``, as well as the -discouraged special offset members ``"__dictoffset__"`` and -``"__weaklistoffset__"`` diff --git a/Misc/NEWS.d/next/C_API/2024-08-29-15-55-55.gh-issue-107954.pr2O50.rst b/Misc/NEWS.d/next/C_API/2024-08-29-15-55-55.gh-issue-107954.pr2O50.rst deleted file mode 100644 index f1116870c9d1c3..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-08-29-15-55-55.gh-issue-107954.pr2O50.rst +++ /dev/null @@ -1,8 +0,0 @@ -Add functions to get and set the current runtime Python configuration: - -* :c:func:`PyConfig_Get` -* :c:func:`PyConfig_GetInt` -* :c:func:`PyConfig_Set` -* :c:func:`PyConfig_Names` - -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-08-30-14-02-17.gh-issue-107954.TPvj4u.rst b/Misc/NEWS.d/next/C_API/2024-08-30-14-02-17.gh-issue-107954.TPvj4u.rst deleted file mode 100644 index e0ebd816bd6586..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-08-30-14-02-17.gh-issue-107954.TPvj4u.rst +++ /dev/null @@ -1,18 +0,0 @@ -Add functions to configure the Python initialization (:pep:`741`): - -* :c:func:`PyInitConfig_Create` -* :c:func:`PyInitConfig_Free` -* :c:func:`PyInitConfig_GetError` -* :c:func:`PyInitConfig_GetExitCode` -* :c:func:`PyInitConfig_HasOption` -* :c:func:`PyInitConfig_GetInt` -* :c:func:`PyInitConfig_GetStr` -* :c:func:`PyInitConfig_GetStrList` -* :c:func:`PyInitConfig_FreeStrList` -* :c:func:`PyInitConfig_SetInt` -* :c:func:`PyInitConfig_SetStr` -* :c:func:`PyInitConfig_SetStrList` -* :c:func:`PyInitConfig_AddModule` -* :c:func:`Py_InitializeFromInitConfig` - -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst b/Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst deleted file mode 100644 index b7a4913abbcb89..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst +++ /dev/null @@ -1,3 +0,0 @@ -:c:func:`PyType_FromSpec`, :c:func:`PyType_FromSpecWithBases` and -:c:func:`PyType_FromModuleAndSpec` will now fail if the metaclass of the new -type has custom :c:member:`~PyTypeObject.tp_new`. diff --git a/Misc/NEWS.d/next/C_API/2024-09-12-16-16-24.gh-issue-123880.2-8vcj.rst b/Misc/NEWS.d/next/C_API/2024-09-12-16-16-24.gh-issue-123880.2-8vcj.rst deleted file mode 100644 index 8a31c962ec7d93..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-09-12-16-16-24.gh-issue-123880.2-8vcj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a bug that prevented circular imports of extension modules that use -single-phase initialization. diff --git a/Misc/NEWS.d/next/C_API/2024-09-16-16-21-39.gh-issue-124127.LB8DBU.rst b/Misc/NEWS.d/next/C_API/2024-09-16-16-21-39.gh-issue-124127.LB8DBU.rst deleted file mode 100644 index 883f173f8fbbc4..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-09-16-16-21-39.gh-issue-124127.LB8DBU.rst +++ /dev/null @@ -1,3 +0,0 @@ -In the limited C API 3.14 and newer, :c:func:`Py_REFCNT` is now implemented -as an opaque function call to hide implementation details. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-09-17-05-23-35.gh-issue-124153.L8TWmx.rst b/Misc/NEWS.d/next/C_API/2024-09-17-05-23-35.gh-issue-124153.L8TWmx.rst deleted file mode 100644 index b8c0b4667cb730..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-09-17-05-23-35.gh-issue-124153.L8TWmx.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyType_GetBaseByToken` and :c:data:`Py_tp_token` slot for easier -type checking, related to :pep:`489` and :pep:`630`. diff --git a/Misc/NEWS.d/next/C_API/2024-09-18-18-40-30.gh-issue-124160.Zy-VKi.rst b/Misc/NEWS.d/next/C_API/2024-09-18-18-40-30.gh-issue-124160.Zy-VKi.rst deleted file mode 100644 index 26e7aef08ea4f3..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-09-18-18-40-30.gh-issue-124160.Zy-VKi.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash when importing modules containing state and single-phase -initialization in a subinterpreter. diff --git a/Misc/NEWS.d/next/C_API/2024-09-24-20-34-21.gh-issue-124296.S4QoS1.rst b/Misc/NEWS.d/next/C_API/2024-09-24-20-34-21.gh-issue-124296.S4QoS1.rst deleted file mode 100644 index e7b9187655eb31..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-09-24-20-34-21.gh-issue-124296.S4QoS1.rst +++ /dev/null @@ -1,3 +0,0 @@ -:c:type:`PyDictObject` no longer maintains a private version tag field -``ma_version_tag`` per :pep:`699`. This field was originally added in -Python 3.6 (:pep:`509`) and deprecated in Python 3.12. diff --git a/Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst b/Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst deleted file mode 100644 index f515619328b359..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-09-25-11-44-02.gh-issue-124502.qWuDjT.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyUnicode_Equal` function to the limited C API: test if two -strings are equal. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst deleted file mode 100644 index 40c26e15a2de92..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst +++ /dev/null @@ -1,3 +0,0 @@ -Convert the :ref:`curses.window ` static type exposed -by the :c:macro:`!PyCursesWindow_Type` macro in ``Include/py_curses.h`` to a -:ref:`heap type `. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-10-09-15-14-53.bpo-24766.c_C1Wc.rst b/Misc/NEWS.d/next/Core and Builtins/2018-10-09-15-14-53.bpo-24766.c_C1Wc.rst deleted file mode 100644 index 93a8562efe6d6f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2018-10-09-15-14-53.bpo-24766.c_C1Wc.rst +++ /dev/null @@ -1 +0,0 @@ -Fix handling of ``doc`` argument to subclasses of ``property``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-22-15-56-35.gh-issue-95144.FZYWX-.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-22-15-56-35.gh-issue-95144.FZYWX-.rst deleted file mode 100644 index 83b1126a8a455f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-22-15-56-35.gh-issue-95144.FZYWX-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the error message from ``a in b`` when ``b`` is not a container -to mention the term "container". diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst deleted file mode 100644 index b1f08288f925da..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst +++ /dev/null @@ -1 +0,0 @@ -Add class methods :meth:`float.from_number` and :meth:`complex.from_number`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-15-18-11-48.gh-issue-113190.OwQX64.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-15-18-11-48.gh-issue-113190.OwQX64.rst deleted file mode 100644 index 4c12870c3df548..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-01-15-18-11-48.gh-issue-113190.OwQX64.rst +++ /dev/null @@ -1 +0,0 @@ -:c:func:`Py_Finalize` now deletes all interned strings. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-15-21-51-26.gh-issue-114091.VOtSJl.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-15-21-51-26.gh-issue-114091.VOtSJl.rst deleted file mode 100644 index 55b7d9104baed9..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-01-15-21-51-26.gh-issue-114091.VOtSJl.rst +++ /dev/null @@ -1 +0,0 @@ -Changed the error message for awaiting something that can't be awaited from "object can't be used in an await expression" to "'' object can't be awaited". diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-19-22-21-22.gh-issue-116022.iyHENN.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-19-22-21-22.gh-issue-116022.iyHENN.rst deleted file mode 100644 index 659ffb289129e2..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-03-19-22-21-22.gh-issue-116022.iyHENN.rst +++ /dev/null @@ -1 +0,0 @@ -Improve the :meth:`~object.__repr__` output of :class:`~ast.AST` nodes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-25-15-07-01.gh-issue-117195.OWakgD.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-25-15-07-01.gh-issue-117195.OWakgD.rst deleted file mode 100644 index ae1e5acc5c333b..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-03-25-15-07-01.gh-issue-117195.OWakgD.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid assertion failure for debug builds when calling -``object.__sizeof__(1)`` diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-08-13-49-02.gh-issue-117558.9lSEpR.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-08-13-49-02.gh-issue-117558.9lSEpR.rst deleted file mode 100644 index 222c516d2ef1b9..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-04-08-13-49-02.gh-issue-117558.9lSEpR.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve error messages when a string, bytes or bytearray object of length 1 -is expected. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-27-18-36-46.gh-issue-115801.SVeHSy.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-27-18-36-46.gh-issue-115801.SVeHSy.rst deleted file mode 100644 index 93b176d5767335..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-04-27-18-36-46.gh-issue-115801.SVeHSy.rst +++ /dev/null @@ -1 +0,0 @@ -Raise ``TypeError`` when passing a string to :func:`difflib.unified_diff` and :func:`difflib.context_diff`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-01-05-09-16.gh-issue-117139.t41w_D.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-01-05-09-16.gh-issue-117139.t41w_D.rst deleted file mode 100644 index 07d5dd53aac30a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-01-05-09-16.gh-issue-117139.t41w_D.rst +++ /dev/null @@ -1,5 +0,0 @@ -Convert the Python evaluation stack to use internal stack references. The -purpose is to support tagged pointers. In :pep:`703`, this will -allow for its form of deferred reference counting. For both -the default and free-threaded builds, this sets up the infrastructure -for unboxed integers in the future. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-07-16-57-56.gh-issue-118561.wNMKVd.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-07-16-57-56.gh-issue-118561.wNMKVd.rst deleted file mode 100644 index c506a8cefd00f1..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-07-16-57-56.gh-issue-118561.wNMKVd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix race condition in free-threaded build where :meth:`!list.extend` could -expose uninitialised memory to concurrent readers. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-08-09-44-15.gh-issue-118767.iFF5F5.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-08-09-44-15.gh-issue-118767.iFF5F5.rst deleted file mode 100644 index 4828f8fbf50cea..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-08-09-44-15.gh-issue-118767.iFF5F5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Using :data:`NotImplemented` in a boolean context now raises -:exc:`TypeError`. Contributed by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-09-02-37-25.gh-issue-118750.7aLfT-.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-09-02-37-25.gh-issue-118750.7aLfT-.rst deleted file mode 100644 index 727427d451d1e0..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-09-02-37-25.gh-issue-118750.7aLfT-.rst +++ /dev/null @@ -1 +0,0 @@ -If the C version of the ``decimal`` module is available, ``int(str)`` now uses it to supply an asymptotically much faster conversion. However, this only applies if the string contains over about 2 million digits. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-09-19-47-12.gh-issue-117657.Vn0Yey.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-09-19-47-12.gh-issue-117657.Vn0Yey.rst deleted file mode 100644 index db4c5813ca610c..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-09-19-47-12.gh-issue-117657.Vn0Yey.rst +++ /dev/null @@ -1 +0,0 @@ -Fix data races on the field that stores a pointer to the interpreter's main thread that occur in free-threaded builds. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-10-19-54-18.gh-issue-118921.O4ztZG.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-10-19-54-18.gh-issue-118921.O4ztZG.rst deleted file mode 100644 index 39ccf472067cfd..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-10-19-54-18.gh-issue-118921.O4ztZG.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``copy()`` method for ``FrameLocalsProxy`` which returns a snapshot ``dict`` for local variables. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-11-21-44-17.gh-issue-118844.q2H_km.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-11-21-44-17.gh-issue-118844.q2H_km.rst deleted file mode 100644 index 6e80b773889413..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-11-21-44-17.gh-issue-118844.q2H_km.rst +++ /dev/null @@ -1 +0,0 @@ -Fix build failures when configuring with both ``--disable-gil`` and ``--enable-experimental-jit``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-15-12-15-58.gh-issue-119057.P3G9G2.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-15-12-15-58.gh-issue-119057.P3G9G2.rst deleted file mode 100644 index d252888906c348..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-15-12-15-58.gh-issue-119057.P3G9G2.rst +++ /dev/null @@ -1,4 +0,0 @@ -Improve :exc:`ZeroDivisionError` error message. -Now, all error messages are harmonized: all ``/``, ``//``, and ``%`` -operations just use "division by zero" message. -And ``0 ** -1`` operation uses "zero to a negative power". diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-16-23-02-03.gh-issue-119049.qpd_S-.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-16-23-02-03.gh-issue-119049.qpd_S-.rst deleted file mode 100644 index 1d7aad8d1e5be6..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-16-23-02-03.gh-issue-119049.qpd_S-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix displaying the source line for warnings created by the C API if the -:mod:`warnings` module had not yet been imported. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-20-10-10-51.gh-issue-119180.35xqpu.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-20-10-10-51.gh-issue-119180.35xqpu.rst deleted file mode 100644 index 5a88ce097274fb..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-20-10-10-51.gh-issue-119180.35xqpu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add an ``__annotate__`` attribute to functions, classes, and modules as part -of :pep:`649`. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-20-14-57-39.gh-issue-118692.Qadm7F.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-20-14-57-39.gh-issue-118692.Qadm7F.rst deleted file mode 100644 index 11d177886df5b5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-20-14-57-39.gh-issue-118692.Qadm7F.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid creating unnecessary :exc:`StopIteration` instances for monitoring. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-21-09-46-51.gh-issue-119011.WOe3bu.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-21-09-46-51.gh-issue-119011.WOe3bu.rst deleted file mode 100644 index 0083c18da13278..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-21-09-46-51.gh-issue-119011.WOe3bu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixes ``type.__type_params__`` to return an empty tuple instead of a -descriptor. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-21-11-27-14.gh-issue-119213.nxjxrt.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-21-11-27-14.gh-issue-119213.nxjxrt.rst deleted file mode 100644 index e9073b4ba08798..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-21-11-27-14.gh-issue-119213.nxjxrt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Non-builtin modules built with argument clinic were crashing if used in a -subinterpreter before the main interpreter. The objects that were causing -the problem by leaking between interpreters carelessly have been fixed. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-21-12-17-02.gh-issue-119180.UNDUb9.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-21-12-17-02.gh-issue-119180.UNDUb9.rst deleted file mode 100644 index 54c6639e0fa524..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-21-12-17-02.gh-issue-119180.UNDUb9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Replace :opcode:`!LOAD_ASSERTION_ERROR` opcode with :opcode:`LOAD_COMMON_CONSTANT` -and add support for :exc:`NotImplementedError`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-22-06-22-47.gh-issue-119180.vZMiXm.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-22-06-22-47.gh-issue-119180.vZMiXm.rst deleted file mode 100644 index 265ffb32e6a1f9..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-22-06-22-47.gh-issue-119180.vZMiXm.rst +++ /dev/null @@ -1 +0,0 @@ -Evaluation of annotations is now deferred. See :pep:`649` for details. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-22-12-49-03.gh-issue-119372.PXig1R.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-22-12-49-03.gh-issue-119372.PXig1R.rst deleted file mode 100644 index aa628299abbd95..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-22-12-49-03.gh-issue-119372.PXig1R.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correct invalid corner cases in complex division (resulted in ``(nan+nanj)`` -output), e.g. ``1/complex('(inf+infj)')``. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-14.gh-issue-119395.z-Hsqb.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-14.gh-issue-119395.z-Hsqb.rst deleted file mode 100644 index 24cd90a8e5e5db..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-14.gh-issue-119395.z-Hsqb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where names appearing after a generic class are mangled as if they -are in the generic class. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-45.gh-issue-119311.2DBwKR.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-45.gh-issue-119311.2DBwKR.rst deleted file mode 100644 index 9e0db37340c49a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-23-06-34-45.gh-issue-119311.2DBwKR.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where names are unexpectedly mangled in the bases of generic -classes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-23-20-17-37.gh-issue-119258.wZFIpt.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-23-20-17-37.gh-issue-119258.wZFIpt.rst deleted file mode 100644 index 68f1ec1efa5751..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-23-20-17-37.gh-issue-119258.wZFIpt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Eliminate type version guards in the tier two interpreter. - -Note that setting the ``tp_version_tag`` manually (which has never been supported) may result in crashes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-04-00.gh-issue-119525.zLFLf1.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-04-00.gh-issue-119525.zLFLf1.rst deleted file mode 100644 index 83c29a16e572d7..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-04-00.gh-issue-119525.zLFLf1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix deadlock involving ``_PyType_Lookup()`` cache in the free-threaded build -when the GIL is dynamically enabled at runtime. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-16-52.gh-issue-119369.qBThho.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-16-52.gh-issue-119369.qBThho.rst deleted file mode 100644 index 7abdd5cd85ccd6..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-24-21-16-52.gh-issue-119369.qBThho.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix deadlock during thread deletion in free-threaded build, which could -occur when the GIL was enabled at runtime. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-25-12-52-25.gh-issue-119560.wSlm8q.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-25-12-52-25.gh-issue-119560.wSlm8q.rst deleted file mode 100644 index 3a28a94df0f7cf..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-25-12-52-25.gh-issue-119560.wSlm8q.rst +++ /dev/null @@ -1,3 +0,0 @@ -An invalid assert in beta 1 has been removed. The assert would fail if -``PyState_FindModule()`` was used in an extension module's init function -before the module def had been initialized. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-25-13-51-48.gh-issue-111999.L0q1gh.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-25-13-51-48.gh-issue-111999.L0q1gh.rst deleted file mode 100644 index 4b1ca6ca5b0765..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-25-13-51-48.gh-issue-111999.L0q1gh.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the signature of :meth:`str.format_map`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-25-16-45-27.gh-issue-119548.pqF9Y6.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-25-16-45-27.gh-issue-119548.pqF9Y6.rst deleted file mode 100644 index 0318790d46f0a3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-25-16-45-27.gh-issue-119548.pqF9Y6.rst +++ /dev/null @@ -1 +0,0 @@ -Add a ``clear`` command to the REPL. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-27-19-13-49.gh-issue-109218.-sdDg0.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-27-19-13-49.gh-issue-109218.-sdDg0.rst deleted file mode 100644 index db762174a8c1e1..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-27-19-13-49.gh-issue-109218.-sdDg0.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`complex` accepts now a string only as a positional argument. Passing -a complex number as the "real" or "imag" argument is deprecated; it should -only be passed as a single positional argument. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-28-22-49-56.gh-issue-119689.VwLFD5.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-28-22-49-56.gh-issue-119689.VwLFD5.rst deleted file mode 100644 index 56be31326216eb..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-28-22-49-56.gh-issue-119689.VwLFD5.rst +++ /dev/null @@ -1 +0,0 @@ -Generate stack effect metadata for pseudo instructions from bytecodes.c. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst deleted file mode 100644 index 111e096d262ea0..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-29-18-53-43.gh-issue-119740.zP2JNM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove the previously-deprecated delegation of :func:`int` to -:meth:`~object.__trunc__`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-30-04-11-36.gh-issue-118934.fbDqve.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-30-04-11-36.gh-issue-118934.fbDqve.rst deleted file mode 100644 index 3087034fe458b8..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-30-04-11-36.gh-issue-118934.fbDqve.rst +++ /dev/null @@ -1 +0,0 @@ -Make ``PyEval_GetLocals`` return borrowed reference diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-30-23-01-00.gh-issue-119821.jPGfvt.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-30-23-01-00.gh-issue-119821.jPGfvt.rst deleted file mode 100644 index cc25eee6dd6ae4..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-30-23-01-00.gh-issue-119821.jPGfvt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix execution of :ref:`annotation scopes ` within classes -when ``globals`` is set to a non-dict. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst deleted file mode 100644 index 567c096472878f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-31-08-23-41.gh-issue-119180.KL4VxZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`classmethod` and :func:`staticmethod` now wrap the -:attr:`~object.__annotations__` and :attr:`~object.__annotate__` attributes of -their underlying callable lazily. See :pep:`649`. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-31-12-06-11.gh-issue-119842.tCGVsv.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-31-12-06-11.gh-issue-119842.tCGVsv.rst deleted file mode 100644 index 2fcb170f6226e5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-05-31-12-06-11.gh-issue-119842.tCGVsv.rst +++ /dev/null @@ -1 +0,0 @@ -Honor :c:func:`PyOS_InputHook` in the new REPL. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-02-06-12-35.gh-issue-119879.Jit951.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-02-06-12-35.gh-issue-119879.Jit951.rst deleted file mode 100644 index 89de6b0299a35a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-02-06-12-35.gh-issue-119879.Jit951.rst +++ /dev/null @@ -1 +0,0 @@ -String search is now slightly faster for certain cases. It now utilizes last character gap (good suffix rule) for two-way periodic needles. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-25-04.gh-issue-119724.EH1dkA.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-25-04.gh-issue-119724.EH1dkA.rst deleted file mode 100644 index 78dc48da934cf6..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-25-04.gh-issue-119724.EH1dkA.rst +++ /dev/null @@ -1,3 +0,0 @@ -Reverted improvements to error messages for ``elif``/``else`` statements not -matching any valid statements, which made in hard to locate the syntax -errors inside those ``elif``/``else`` blocks. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst deleted file mode 100644 index 513a0200dcc48a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-03-13-48-44.gh-issue-119933.Kc0HG5.rst +++ /dev/null @@ -1,4 +0,0 @@ -Improve :exc:`SyntaxError` messages for invalid expressions in a type -parameters bound, a type parameter constraint tuple or a default type -parameter. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-05-08-39-40.gh-issue-120080.DJFK11.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-05-08-39-40.gh-issue-120080.DJFK11.rst deleted file mode 100644 index 8c5602fcdb4ad2..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-05-08-39-40.gh-issue-120080.DJFK11.rst +++ /dev/null @@ -1,2 +0,0 @@ -Direct call to the :meth:`!int.__round__` now accepts ``None`` -as a valid argument. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-05-10-32-44.gh-issue-120097.9S2klk.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-05-10-32-44.gh-issue-120097.9S2klk.rst deleted file mode 100644 index 39d829bb0ed310..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-05-10-32-44.gh-issue-120097.9S2klk.rst +++ /dev/null @@ -1,2 +0,0 @@ -``FrameLocalsProxy`` now subclasses ``collections.abc.Mapping`` and can be -matched as a mapping in ``match`` statements diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst deleted file mode 100644 index c06d5a276c03eb..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst +++ /dev/null @@ -1 +0,0 @@ -Fix source locations of instructions generated for with statements. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-07-16-09-04.gh-issue-120225.kuYf9t.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-07-16-09-04.gh-issue-120225.kuYf9t.rst deleted file mode 100644 index d00b9aaa8192e3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-07-16-09-04.gh-issue-120225.kuYf9t.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash in compiler on empty block at end of exception handler. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-07-22-54-15.gh-issue-119726.D9EE-o.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-07-22-54-15.gh-issue-119726.D9EE-o.rst deleted file mode 100644 index 595d8dda25fe1b..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-07-22-54-15.gh-issue-119726.D9EE-o.rst +++ /dev/null @@ -1 +0,0 @@ -JIT: Re-use trampolines on AArch64 when creating stencils. Patch by Diego Russo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-09-19-13-38.gh-issue-119666.S0G4rZ.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-09-19-13-38.gh-issue-119666.S0G4rZ.rst deleted file mode 100644 index 09c1f553c48702..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-09-19-13-38.gh-issue-119666.S0G4rZ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a compiler crash in the case where two comprehensions in class scope both reference ``__class__``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst deleted file mode 100644 index 2872006ee34b8b..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix use-after free in ``list_richcompare_impl`` which can be invoked via -some specifically tailored evil input. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst deleted file mode 100644 index 8dc8aec44d80c4..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash when multiple threads read and write to the same ``__class__`` of an object concurrently. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-10-22-30-26.gh-issue-93691.68WOTS.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-10-22-30-26.gh-issue-93691.68WOTS.rst deleted file mode 100644 index 294f8d892b459b..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-10-22-30-26.gh-issue-93691.68WOTS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix source locations of instructions generated for the iterator of a for -statement. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-11-12-47-54.gh-issue-120346.hhn_6X.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-11-12-47-54.gh-issue-120346.hhn_6X.rst deleted file mode 100644 index 757a21625cfb83..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-11-12-47-54.gh-issue-120346.hhn_6X.rst +++ /dev/null @@ -1,2 +0,0 @@ -Respect :envvar:`PYTHON_BASIC_REPL` when running in interactive inspect mode -(``python -i``). Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-11-17-56-12.gh-issue-120221.si9hM9.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-11-17-56-12.gh-issue-120221.si9hM9.rst deleted file mode 100644 index 3781576bc5a257..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-11-17-56-12.gh-issue-120221.si9hM9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deliver real signals on Ctrl-C and Ctrl-Z in the new REPL. Patch by Pablo -Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-12-13-47-25.gh-issue-120397.n-I_cc.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-12-13-47-25.gh-issue-120397.n-I_cc.rst deleted file mode 100644 index 24f046d9d89d51..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-12-13-47-25.gh-issue-120397.n-I_cc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the throughput by up to two times for the :meth:`str.count`, :meth:`bytes.count` and :meth:`bytearray.count` -methods for counting single characters. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-23-15.gh-issue-120380.edtqjq.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-23-15.gh-issue-120380.edtqjq.rst deleted file mode 100644 index c682a0b7666416..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-23-15.gh-issue-120380.edtqjq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix Python implementation of :class:`pickle.Pickler` for :class:`bytes` and -:class:`bytearray` objects when using protocol version 5. Patch by Bénédikt -Tran. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst deleted file mode 100644 index 2d7212a66f7a84..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-12-18-50-29.gh-issue-120367.LmXx2y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash in compiler on code with redundant NOPs and JUMPs which show up -after exception handlers are moved to the end of the code. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst deleted file mode 100644 index 65959ca2d28075..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an array out of bounds crash in ``list_ass_subscript``, which could be -invoked via some specifically tailored input: including concurrent modification -of a list object, where one thread assigns a slice and another clears it. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-14-07-52-00.gh-issue-120485.yy4K4b.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-14-07-52-00.gh-issue-120485.yy4K4b.rst deleted file mode 100644 index f41c233908362f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-14-07-52-00.gh-issue-120485.yy4K4b.rst +++ /dev/null @@ -1 +0,0 @@ -Add an override of ``allow_reuse_port`` on classes subclassing ``socketserver.TCPServer`` where ``allow_reuse_address`` is also overridden. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-14-22-02-25.gh-issue-113993.MiA0vX.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-14-22-02-25.gh-issue-113993.MiA0vX.rst deleted file mode 100644 index 9931787cb36d4c..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-14-22-02-25.gh-issue-113993.MiA0vX.rst +++ /dev/null @@ -1,5 +0,0 @@ -Strings interned with :func:`sys.intern` are again garbage-collected when no -longer used, as per the documentation. Strings interned with the C function -:c:func:`PyUnicode_InternInPlace` are still immortal. Internals of the -string interning mechanism have been changed. This may affect performance -and identities of :class:`str` objects. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-17-12-20-20.gh-issue-120507.94lz2J.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-17-12-20-20.gh-issue-120507.94lz2J.rst deleted file mode 100644 index c12e104fa68e70..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-17-12-20-20.gh-issue-120507.94lz2J.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the ``BEFORE_WITH`` and ``BEFORE_ASYNC_WITH`` -instructions. Add the new :opcode:`LOAD_SPECIAL` instruction. Generate code -for ``with`` and ``async with`` statements using the new instruction. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-18-21-34-30.gh-issue-120367.zDwffP.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-18-21-34-30.gh-issue-120367.zDwffP.rst deleted file mode 100644 index 087640e5400b98..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-18-21-34-30.gh-issue-120367.zDwffP.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where compiler creates a redundant jump during pseudo-op replacement. Can only happen with a synthetic AST that has a try on the same line as the instruction following the exception handler. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-18-22-41-05.gh-issue-120722.rS7tkE.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-18-22-41-05.gh-issue-120722.rS7tkE.rst deleted file mode 100644 index df83e69c601a32..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-18-22-41-05.gh-issue-120722.rS7tkE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly set the bytecode position on return instructions within lambdas. -Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst deleted file mode 100644 index 8923f3fcefe3c1..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-01-58-54.gh-issue-120437.nCkIoI.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``_CHECK_STACK_SPACE`` optimization problems introduced in :gh:`118322`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-11-10-50.gh-issue-119462.DpcqSe.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-11-10-50.gh-issue-119462.DpcqSe.rst deleted file mode 100644 index 7a3b74b63b2e40..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-11-10-50.gh-issue-119462.DpcqSe.rst +++ /dev/null @@ -1,4 +0,0 @@ -Make sure that invariants of type versioning are maintained: -* Superclasses always have their version number assigned before subclasses -* The version tag is always zero if the tag is not valid. -* The version tag is always non-if the tag is valid. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-19-54-35.gh-issue-120754.uF29sj.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-19-54-35.gh-issue-120754.uF29sj.rst deleted file mode 100644 index 46481d8f31aaba..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-19-54-35.gh-issue-120754.uF29sj.rst +++ /dev/null @@ -1 +0,0 @@ -Reduce the number of system calls invoked when reading a whole file (ex. ``open('a.txt').read()``). For a sample program that reads the contents of the 400+ ``.rst`` files in the cpython repository ``Doc`` folder, there is an over 10% reduction in system call count. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-21-34-21.gh-issue-98442.cqhjkN.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-19-21-34-21.gh-issue-98442.cqhjkN.rst deleted file mode 100644 index fb0a93f41a583f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-19-21-34-21.gh-issue-98442.cqhjkN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix too wide source locations of the cleanup instructions of a with -statement. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-24-08-39-23.gh-issue-116017.-Bw2UY.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-24-08-39-23.gh-issue-116017.-Bw2UY.rst deleted file mode 100644 index 3ca1b37f701e46..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-24-08-39-23.gh-issue-116017.-Bw2UY.rst +++ /dev/null @@ -1,3 +0,0 @@ -Simplify the warmup mechanism used for "side exits" in JIT code, resulting -in slightly better performance and slightly lower memory usage for most -platforms. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-25-16-26-44.gh-issue-119726.WqvHxB.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-25-16-26-44.gh-issue-119726.WqvHxB.rst deleted file mode 100644 index 2e5132f61e504f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-25-16-26-44.gh-issue-119726.WqvHxB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the speed and memory use of C function calls from JIT code on AArch64. -Patch by Diego Russo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-26-13-42-36.gh-issue-113433.xKAtLB.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-26-13-42-36.gh-issue-113433.xKAtLB.rst deleted file mode 100644 index bf8377ac488bcc..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-26-13-42-36.gh-issue-113433.xKAtLB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Subinterpreters now get cleaned up automatically during runtime -finalization. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-26-14-09-31.gh-issue-120838.nFeTL9.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-26-14-09-31.gh-issue-120838.nFeTL9.rst deleted file mode 100644 index 057d00aeeaba11..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-26-14-09-31.gh-issue-120838.nFeTL9.rst +++ /dev/null @@ -1,2 +0,0 @@ -:c:func:`Py_Finalize()` and :c:func:`Py_FinalizeEx()` now always run with -the main interpreter active. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-28-10-02-58.gh-issue-121115.EeSLfc.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-28-10-02-58.gh-issue-121115.EeSLfc.rst deleted file mode 100644 index aaecc873551cc7..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-28-10-02-58.gh-issue-121115.EeSLfc.rst +++ /dev/null @@ -1,3 +0,0 @@ -:c:func:`PyLong_AsNativeBytes` no longer uses :meth:`~object.__index__` -methods by default. The ``Py_ASNATIVEBYTES_ALLOW_INDEX`` flag has been added -to allow it. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-28-18-34-49.gh-issue-119726.Fjv_Ab.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-28-18-34-49.gh-issue-119726.Fjv_Ab.rst deleted file mode 100644 index cf5d61450aa3ae..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-28-18-34-49.gh-issue-119726.Fjv_Ab.rst +++ /dev/null @@ -1,2 +0,0 @@ -Optimize code layout for calls to C functions from the JIT on AArch64. -Patch by Diego Russo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst deleted file mode 100644 index 3a02145378e2cd..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove ``subprocess._USE_VFORK`` escape hatch code and documentation. -It was added just in case, and doesn't have any known cases that require it. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-29-10-46-14.gh-issue-121130.Rj66Xs.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-29-10-46-14.gh-issue-121130.Rj66Xs.rst deleted file mode 100644 index 7084f0cbebbb73..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-29-10-46-14.gh-issue-121130.Rj66Xs.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix f-strings with debug expressions in format specifiers. Patch by Pablo -Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-30-03-48-10.gh-issue-121149.lLBMKe.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-30-03-48-10.gh-issue-121149.lLBMKe.rst deleted file mode 100644 index 38d618f06090fd..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-06-30-03-48-10.gh-issue-121149.lLBMKe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added specialization for summation of complexes, this also improves accuracy -of builtin :func:`sum` for such inputs. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-04-23-38-30.gh-issue-121368.m3EF9E.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-04-23-38-30.gh-issue-121368.m3EF9E.rst deleted file mode 100644 index 3df5b216cbc0af..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-04-23-38-30.gh-issue-121368.m3EF9E.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix race condition in ``_PyType_Lookup`` in the free-threaded build due to -a missing memory fence. This could lead to ``_PyType_Lookup`` returning -incorrect results on arm64. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-05-11-29-27.gh-issue-121288.lYKYYP.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-05-11-29-27.gh-issue-121288.lYKYYP.rst deleted file mode 100644 index ffe8f373c905e1..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-05-11-29-27.gh-issue-121288.lYKYYP.rst +++ /dev/null @@ -1,5 +0,0 @@ -:exc:`ValueError` messages for :meth:`!list.index`, :meth:`!range.index`, -:meth:`!deque.index`, :meth:`!deque.remove` and -:meth:`!ShareableList.index` no longer contain the repr of the searched -value (which can be arbitrary large) and are consistent with error messages -for other :meth:`!index` and :meth:`!remove` methods. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-08-02-24-55.gh-issue-121439.jDHod3.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-08-02-24-55.gh-issue-121439.jDHod3.rst deleted file mode 100644 index 361f9fc71186c6..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-08-02-24-55.gh-issue-121439.jDHod3.rst +++ /dev/null @@ -1 +0,0 @@ -Allow tuples of length 20 in the freelist to be reused. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-08-10-31-08.gh-issue-121012.M5hHk-.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-08-10-31-08.gh-issue-121012.M5hHk-.rst deleted file mode 100644 index 7b04eb68b03752..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-08-10-31-08.gh-issue-121012.M5hHk-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Tier 2 execution now ensures that list iterators remain exhausted, once they -become exhausted. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-08-17-15-14.gh-issue-121497.I8hMDC.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-08-17-15-14.gh-issue-121497.I8hMDC.rst deleted file mode 100644 index 33de31abebe7c7..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-08-17-15-14.gh-issue-121497.I8hMDC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug that was preventing the REPL to correctly respect the history when -an input hook was set. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-09-13-53-18.gh-issue-121499.rpp7il.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-09-13-53-18.gh-issue-121499.rpp7il.rst deleted file mode 100644 index aec8ab9d4662b5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-09-13-53-18.gh-issue-121499.rpp7il.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug affecting how multi-line history was being rendered in the new -REPL after interacting with the new screen cache. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-10-02-02-32.gh-issue-121562.8beIMi.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-10-02-02-32.gh-issue-121562.8beIMi.rst deleted file mode 100644 index 940380971f407f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-10-02-02-32.gh-issue-121562.8beIMi.rst +++ /dev/null @@ -1,2 +0,0 @@ -Optimized performance of hex_from_char by replacing switch-case with a -lookup table diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst deleted file mode 100644 index ec1e7327b77f19..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst +++ /dev/null @@ -1,2 +0,0 @@ -Unexpected slot wrappers are no longer created for builtin static types in -subinterpreters. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst deleted file mode 100644 index 25aae6c8c5cb10..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst +++ /dev/null @@ -1,4 +0,0 @@ -Previously, incorrect usage of :keyword:`await` or asynchronous -comprehensions in code removed by the :option:`-O` option was not flagged by -the Python compiler. Now, such code raises :exc:`SyntaxError`. Patch by -Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-13-12-27-31.gh-issue-121657.wgOYLw.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-13-12-27-31.gh-issue-121657.wgOYLw.rst deleted file mode 100644 index cb18629d79f5ce..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-13-12-27-31.gh-issue-121657.wgOYLw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the :exc:`SyntaxError` message if the user tries to use -:keyword:`yield from ` outside a function. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-15-16-26-32.gh-issue-121794.fhBtiQ.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-15-16-26-32.gh-issue-121794.fhBtiQ.rst deleted file mode 100644 index 979efa0a0a1597..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-15-16-26-32.gh-issue-121794.fhBtiQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug in free-threaded Python where a resurrected object could lead to -a negative ref count assertion failure. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-15-20-41-06.gh-issue-121814.oR2ixR.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-15-20-41-06.gh-issue-121814.oR2ixR.rst deleted file mode 100644 index 14666de45f32e3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-15-20-41-06.gh-issue-121814.oR2ixR.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed the SegFault when :c:func:`PyEval_SetTrace` is used with no Python frame on stack. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-16-15-11-51.gh-issue-121795.xkIHrI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-16-15-11-51.gh-issue-121795.xkIHrI.rst deleted file mode 100644 index b4102649c56758..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-16-15-11-51.gh-issue-121795.xkIHrI.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of set membership testing, ``set.remove()`` and ``set.discard()`` when the argument is a set. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst deleted file mode 100644 index a03ee83d6f8ec9..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when rematerializing a managed dictionary after it was deleted. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-19-09-38-01.gh-issue-99108.qzM6gl.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-19-09-38-01.gh-issue-99108.qzM6gl.rst deleted file mode 100644 index 125f04a36a18c9..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-19-09-38-01.gh-issue-99108.qzM6gl.rst +++ /dev/null @@ -1,10 +0,0 @@ -Python's hashlib now unconditionally uses the vendored HACL* library for -Blake2. Python no longer accepts libb2 as an optional dependency for Blake2. - -We refreshed HACL* to the latest version, and now vendor HACL*'s 128-bit and -256-bit wide vector implementations for Blake2, which are used on x86/x64 -toolchains when the required CPU features are available at runtime. - -HACL*'s 128-bit wide vector implementation of Blake2 can also run on ARM -NEON and Power8, but lacking evidence of a performance gain, these are not -enabled (yet). diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-19-15-28-05.gh-issue-122026.sta2Ca.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-19-15-28-05.gh-issue-122026.sta2Ca.rst deleted file mode 100644 index 2721a405a50446..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-19-15-28-05.gh-issue-122026.sta2Ca.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug that caused the tokenizer to not correctly identify mismatched -parentheses inside f-strings in some situations. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst deleted file mode 100644 index bddee3a57fba80..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-21-01-23-54.gh-issue-122029.gKv-e2.rst +++ /dev/null @@ -1 +0,0 @@ -Emit ``c_call`` events in :func:`sys.setprofile` when a ``PyMethodObject`` pointing to a ``PyCFunction`` is called. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-23-11-57-36.gh-issue-122160.HSnrAP.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-23-11-57-36.gh-issue-122160.HSnrAP.rst deleted file mode 100644 index 78153fc1abdaeb..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-23-11-57-36.gh-issue-122160.HSnrAP.rst +++ /dev/null @@ -1 +0,0 @@ -Remove the ``BUILD_CONST_KEY_MAP`` opcode. Use :opcode:`BUILD_MAP` instead. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-23-23-59-04.gh-issue-122208.z8KHsY.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-23-23-59-04.gh-issue-122208.z8KHsY.rst deleted file mode 100644 index e4a89d137ede0e..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-23-23-59-04.gh-issue-122208.z8KHsY.rst +++ /dev/null @@ -1 +0,0 @@ -Dictionary watchers now only deliver the PyDict_EVENT_ADDED event when the insertion is in a known good state to succeed. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst deleted file mode 100644 index 5a9a82ddef6ee4..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst +++ /dev/null @@ -1,4 +0,0 @@ -Specializations for sums with float and complex inputs in :func:`sum` now -always use compensated summation. Also, for integer items in above -specializations: :c:func:`PyLong_AsDouble` is used, instead of -:c:func:`PyLong_AsLongAndOverflow`. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-24-22-39-07.gh-issue-122245.LVa9v8.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-24-22-39-07.gh-issue-122245.LVa9v8.rst deleted file mode 100644 index fff99b4992e321..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-24-22-39-07.gh-issue-122245.LVa9v8.rst +++ /dev/null @@ -1,4 +0,0 @@ -Detection of writes to ``__debug__`` is moved from the compiler's codegen -stage to the symtable. This means that these errors are now detected even in -code that is optimized away before codegen (such as assertions with the -:option:`-O` command line option). diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-26-14-05-51.gh-issue-122300.SVIF-l.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-26-14-05-51.gh-issue-122300.SVIF-l.rst deleted file mode 100644 index 6b58f89247d1d4..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-26-14-05-51.gh-issue-122300.SVIF-l.rst +++ /dev/null @@ -1,2 +0,0 @@ -Preserve AST nodes for f-string with single-element format specifiers. Patch -by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-30-11-41-35.gh-issue-122445.Rq0bjS.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-30-11-41-35.gh-issue-122445.Rq0bjS.rst deleted file mode 100644 index cb9dabbc71706f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-30-11-41-35.gh-issue-122445.Rq0bjS.rst +++ /dev/null @@ -1 +0,0 @@ -Add only fields which are modified via self.* to :attr:`~type.__static_attributes__`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-05-19-04-06.gh-issue-116622.3LWUzE.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-05-19-04-06.gh-issue-116622.3LWUzE.rst deleted file mode 100644 index 9320928477af2c..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-05-19-04-06.gh-issue-116622.3LWUzE.rst +++ /dev/null @@ -1 +0,0 @@ -Fix Android stdout and stderr messages being truncated or lost. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-18-18-25-54.gh-issue-123123.0ZcaEB.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-18-18-25-54.gh-issue-123123.0ZcaEB.rst deleted file mode 100644 index 824d307bb270a2..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-18-18-25-54.gh-issue-123123.0ZcaEB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix displaying :exc:`SyntaxError` exceptions covering multiple lines. Patch -by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-20-11-09-16.gh-issue-123048.2TISpv.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-20-11-09-16.gh-issue-123048.2TISpv.rst deleted file mode 100644 index f0b756febbc1b8..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-20-11-09-16.gh-issue-123048.2TISpv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug where pattern matching code could emit a :opcode:`JUMP_FORWARD` -with no source location. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-20-12-29-52.gh-issue-123142.3PXiNb.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-20-12-29-52.gh-issue-123142.3PXiNb.rst deleted file mode 100644 index 0aa70f23bfde87..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-20-12-29-52.gh-issue-123142.3PXiNb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix too-wide source location in exception tracebacks coming from broken -iterables in comprehensions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-21-15-22-53.gh-issue-121804.r5K3PS.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-21-15-22-53.gh-issue-121804.r5K3PS.rst deleted file mode 100644 index ce96c316923ce5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-21-15-22-53.gh-issue-121804.r5K3PS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly show error locations when a :exc:`SyntaxError` is raised -in the basic REPL. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-23-13-08-27.gh-issue-123229.aHm-dw.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-23-13-08-27.gh-issue-123229.aHm-dw.rst deleted file mode 100644 index aa9e8d1fa93bf5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-23-13-08-27.gh-issue-123229.aHm-dw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix valgrind warning by initializing the f-string buffers to 0 in the -tokenizer. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-23-15-59-54.gh-issue-123177.OLcaC5.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-23-15-59-54.gh-issue-123177.OLcaC5.rst deleted file mode 100644 index da688effca3712..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-23-15-59-54.gh-issue-123177.OLcaC5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deactivate line wrap in the Apple Terminal via a ANSI escape code. Patch by -Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-25-10-54-22.gh-issue-122982.KLD91q.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-25-10-54-22.gh-issue-122982.KLD91q.rst deleted file mode 100644 index 64882df6af10d2..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-25-10-54-22.gh-issue-122982.KLD91q.rst +++ /dev/null @@ -1 +0,0 @@ -Extend the deprecation period for bool inversion (``~``) by two years. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-26-00-58-26.gh-issue-123321.ApxcnE.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-26-00-58-26.gh-issue-123321.ApxcnE.rst deleted file mode 100644 index b0547e0e588e3d..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-26-00-58-26.gh-issue-123321.ApxcnE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Prevent Parser/myreadline race condition from segfaulting on multi-threaded -use. Patch by Bar Harel and Amit Wienner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-27-13-16-40.gh-issue-123344.56Or78.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-27-13-16-40.gh-issue-123344.56Or78.rst deleted file mode 100644 index b8b373d48b6522..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-08-27-13-16-40.gh-issue-123344.56Or78.rst +++ /dev/null @@ -1 +0,0 @@ -Add AST optimizations for type parameter defaults. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-09-23-23-06-19.gh-issue-124285.mahGTg.rst b/Misc/NEWS.d/next/Core and Builtins/2024-09-23-23-06-19.gh-issue-124285.mahGTg.rst deleted file mode 100644 index a6dec66a743f92..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-09-23-23-06-19.gh-issue-124285.mahGTg.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where ``bool(a)`` can be invoked more than once during the -evaluation of a compound boolean expression. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst b/Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst deleted file mode 100644 index 185cb3048fadf5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-10-03-22-26-39.gh-issue-124871.tAMF47.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix compiler bug (in some versions of 3.13) where an assertion fails during reachability -analysis. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst deleted file mode 100644 index 72b5c071a5c67b..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst +++ /dev/null @@ -1 +0,0 @@ -Fix pasting of characters containing unicode character joiners in the new REPL. Patch by Marta Gomez Macias diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst deleted file mode 100644 index 7fca7d5461d39b..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix PyREPL console getting into a blocked state after interrupting a long -paste diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-18-21-19-04.gh-issue-121999.8IBbTK.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-18-21-19-04.gh-issue-121999.8IBbTK.rst deleted file mode 100644 index e65aa993566446..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-18-21-19-04.gh-issue-121999.8IBbTK.rst +++ /dev/null @@ -1,2 +0,0 @@ -The default extraction filter for the :mod:`tarfile` module is now -set to :func:`'data' `. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst deleted file mode 100644 index 3e8116ba7d28f1..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst +++ /dev/null @@ -1,3 +0,0 @@ -When a :class:`list`, :class:`tuple` or :class:`dict` -with too many elements is unpacked, show the actual -length in the error message. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-13-56-32.gh-issue-120906.qBh2I9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-13-56-32.gh-issue-120906.qBh2I9.rst deleted file mode 100644 index 2b753bc37d4a39..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-13-56-32.gh-issue-120906.qBh2I9.rst +++ /dev/null @@ -1 +0,0 @@ -:attr:`frame.f_locals` now supports arbitrary hashable objects as keys. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-10-55-46.gh-issue-116090.p1MhU0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-10-55-46.gh-issue-116090.p1MhU0.rst deleted file mode 100644 index 6efb620961f498..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-10-55-46.gh-issue-116090.p1MhU0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue in JIT builds that prevented some :keyword:`for` loops from -correctly firing :monitoring-event:`RAISE` monitoring events. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-19-20-25.gh-issue-122417.NVgs0a.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-19-20-25.gh-issue-122417.NVgs0a.rst deleted file mode 100644 index b050c9ce39c054..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-29-19-20-25.gh-issue-122417.NVgs0a.rst +++ /dev/null @@ -1,4 +0,0 @@ -In the free-threaded build, the reference counts for heap type objects are now -partially stored in a distributed manner in per-thread arrays. This reduces -contention on the heap type's reference count fields when creating or -destroying instances of the same type from multiple threads concurrently. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-01-19-13-58.gh-issue-122527.eztso6.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-01-19-13-58.gh-issue-122527.eztso6.rst deleted file mode 100644 index f697ed99d0c523..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-01-19-13-58.gh-issue-122527.eztso6.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a crash that occurred when a ``PyStructSequence`` was deallocated after -its type's dictionary was cleared by the GC. The type's -:c:member:`~PyTypeObject.tp_basicsize` now accounts for non-sequence fields -that aren't included in the :c:macro:`Py_SIZE` of the sequence. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-05-19-28-12.gh-issue-122697.17MvYl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-05-19-28-12.gh-issue-122697.17MvYl.rst deleted file mode 100644 index 34ee6a916bcf33..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-05-19-28-12.gh-issue-122697.17MvYl.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed memory leaks at interpreter shutdown in the free-threaded build, and -also reporting of leaked memory blocks via :option:`-X showrefcount <-X>`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-08-16-02-28.gh-issue-118093.m6Mrvy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-08-16-02-28.gh-issue-118093.m6Mrvy.rst deleted file mode 100644 index dacc7275d3d6dd..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-08-16-02-28.gh-issue-118093.m6Mrvy.rst +++ /dev/null @@ -1 +0,0 @@ -Improve the experimental JIT's handling of polymorphic code. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-10-12-44-03.gh-issue-122888.TUyu9r.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-10-12-44-03.gh-issue-122888.TUyu9r.rst deleted file mode 100644 index 93171360df0dda..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-10-12-44-03.gh-issue-122888.TUyu9r.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash on certain calls to ``str()`` with positional arguments of the -wrong type. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-19-37.gh-issue-122907.q68096.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-19-37.gh-issue-122907.q68096.rst deleted file mode 100644 index 88c872f4ef45f4..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-19-37.gh-issue-122907.q68096.rst +++ /dev/null @@ -1,3 +0,0 @@ -Building with ``HAVE_DYNAMIC_LOADING`` now works as well as it did in 3.12. -Existing deficiences will be addressed separately. -(See https://github.com/python/cpython/issues/122950.) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-45-47.gh-issue-122821.WnAzTK.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-45-47.gh-issue-122821.WnAzTK.rst deleted file mode 100644 index 4cf31054bd0ccd..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-12-11-45-47.gh-issue-122821.WnAzTK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make sure that branches in :keyword:`while` statements have consistent offsets for -:mod:`sys.monitoring`. :keyword:`!while` statements are now compiled with a simple -jump at the end of the body, instead of duplicating the test. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-14-11-38-56.gh-issue-118093.3BywDP.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-14-11-38-56.gh-issue-118093.3BywDP.rst deleted file mode 100644 index 4a3a094a6fc074..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-14-11-38-56.gh-issue-118093.3BywDP.rst +++ /dev/null @@ -1,5 +0,0 @@ -Add three specializations for :opcode:`CALL_KW`: - -* :opcode:`!CALL_KW_PY` for calls to Python functions -* :opcode:`!CALL_KW_BOUND_METHOD` for calls to bound methods -* :opcode:`!CALL_KW_NON_PY` for all other calls diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-15-19-28-43.gh-issue-123022.m3EF9E.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-15-19-28-43.gh-issue-123022.m3EF9E.rst deleted file mode 100644 index 47107dee44eec3..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-15-19-28-43.gh-issue-123022.m3EF9E.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash in free-threaded build when calling :c:func:`Py_Initialize` from -a non-main thread. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-17-17-26-25.gh-issue-123083.9xWLJ-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-17-17-26-25.gh-issue-123083.9xWLJ-.rst deleted file mode 100644 index edc3f1ab6a8e17..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-17-17-26-25.gh-issue-123083.9xWLJ-.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a potential use-after-free in ``STORE_ATTR_WITH_HINT``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-19-15-13-13.gh-issue-118093.dLZ8qS.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-19-15-13-13.gh-issue-118093.dLZ8qS.rst deleted file mode 100644 index d8127d8b5054fe..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-19-15-13-13.gh-issue-118093.dLZ8qS.rst +++ /dev/null @@ -1,3 +0,0 @@ -Break up ``CALL_ALLOC_AND_ENTER_INIT`` into micro-ops and relax -requirement for exact args, in order to increase the amount of code -supported by tier 2. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-21-08-53-00.gh-issue-115776.9A7Dv_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-21-08-53-00.gh-issue-115776.9A7Dv_.rst deleted file mode 100644 index 953ebd72382e1f..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-21-08-53-00.gh-issue-115776.9A7Dv_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Enables inline values (Python's equivalent of hidden classes) on any class -who's instances are of a fixed size. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-11-26-54.gh-issue-122298.ZMyln4.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-11-26-54.gh-issue-122298.ZMyln4.rst deleted file mode 100644 index 722f69616b6b1b..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-11-26-54.gh-issue-122298.ZMyln4.rst +++ /dev/null @@ -1,3 +0,0 @@ -Restore printout of GC stats when ``gc.set_debug(gc.DEBUG_STATS)`` is -called. This feature was accidentally removed when implementing incremental -GC. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-18-31-10.gh-issue-123275.DprIrj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-18-31-10.gh-issue-123275.DprIrj.rst deleted file mode 100644 index ab344a8ca40e47..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-18-31-10.gh-issue-123275.DprIrj.rst +++ /dev/null @@ -1 +0,0 @@ -Support :option:`-X gil=1 <-X>` and :envvar:`PYTHON_GIL=1 ` on non-free-threaded builds. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-21-20-34.gh-issue-123271.xeVViR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-21-20-34.gh-issue-123271.xeVViR.rst deleted file mode 100644 index 51fdec452c1d41..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-23-21-20-34.gh-issue-123271.xeVViR.rst +++ /dev/null @@ -1 +0,0 @@ -Make concurrent iterations over the same :func:`zip` iterator safe under free-threading. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-25-18-27-49.gh-issue-123177.yLuyqE.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-25-18-27-49.gh-issue-123177.yLuyqE.rst deleted file mode 100644 index 1f1791d9a6cf50..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-25-18-27-49.gh-issue-123177.yLuyqE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug causing stray prompts to appear in the middle of wrapped lines in -the new REPL. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-27-21-44-14.gh-issue-116017.ZY3yBY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-27-21-44-14.gh-issue-116017.ZY3yBY.rst deleted file mode 100644 index de62875e16475d..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-27-21-44-14.gh-issue-116017.ZY3yBY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improved JIT memory consumption by periodically freeing memory used by infrequently-executed code. -This change is especially likely to improve the memory footprint of long-running programs. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-28-22-42-51.gh-issue-123440.yOFB0N.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-28-22-42-51.gh-issue-123440.yOFB0N.rst deleted file mode 100644 index 0f2e49c10b0c64..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-28-22-42-51.gh-issue-123440.yOFB0N.rst +++ /dev/null @@ -1 +0,0 @@ -Improve :exc:`SyntaxError` message for using ``except as`` with not a name. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-13-18-18.gh-issue-123446.KWDrgq.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-13-18-18.gh-issue-123446.KWDrgq.rst deleted file mode 100644 index 704bde9d01cac9..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-13-18-18.gh-issue-123446.KWDrgq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix empty function name in :exc:`TypeError` when builtin magic methods are -used without the required args. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-19-46-07.gh-issue-123484.rjUn_F.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-19-46-07.gh-issue-123484.rjUn_F.rst deleted file mode 100644 index 3062e3684c8e78..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-08-29-19-46-07.gh-issue-123484.rjUn_F.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``_Py_DebugOffsets`` for long objects to be relative to the start of the -object rather than the start of a subobject. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-00-02-05.gh-issue-123545.8nQNbL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-00-02-05.gh-issue-123545.8nQNbL.rst deleted file mode 100644 index 4da4151416d13c..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-00-02-05.gh-issue-123545.8nQNbL.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a double decref in rare cases on experimental JIT builds. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-12-08-39.gh-issue-123562.aJPKVu.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-12-08-39.gh-issue-123562.aJPKVu.rst deleted file mode 100644 index 10ef82c9677d35..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-01-12-08-39.gh-issue-123562.aJPKVu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve :exc:`SyntaxError` message for using ``case ... as ...`` with not a -name. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-17-32-15.gh-issue-119034.HYh5Vj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-17-32-15.gh-issue-119034.HYh5Vj.rst deleted file mode 100644 index f528691e1b6f9f..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-17-32-15.gh-issue-119034.HYh5Vj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Change ```` and ```` keys of the Python REPL to history -search forward/backward. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-36-45.gh-issue-123339.QcmpSs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-36-45.gh-issue-123339.QcmpSs.rst deleted file mode 100644 index 25b47d5fbaefa5..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-36-45.gh-issue-123339.QcmpSs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Setting the :attr:`!__module__` attribute for a class now removes the -``__firstlineno__`` item from the type's dict, so they will no longer be -inconsistent. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-39-10.gh-issue-123614.26TMHp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-39-10.gh-issue-123614.26TMHp.rst deleted file mode 100644 index 64a5eac9f7840a..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-02-20-39-10.gh-issue-123614.26TMHp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :func:`turtle.save` to easily save Turtle drawings as PostScript files. -Patch by Marie Roald and Yngve Mardal Moe. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-03-13-34-35.gh-issue-123572.uuqoYV.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-03-13-34-35.gh-issue-123572.uuqoYV.rst deleted file mode 100644 index 38456ac60ca4ed..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-03-13-34-35.gh-issue-123572.uuqoYV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix key mappings for various F-keys in Windows for the new REPL. Patch by -devdanzin diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-14-13-01.gh-issue-119310.WQxyDF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-14-13-01.gh-issue-119310.WQxyDF.rst deleted file mode 100644 index e7bc24b537d46a..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-14-13-01.gh-issue-119310.WQxyDF.rst +++ /dev/null @@ -1,3 +0,0 @@ -Allow the new interactive shell to read history files written with the -editline library that use unicode-escaped entries. Patch by aorcajo and -Łukasz Langa. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-19-23-44.gh-issue-120221.giJEDT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-19-23-44.gh-issue-120221.giJEDT.rst deleted file mode 100644 index c562b87b02a852..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-06-19-23-44.gh-issue-120221.giJEDT.rst +++ /dev/null @@ -1,2 +0,0 @@ -asyncio REPL is now again properly recognizing KeyboardInterrupts. Display -of exceptions raised in secondary threads is fixed. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-13-27-16.gh-issue-77894.ZC-Olu.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-13-27-16.gh-issue-77894.ZC-Olu.rst deleted file mode 100644 index a714033dd296b9..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-13-27-16.gh-issue-77894.ZC-Olu.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix possible crash in the garbage collector when it tries to break a -reference loop containing a :class:`memoryview` object. Now a -:class:`!memoryview` object can only be cleared if there are no buffers that -refer it. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-20-25-00.gh-issue-123923.A7uxqa.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-20-25-00.gh-issue-123923.A7uxqa.rst deleted file mode 100644 index b7bc965b68b059..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-10-20-25-00.gh-issue-123923.A7uxqa.rst +++ /dev/null @@ -1,4 +0,0 @@ -The ``f_executable`` field in the internal :c:struct:`_PyInterpreterFrame` -struct now uses a tagged pointer. Profilers and debuggers that uses this -field should clear the least significant bit to recover the -:c:expr:`PyObject*` pointer. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-11-15-48-36.gh-issue-123958.5VW2r0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-11-15-48-36.gh-issue-123958.5VW2r0.rst deleted file mode 100644 index fc2623a7cbf789..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-11-15-48-36.gh-issue-123958.5VW2r0.rst +++ /dev/null @@ -1 +0,0 @@ -docstrings are now removed from the optimized AST in optimization level 2. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-12-21-53-26.gh-issue-124022.fQzUiW.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-12-21-53-26.gh-issue-124022.fQzUiW.rst deleted file mode 100644 index 90a77a5346d22b..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-12-21-53-26.gh-issue-124022.fQzUiW.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where docstring is removed from classes in interactive mode. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-13-02-25-06.gh-issue-124027.to_9DY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-13-02-25-06.gh-issue-124027.to_9DY.rst deleted file mode 100644 index 1834ba0ba08bfb..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-13-02-25-06.gh-issue-124027.to_9DY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support ````, ````, and ```` keys in the Python -REPL when ``$TERM`` is set to ``vt100``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-17-22-06-01.gh-issue-124188.aFqNAB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-17-22-06-01.gh-issue-124188.aFqNAB.rst deleted file mode 100644 index 0c2935fbe000bc..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-17-22-06-01.gh-issue-124188.aFqNAB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix reading and decoding a line from the source file witn non-UTF-8 encoding -for syntax errors raised in the compiler. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-13-17-31.gh-issue-122878.4iFpsB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-13-17-31.gh-issue-122878.4iFpsB.rst deleted file mode 100644 index 85dd0fd769be68..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-13-17-31.gh-issue-122878.4iFpsB.rst +++ /dev/null @@ -1 +0,0 @@ -Use the ``pager`` binary, if available (e.g. on Debian and derivatives), to display REPL ``help()``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-16-57-34.gh-issue-119726.DseseK.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-16-57-34.gh-issue-119726.DseseK.rst deleted file mode 100644 index c01eeff952534f..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-19-16-57-34.gh-issue-119726.DseseK.rst +++ /dev/null @@ -1,2 +0,0 @@ -The JIT now generates more efficient code for calls to C functions resulting -in up to 0.8% memory savings and 1.5% speed improvement on AArch64. Patch by Diego Russo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-13-25-27.gh-issue-65961.LDqXV2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-13-25-27.gh-issue-65961.LDqXV2.rst deleted file mode 100644 index d380027f3c5776..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-13-25-27.gh-issue-65961.LDqXV2.rst +++ /dev/null @@ -1 +0,0 @@ -Deprecate the setting and using ``__package__`` and ``__cached__``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-15-23-14.gh-issue-123856.yrgJ9m.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-15-23-14.gh-issue-123856.yrgJ9m.rst deleted file mode 100644 index b5f423f3ff1c96..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-23-15-23-14.gh-issue-123856.yrgJ9m.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix PyREPL failure when a keyboard interrupt is triggered after using a -history search diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-11-53-22.gh-issue-124442.EXC1Ve.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-11-53-22.gh-issue-124442.EXC1Ve.rst deleted file mode 100644 index 58e79f22ac0f90..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-11-53-22.gh-issue-124442.EXC1Ve.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix nondeterminism in compilation by sorting the value of -:attr:`~type.__static_attributes__`. Patch by kp2pml30. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-14-45-56.gh-issue-124513.ywiXtr.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-14-45-56.gh-issue-124513.ywiXtr.rst deleted file mode 100644 index 691e03b3b98e7a..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-14-45-56.gh-issue-124513.ywiXtr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in FrameLocalsProxy constructor: check the number of arguments. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.rst deleted file mode 100644 index 1005c651849f45..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.rst +++ /dev/null @@ -1,3 +0,0 @@ -When deallocating an object with inline values whose ``__dict__`` is still -live: if memory allocation for the inline values fails, clear the -dictionary. Prevents an interpreter crash. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-13-25-01.gh-issue-119180.k_JCX0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-13-25-01.gh-issue-119180.k_JCX0.rst deleted file mode 100644 index 4cdbb205c962c4..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-13-25-01.gh-issue-119180.k_JCX0.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``__main__`` module no longer always contains an ``__annotations__`` -dictionary in its global namespace. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-17-55-34.gh-issue-116510.dhn8w8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-17-55-34.gh-issue-116510.dhn8w8.rst deleted file mode 100644 index fc3f8af72d87bf..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-17-55-34.gh-issue-116510.dhn8w8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug that can cause a crash when sub-interpreters use "basic" -single-phase extension modules. Shared objects could refer to PyGC_Head -nodes that had been freed as part of interpreter cleanup. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst deleted file mode 100644 index e3741321006548..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-18-21-06.gh-issue-116510.FacUWO.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a crash caused by immortal interned strings being shared between -sub-interpreters that use basic single-phase init. In that case, the string -can be used by an interpreter that outlives the interpreter that created and -interned it. For interpreters that share obmalloc state, also share the -interned dict with the main interpreter. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-27-17-18-53.gh-issue-124642.OCjhBJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-27-17-18-53.gh-issue-124642.OCjhBJ.rst deleted file mode 100644 index 29763844a9f592..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-27-17-18-53.gh-issue-124642.OCjhBJ.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed scalability issue in free-threaded builds for lock-free reads from dictionaries in multi-threaded scenarios diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-16-39-37.gh-issue-118093.J2A3gz.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-16-39-37.gh-issue-118093.J2A3gz.rst deleted file mode 100644 index 2e5c64581b6aef..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-16-39-37.gh-issue-118093.J2A3gz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the experimental JIT compiler's ability to stay "on trace" when -encountering highly-biased branches. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst deleted file mode 100644 index 5cd34535d674d3..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-03-14-39-41.gh-issue-123378.dCxANf.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a crash in the :meth:`~object.__str__` method of :exc:`UnicodeError` -objects when the :attr:`UnicodeError.start` and :attr:`UnicodeError.end` -values are invalid or out-of-range. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst deleted file mode 100644 index 8971e052860225..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-05-23-53-06.gh-issue-125008.ETANpd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`tokenize.untokenize` producing invalid syntax for -double braces preceded by certain escape characters. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst deleted file mode 100644 index 93716c0b1c0df1..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-07-23-33-18.gh-issue-125039.MKTyNI.rst +++ /dev/null @@ -1 +0,0 @@ -Make ``this_instr`` and ``prev_instr`` const in cases generator. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst deleted file mode 100644 index c7eaac32601bb3..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-12-04-56.gh-issue-125174._8h6T7.rst +++ /dev/null @@ -1,4 +0,0 @@ -Make the handling of reference counts of immortal objects more robust. -Immortal objects with reference counts that deviate from their original -reference count by up to a billion (half a billion on 32 bit builds) are -still counted as immortal. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst deleted file mode 100644 index c79650c3a64feb..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix possible race condition when calling :meth:`~object.__reduce_ex__` for the -first time in the free threading build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst deleted file mode 100644 index 4bd17a6e683bc7..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-15-15-29-41.gh-issue-124375.wNrWVa.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash in the free threading build when the GC runs concurrently with a new thread starting. diff --git a/Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst b/Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst deleted file mode 100644 index a89086af35bfc1..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2018-07-04-20-35-25.bpo-34008.bqecIb.rst +++ /dev/null @@ -1,8 +0,0 @@ -The :c:func:`Py_Main` documentation moved from the "Very High Level API" section to the -"Initialization and Finalization" section. - -Also make it explicit that we expect ``Py_Main`` to typically be called instead -of ``Py_Initialize`` rather than after it (since ``Py_Main`` makes its own -call to ``Py_Initialize``). Document that calling both is -supported but is version dependent on which settings -will be applied correctly. diff --git a/Misc/NEWS.d/next/Documentation/2024-06-03-22-06-26.gh-issue-119574.Ik9kOO.rst b/Misc/NEWS.d/next/Documentation/2024-06-03-22-06-26.gh-issue-119574.Ik9kOO.rst deleted file mode 100644 index 902e7c17fc2e9d..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-06-03-22-06-26.gh-issue-119574.Ik9kOO.rst +++ /dev/null @@ -1 +0,0 @@ -Added some missing environment variables to the output of :option:`--help-env`. diff --git a/Misc/NEWS.d/next/Documentation/2024-06-05-12-36-18.gh-issue-120012.f14DbQ.rst b/Misc/NEWS.d/next/Documentation/2024-06-05-12-36-18.gh-issue-120012.f14DbQ.rst deleted file mode 100644 index 2bf0c977b90387..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-06-05-12-36-18.gh-issue-120012.f14DbQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Clarify the behaviours of :meth:`multiprocessing.Queue.empty` and -:meth:`multiprocessing.SimpleQueue.empty` on closed queues. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Documentation/2024-07-14-11-48-10.gh-issue-121749.nxHoTk.rst b/Misc/NEWS.d/next/Documentation/2024-07-14-11-48-10.gh-issue-121749.nxHoTk.rst deleted file mode 100644 index 17dc60c11468f4..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-07-14-11-48-10.gh-issue-121749.nxHoTk.rst +++ /dev/null @@ -1 +0,0 @@ -Fix documentation for :c:func:`PyModule_AddObjectRef`. diff --git a/Misc/NEWS.d/next/Documentation/2024-07-14-12-25-53.gh-issue-117765.YFMOUv.rst b/Misc/NEWS.d/next/Documentation/2024-07-14-12-25-53.gh-issue-117765.YFMOUv.rst deleted file mode 100644 index a727c1aa9a0571..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-07-14-12-25-53.gh-issue-117765.YFMOUv.rst +++ /dev/null @@ -1 +0,0 @@ -Improved documentation for :func:`unittest.mock.patch.dict` diff --git a/Misc/NEWS.d/next/Documentation/2024-07-19-12-22-48.gh-issue-121277.wF_zKd.rst b/Misc/NEWS.d/next/Documentation/2024-07-19-12-22-48.gh-issue-121277.wF_zKd.rst deleted file mode 100644 index 60f75ae0c21326..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-07-19-12-22-48.gh-issue-121277.wF_zKd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Writers of CPython's documentation can now use ``next`` as the version for -the ``versionchanged``, ``versionadded``, ``deprecated`` directives. diff --git a/Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst b/Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst deleted file mode 100644 index ba607bf7a42cd9..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-08-01-17-18-21.gh-issue-70870.fZnBM9.rst +++ /dev/null @@ -1,3 +0,0 @@ -Clarified the dual usage of the term "free variable" (both the formal -meaning of any reference to names defined outside the local scope, and the -narrower pragmatic meaning of nonlocal variables named in ``co_freevars``). diff --git a/Misc/NEWS.d/next/Documentation/2024-09-11-16-52-08.gh-issue-123976.jhOfNR.rst b/Misc/NEWS.d/next/Documentation/2024-09-11-16-52-08.gh-issue-123976.jhOfNR.rst deleted file mode 100644 index 7f8e5801ae6597..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-09-11-16-52-08.gh-issue-123976.jhOfNR.rst +++ /dev/null @@ -1 +0,0 @@ -Refresh docs around custom providers. diff --git a/Misc/NEWS.d/next/Documentation/2024-09-19-19-33-25.gh-issue-116622.M65UZ6.rst b/Misc/NEWS.d/next/Documentation/2024-09-19-19-33-25.gh-issue-116622.M65UZ6.rst deleted file mode 100644 index f047a8c6caa698..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-09-19-19-33-25.gh-issue-116622.M65UZ6.rst +++ /dev/null @@ -1 +0,0 @@ -Add an Android platform guide, and flag modules not available on Android. diff --git a/Misc/NEWS.d/next/Documentation/2024-09-24-11-52-36.gh-issue-124457.yrCjSV.rst b/Misc/NEWS.d/next/Documentation/2024-09-24-11-52-36.gh-issue-124457.yrCjSV.rst deleted file mode 100644 index f9da7b8a5724f5..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-09-24-11-52-36.gh-issue-124457.yrCjSV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove coverity scan from the CPython repo. It has not been used since 2020 -and is currently unmaintained. diff --git a/Misc/NEWS.d/next/Documentation/2024-09-27-16-47-48.gh-issue-124720.nVSTVb.rst b/Misc/NEWS.d/next/Documentation/2024-09-27-16-47-48.gh-issue-124720.nVSTVb.rst deleted file mode 100644 index 6bef1e4158400b..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-09-27-16-47-48.gh-issue-124720.nVSTVb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update "Using Python on a Mac" section of the "Python Setup and Usage" -document and include information on installing free-threading support. diff --git a/Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst b/Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst deleted file mode 100644 index e910da5b879ba5..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-10-07-00-31-17.gh-issue-125018.yKnymn.rst +++ /dev/null @@ -1,4 +0,0 @@ -The :mod:`importlib.metadata` documentation now includes semantic -cross-reference targets for the significant documented APIs. This means -intersphinx references like :func:`importlib.metadata.version` will -now work as expected. diff --git a/Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst b/Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst deleted file mode 100644 index 69a5c764d05a2e..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Added definitions for :term:`context`, :term:`current context`, and -:term:`context management protocol`, updated related definitions to be -consistent, and expanded the documentation for :class:`contextvars.Context`. diff --git a/Misc/NEWS.d/next/IDLE/2024-06-05-14-54-24.gh-issue-120104.j_thj4.rst b/Misc/NEWS.d/next/IDLE/2024-06-05-14-54-24.gh-issue-120104.j_thj4.rst deleted file mode 100644 index 10f5e345bf3e4f..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2024-06-05-14-54-24.gh-issue-120104.j_thj4.rst +++ /dev/null @@ -1 +0,0 @@ -Fix padding in config and search dialog windows in IDLE. diff --git a/Misc/NEWS.d/next/IDLE/2024-06-16-21-42-45.gh-issue-120083.nczuyv.rst b/Misc/NEWS.d/next/IDLE/2024-06-16-21-42-45.gh-issue-120083.nczuyv.rst deleted file mode 100644 index 643c2bb38c6e1f..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2024-06-16-21-42-45.gh-issue-120083.nczuyv.rst +++ /dev/null @@ -1 +0,0 @@ -Add explicit black IDLE Hovertip foreground color needed for recent macOS. Fixes Sonoma showing unreadable white on pale yellow. Patch by John Riggles. diff --git a/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst b/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst deleted file mode 100644 index 604194ebb2e859..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst +++ /dev/null @@ -1,2 +0,0 @@ -Stop Shell freezes by blocking user access to non-method sys.stdout.shell attributes, -which are all private. diff --git a/Misc/NEWS.d/next/IDLE/2024-07-30-18-02-55.gh-issue-122482.TerE0g.rst b/Misc/NEWS.d/next/IDLE/2024-07-30-18-02-55.gh-issue-122482.TerE0g.rst deleted file mode 100644 index 8a11e73305992f..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2024-07-30-18-02-55.gh-issue-122482.TerE0g.rst +++ /dev/null @@ -1,2 +0,0 @@ -Change About IDLE to direct users to discuss.python.org instead of the now -unused idle-dev email and mailing list. diff --git a/Misc/NEWS.d/next/IDLE/2024-09-21-23-12-18.gh-issue-112938.OeiDru.rst b/Misc/NEWS.d/next/IDLE/2024-09-21-23-12-18.gh-issue-112938.OeiDru.rst deleted file mode 100644 index 0cd058eeffb1d5..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2024-09-21-23-12-18.gh-issue-112938.OeiDru.rst +++ /dev/null @@ -1 +0,0 @@ -Fix uninteruptable hang when Shell gets rapid continuous output. diff --git a/Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst b/Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst deleted file mode 100644 index 541f6212794ef2..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2024-10-04-15-34-34.gh-issue-122392.V8K3w2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Increase currently inadequate vertical spacing for the IDLE browsers (path, -module, and stack) on high-resolution monitors. diff --git a/Misc/NEWS.d/next/Library/2018-12-04-07-36-27.bpo-14074.fMLKCu.rst b/Misc/NEWS.d/next/Library/2018-12-04-07-36-27.bpo-14074.fMLKCu.rst deleted file mode 100644 index 221c8e05fa98aa..00000000000000 --- a/Misc/NEWS.d/next/Library/2018-12-04-07-36-27.bpo-14074.fMLKCu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :mod:`argparse` metavar processing to allow positional arguments to have a -tuple metavar. diff --git a/Misc/NEWS.d/next/Library/2019-08-27-01-16-50.gh-issue-67693.4NIAiy.rst b/Misc/NEWS.d/next/Library/2019-08-27-01-16-50.gh-issue-67693.4NIAiy.rst deleted file mode 100644 index 22457df03e65c9..00000000000000 --- a/Misc/NEWS.d/next/Library/2019-08-27-01-16-50.gh-issue-67693.4NIAiy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`urllib.parse.urlunparse` and :func:`urllib.parse.urlunsplit` for URIs with path starting with multiple slashes and no authority. -Based on patch by Ashwin Ramaswami. diff --git a/Misc/NEWS.d/next/Library/2020-03-28-21-00-54.bpo-15987.aBL8XS.rst b/Misc/NEWS.d/next/Library/2020-03-28-21-00-54.bpo-15987.aBL8XS.rst deleted file mode 100644 index b906393449656d..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-03-28-21-00-54.bpo-15987.aBL8XS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Implemented :func:`ast.compare` for comparing two ASTs. Patch by Batuhan -Taskaya with some help from Jeremy Hylton. diff --git a/Misc/NEWS.d/next/Library/2020-12-22-18-08-12.bpo-41843.q9Nh2r.rst b/Misc/NEWS.d/next/Library/2020-12-22-18-08-12.bpo-41843.q9Nh2r.rst deleted file mode 100644 index 4e525f7ed6a757..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-12-22-18-08-12.bpo-41843.q9Nh2r.rst +++ /dev/null @@ -1,2 +0,0 @@ -Solaris now uses :func:`os.sendfile` fast-copy syscall for more efficient -:mod:`shutil` file copy related functions. diff --git a/Misc/NEWS.d/next/Library/2021-08-24-19-37-46.bpo-44864.KzxaDh.rst b/Misc/NEWS.d/next/Library/2021-08-24-19-37-46.bpo-44864.KzxaDh.rst deleted file mode 100644 index 9610fa90ef0a98..00000000000000 --- a/Misc/NEWS.d/next/Library/2021-08-24-19-37-46.bpo-44864.KzxaDh.rst +++ /dev/null @@ -1 +0,0 @@ -Do not translate user-provided strings in :class:`argparse.ArgumentParser`. diff --git a/Misc/NEWS.d/next/Library/2022-03-10-16-47-57.bpo-45767.ywmyo1.rst b/Misc/NEWS.d/next/Library/2022-03-10-16-47-57.bpo-45767.ywmyo1.rst deleted file mode 100644 index 0cdf1e84157777..00000000000000 --- a/Misc/NEWS.d/next/Library/2022-03-10-16-47-57.bpo-45767.ywmyo1.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix integer conversion in :func:`os.major`, :func:`os.minor`, and -:func:`os.makedev`. Support device numbers larger than ``2**63-1``. Support -non-existent device number (``NODEV``). diff --git a/Misc/NEWS.d/next/Library/2023-03-30-18-19-53.gh-issue-103134.bHrn91.rst b/Misc/NEWS.d/next/Library/2023-03-30-18-19-53.gh-issue-103134.bHrn91.rst deleted file mode 100644 index 11559dce0ae2b4..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-30-18-19-53.gh-issue-103134.bHrn91.rst +++ /dev/null @@ -1,6 +0,0 @@ -Add additional methods to :ref:`proxy objects ` -in the :mod:`!multiprocessing` module: - -* :meth:`!clear` and :meth:`!copy` for proxies of :class:`list` -* :meth:`~dict.fromkeys`, ``reversed(d)``, ``d | {}``, ``{} | d``, - ``d |= {'b': 2}`` for proxies of :class:`dict` diff --git a/Misc/NEWS.d/next/Library/2023-04-10-00-04-37.gh-issue-87106.UyBnPQ.rst b/Misc/NEWS.d/next/Library/2023-04-10-00-04-37.gh-issue-87106.UyBnPQ.rst deleted file mode 100644 index 2c736e72476313..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-10-00-04-37.gh-issue-87106.UyBnPQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed handling in :meth:`inspect.Signature.bind` of keyword arguments having -the same name as positional-only arguments when a variadic keyword argument -(e.g. ``**kwargs``) is present. diff --git a/Misc/NEWS.d/next/Library/2023-04-24-05-34-23.gh-issue-103194.GwBwWL.rst b/Misc/NEWS.d/next/Library/2023-04-24-05-34-23.gh-issue-103194.GwBwWL.rst deleted file mode 100644 index bc9187309c6a53..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-24-05-34-23.gh-issue-103194.GwBwWL.rst +++ /dev/null @@ -1,4 +0,0 @@ -Prepare Tkinter for C API changes in Tcl 8.7/9.0 to avoid -:class:`!_tkinter.Tcl_Obj` being unexpectedly returned -instead of :class:`bool`, :class:`str`, -:class:`bytearray`, or :class:`int`. diff --git a/Misc/NEWS.d/next/Library/2023-04-26-22-24-17.gh-issue-92081.V8xMot.rst b/Misc/NEWS.d/next/Library/2023-04-26-22-24-17.gh-issue-92081.V8xMot.rst deleted file mode 100644 index 0302e957b884cf..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-26-22-24-17.gh-issue-92081.V8xMot.rst +++ /dev/null @@ -1 +0,0 @@ -Fix missing spaces in email headers when the spaces are mixed with encoded 8-bit characters. diff --git a/Misc/NEWS.d/next/Library/2023-04-28-09-54-15.gh-issue-103956.EyLDPS.rst b/Misc/NEWS.d/next/Library/2023-04-28-09-54-15.gh-issue-103956.EyLDPS.rst deleted file mode 100644 index 4ce1491ffa91e2..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-28-09-54-15.gh-issue-103956.EyLDPS.rst +++ /dev/null @@ -1 +0,0 @@ -Fix lack of newline characters in :mod:`trace` module output when line tracing is enabled but source code line for current frame is not available. diff --git a/Misc/NEWS.d/next/Library/2023-06-16-14-52-00.gh-issue-102450.MfeR6A.rst b/Misc/NEWS.d/next/Library/2023-06-16-14-52-00.gh-issue-102450.MfeR6A.rst deleted file mode 100644 index abfad5fa63b777..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-16-14-52-00.gh-issue-102450.MfeR6A.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add missing ISO-8601 24:00 alternative to midnight of next day to :meth:`datetime.datetime.fromisoformat` and :meth:`datetime.time.fromisoformat`. -Patch by Izan "TizzySaurus" Robinson (tizzysaurus@gmail.com) diff --git a/Misc/NEWS.d/next/Library/2023-06-17-09-07-06.gh-issue-105623.5G06od.rst b/Misc/NEWS.d/next/Library/2023-06-17-09-07-06.gh-issue-105623.5G06od.rst deleted file mode 100644 index 2890674aac4bbc..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-17-09-07-06.gh-issue-105623.5G06od.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix performance degradation in -:class:`logging.handlers.RotatingFileHandler`. Patch by Craig Robson. diff --git a/Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst b/Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst deleted file mode 100644 index e741e60ff41a9b..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-09-19-17-56-24.gh-issue-109109.WJvvX2.rst +++ /dev/null @@ -1,5 +0,0 @@ -You can now get the raw TLS certificate chains from TLS connections via -:meth:`ssl.SSLSocket.get_verified_chain` and -:meth:`ssl.SSLSocket.get_unverified_chain` methods. - -Contributed by Mateusz Nowak. diff --git a/Misc/NEWS.d/next/Library/2023-12-12-15-19-58.gh-issue-108172.KyDPuG.rst b/Misc/NEWS.d/next/Library/2023-12-12-15-19-58.gh-issue-108172.KyDPuG.rst deleted file mode 100644 index 5c6b9cd3f81a21..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-12-12-15-19-58.gh-issue-108172.KyDPuG.rst +++ /dev/null @@ -1 +0,0 @@ -``webbrowser`` honors OS preferred browser on Linux when its desktop entry name contains the text of a known browser name. diff --git a/Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst b/Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst deleted file mode 100644 index 0f2a44299717c0..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst +++ /dev/null @@ -1 +0,0 @@ -Correct argparse usage output for required, mutually exclusive groups containing a positional argument diff --git a/Misc/NEWS.d/next/Library/2024-01-12-08-51-03.gh-issue-113978.MqTgB0.rst b/Misc/NEWS.d/next/Library/2024-01-12-08-51-03.gh-issue-113978.MqTgB0.rst deleted file mode 100644 index b8f9f255e0a75d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-01-12-08-51-03.gh-issue-113978.MqTgB0.rst +++ /dev/null @@ -1 +0,0 @@ -Ignore warnings on text completion inside REPL. diff --git a/Misc/NEWS.d/next/Library/2024-01-14-11-43-31.gh-issue-113878.dmEIN3.rst b/Misc/NEWS.d/next/Library/2024-01-14-11-43-31.gh-issue-113878.dmEIN3.rst deleted file mode 100644 index 8e1937ab73c31b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-01-14-11-43-31.gh-issue-113878.dmEIN3.rst +++ /dev/null @@ -1,9 +0,0 @@ -Add *doc* parameter to :func:`dataclasses.field`, so it can be stored and -shown as a documentation / metadata. If ``@dataclass(slots=True)`` is used, -then the supplied string is availabl in the :attr:`~object.__slots__` dict. -Otherwise, the supplied string is only available in the corresponding -:class:`dataclasses.Field` object. - -In order to support this feature we are changing the ``__slots__`` format -in dataclasses from :class:`tuple` to :class:`dict` -when documentation / metadata is present. diff --git a/Misc/NEWS.d/next/Library/2024-01-18-21-44-23.gh-issue-114264.DBKn29.rst b/Misc/NEWS.d/next/Library/2024-01-18-21-44-23.gh-issue-114264.DBKn29.rst deleted file mode 100644 index 069ac68b4f3a95..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-01-18-21-44-23.gh-issue-114264.DBKn29.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of :func:`copy.deepcopy` by adding a fast path for atomic types. diff --git a/Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst b/Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst deleted file mode 100644 index 0fe6a336bdf95b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-02-22-10-12-59.gh-issue-115808.F2g2Ku.rst +++ /dev/null @@ -1 +0,0 @@ -Add :func:`operator.is_none` and :func:`operator.is_not_none` functions. diff --git a/Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst b/Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst deleted file mode 100644 index f9dae0c9b8e2b2..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-02-27-10-22-15.gh-issue-115937.0cVNur.rst +++ /dev/null @@ -1,3 +0,0 @@ -Removed extra preprocessing for the ``__signature__`` attribute: the code -just check if it's a :class:`inspect.Signature` instance. Patch by Sergey B -Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-03-19-21-41-31.gh-issue-106531.Mgd--6.rst b/Misc/NEWS.d/next/Library/2024-03-19-21-41-31.gh-issue-106531.Mgd--6.rst deleted file mode 100644 index 6a5783c5ad9846..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-03-19-21-41-31.gh-issue-106531.Mgd--6.rst +++ /dev/null @@ -1,6 +0,0 @@ -In :mod:`importlib.resources`, sync with `importlib_resources 6.3.2 -`_, -including: ``MultiplexedPath`` now expects ``Traversable`` paths, -deprecating string arguments to ``MultiplexedPath``; Enabled support for -resources in namespace packages in zip files; Fixed ``NotADirectoryError`` -when calling files on a subdirectory of a namespace package. diff --git a/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst b/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst deleted file mode 100644 index d090f931f0238d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst +++ /dev/null @@ -1 +0,0 @@ -Always use :func:`str` to print ``choices`` in :mod:`argparse`. diff --git a/Misc/NEWS.d/next/Library/2024-04-19-14-59-53.gh-issue-118033.amS4Gw.rst b/Misc/NEWS.d/next/Library/2024-04-19-14-59-53.gh-issue-118033.amS4Gw.rst deleted file mode 100644 index 7ceb29330abf22..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-04-19-14-59-53.gh-issue-118033.amS4Gw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`dataclasses.dataclass` not creating a ``__weakref__`` slot when -subclassing :class:`typing.Generic`. diff --git a/Misc/NEWS.d/next/Library/2024-04-24-16-23-04.gh-issue-110190.TGd5qx.rst b/Misc/NEWS.d/next/Library/2024-04-24-16-23-04.gh-issue-110190.TGd5qx.rst deleted file mode 100644 index abc3ddb4ab5597..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-04-24-16-23-04.gh-issue-110190.TGd5qx.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ctypes structs with array on SPARC by setting ``MAX_STRUCT_SIZE`` to 32 -in stgdict. Patch by Jakub Kulik diff --git a/Misc/NEWS.d/next/Library/2024-04-28-19-51-00.gh-issue-118263.Gaap3S.rst b/Misc/NEWS.d/next/Library/2024-04-28-19-51-00.gh-issue-118263.Gaap3S.rst deleted file mode 100644 index 165a1ba69a811b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-04-28-19-51-00.gh-issue-118263.Gaap3S.rst +++ /dev/null @@ -1 +0,0 @@ -Speed up :func:`os.path.splitroot` & :func:`os.path.normpath` with a direct C call. diff --git a/Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst b/Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst deleted file mode 100644 index 37e27a6e37c7d0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`os.path.realpath` now suppresses any :exc:`OSError` from -:func:`os.readlink` when *strict* mode is disabled (the default). diff --git a/Misc/NEWS.d/next/Library/2024-05-06-17-39-52.gh-issue-118673.sTXBit.rst b/Misc/NEWS.d/next/Library/2024-05-06-17-39-52.gh-issue-118673.sTXBit.rst deleted file mode 100644 index f0a87d2a91df3c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-06-17-39-52.gh-issue-118673.sTXBit.rst +++ /dev/null @@ -1 +0,0 @@ -Removed executable bits and shebang from stdlib modules. diff --git a/Misc/NEWS.d/next/Library/2024-05-07-17-38-53.gh-issue-118714.XXKpVZ.rst b/Misc/NEWS.d/next/Library/2024-05-07-17-38-53.gh-issue-118714.XXKpVZ.rst deleted file mode 100644 index f41baee303482a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-07-17-38-53.gh-issue-118714.XXKpVZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow ``restart`` in post-mortem debugging of :mod:`pdb`. Removed restart message -when the user quits pdb from post-mortem mode. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst b/Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst deleted file mode 100644 index 474454b36da956..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow :class:`typing.TypeVar` instances without a default to follow -instances without a default in some cases. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-18-33-07.gh-issue-118507.OCQsAY.rst b/Misc/NEWS.d/next/Library/2024-05-08-18-33-07.gh-issue-118507.OCQsAY.rst deleted file mode 100644 index 67b1fea4f83cb4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-18-33-07.gh-issue-118507.OCQsAY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`os.path.isfile` on Windows for pipes. -Speedup :func:`os.path.isjunction` and :func:`os.path.lexists` on Windows with a native implementation. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-18-59-19.gh-issue-78707._Lz1sw.rst b/Misc/NEWS.d/next/Library/2024-05-08-18-59-19.gh-issue-78707._Lz1sw.rst deleted file mode 100644 index c73bab97b75838..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-18-59-19.gh-issue-78707._Lz1sw.rst +++ /dev/null @@ -1,3 +0,0 @@ -Drop support for passing additional positional arguments to -:meth:`pathlib.PurePath.relative_to` and -:meth:`~pathlib.PurePath.is_relative_to`. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-19-47-34.gh-issue-101357.e4R_9x.rst b/Misc/NEWS.d/next/Library/2024-05-08-19-47-34.gh-issue-101357.e4R_9x.rst deleted file mode 100644 index c99a7e5f024823..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-19-47-34.gh-issue-101357.e4R_9x.rst +++ /dev/null @@ -1,5 +0,0 @@ -Suppress all :exc:`OSError` exceptions from :meth:`pathlib.Path.exists` and -``is_*()`` methods, rather than a selection of more common errors. The new -behaviour is consistent with :func:`os.path.exists`, :func:`os.path.isdir`, -etc. Use :meth:`pathlib.Path.stat` to retrieve the file status without -suppressing exceptions. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-20-41-48.gh-issue-74033.YebHZj.rst b/Misc/NEWS.d/next/Library/2024-05-08-20-41-48.gh-issue-74033.YebHZj.rst deleted file mode 100644 index e6ff47e1a3e57b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-20-41-48.gh-issue-74033.YebHZj.rst +++ /dev/null @@ -1 +0,0 @@ -Drop support for passing keyword arguments to :class:`pathlib.Path`. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-21-13-56.gh-issue-118760.mdmH3T.rst b/Misc/NEWS.d/next/Library/2024-05-08-21-13-56.gh-issue-118760.mdmH3T.rst deleted file mode 100644 index 89ef9334fbc65d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-21-13-56.gh-issue-118760.mdmH3T.rst +++ /dev/null @@ -1 +0,0 @@ -Fix errors in calling Tkinter bindings on Windows. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-21-30-33.gh-issue-118760.XvyMHn.rst b/Misc/NEWS.d/next/Library/2024-05-08-21-30-33.gh-issue-118760.XvyMHn.rst deleted file mode 100644 index 0e2712c26b1c13..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-21-30-33.gh-issue-118760.XvyMHn.rst +++ /dev/null @@ -1 +0,0 @@ -Restore the default value of ``tkiter.wantobjects`` to ``1``. diff --git a/Misc/NEWS.d/next/Library/2024-05-08-23-16-50.gh-issue-118798.Q_ybqP.rst b/Misc/NEWS.d/next/Library/2024-05-08-23-16-50.gh-issue-118798.Q_ybqP.rst deleted file mode 100644 index 28847e13207ffe..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-08-23-16-50.gh-issue-118798.Q_ybqP.rst +++ /dev/null @@ -1,2 +0,0 @@ -The *isdst* parameter has been removed from :func:`email.utils.localtime`. -Patch by Hugo van Kemenade. diff --git a/Misc/NEWS.d/next/Library/2024-05-09-00-52-30.gh-issue-118803.Wv3AvU.rst b/Misc/NEWS.d/next/Library/2024-05-09-00-52-30.gh-issue-118803.Wv3AvU.rst deleted file mode 100644 index 2d86dff57faf72..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-09-00-52-30.gh-issue-118803.Wv3AvU.rst +++ /dev/null @@ -1,3 +0,0 @@ -:class:`!typing.ByteString` and :class:`!collections.abc.ByteString` are -removed. They had previously raised a :exc:`DeprecationWarning` since Python -3.12. diff --git a/Misc/NEWS.d/next/Library/2024-05-09-01-05-52.gh-issue-118805.N7dm07.rst b/Misc/NEWS.d/next/Library/2024-05-09-01-05-52.gh-issue-118805.N7dm07.rst deleted file mode 100644 index 4f1db04d8bd67f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-09-01-05-52.gh-issue-118805.N7dm07.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove *type*, *choices*, and *metavar* parameters of -:class:`!argparse.BooleanOptionalAction`. -They were deprecated since Python 3.12. diff --git a/Misc/NEWS.d/next/Library/2024-05-09-02-43-37.gh-issue-101588.30bNAr.rst b/Misc/NEWS.d/next/Library/2024-05-09-02-43-37.gh-issue-101588.30bNAr.rst deleted file mode 100644 index 3e0f496047bc8e..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-09-02-43-37.gh-issue-101588.30bNAr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove copy, deepcopy, and pickle from itertools. These had previously -raised a DeprecationWarning since Python 3.12. diff --git a/Misc/NEWS.d/next/Library/2024-05-09-08-46-12.gh-issue-118851.aPAoJw.rst b/Misc/NEWS.d/next/Library/2024-05-09-08-46-12.gh-issue-118851.aPAoJw.rst deleted file mode 100644 index d036d0cda617ef..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-09-08-46-12.gh-issue-118851.aPAoJw.rst +++ /dev/null @@ -1,2 +0,0 @@ -``ctx`` arguments to the constructors of :mod:`ast` node classes now default -to :class:`ast.Load() `. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2024-05-09-11-50-26.gh-issue-118824.-jBJQC.rst b/Misc/NEWS.d/next/Library/2024-05-09-11-50-26.gh-issue-118824.-jBJQC.rst deleted file mode 100644 index c9254f1b9dbea8..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-09-11-50-26.gh-issue-118824.-jBJQC.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove deprecated :func:`!pty.master_open` and :func:`!pty.slave_open`. -Use :func:`pty.openpty` instead. -Patch by Nikita Sobolev. diff --git a/Misc/NEWS.d/next/Library/2024-05-09-12-33-25.gh-issue-118827.JrzHz1.rst b/Misc/NEWS.d/next/Library/2024-05-09-12-33-25.gh-issue-118827.JrzHz1.rst deleted file mode 100644 index 40612dd93bd6da..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-09-12-33-25.gh-issue-118827.JrzHz1.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove deprecated :class:`!Quoter` class from :mod:`urllib.parse`. It had -previously raised a :exc:`DeprecationWarning` since Python 3.11. -Patch by Nikita Sobolev. diff --git a/Misc/NEWS.d/next/Library/2024-05-09-21-36-11.gh-issue-118868.uckxxP.rst b/Misc/NEWS.d/next/Library/2024-05-09-21-36-11.gh-issue-118868.uckxxP.rst deleted file mode 100644 index 372a809d9594b0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-09-21-36-11.gh-issue-118868.uckxxP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed issue where kwargs were no longer passed to the logging handler -QueueHandler diff --git a/Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst b/Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst deleted file mode 100644 index 226c8d612a039c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-10-05-24-32.gh-issue-118895.wUm5r2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Setting attributes on :data:`typing.NoDefault` now raises -:exc:`AttributeError` instead of :exc:`TypeError`. diff --git a/Misc/NEWS.d/next/Library/2024-05-10-22-36-01.gh-issue-118928.IW7Ukv.rst b/Misc/NEWS.d/next/Library/2024-05-10-22-36-01.gh-issue-118928.IW7Ukv.rst deleted file mode 100644 index 91c95e4a5395d4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-10-22-36-01.gh-issue-118928.IW7Ukv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Disallow using a sequence of parameters with named placeholders in -:mod:`sqlite3` queries. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2024-05-10-22-59-01.gh-issue-118924.9nyvSH.rst b/Misc/NEWS.d/next/Library/2024-05-10-22-59-01.gh-issue-118924.9nyvSH.rst deleted file mode 100644 index 36581dbb9bb11b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-10-22-59-01.gh-issue-118924.9nyvSH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove :data:`!version` and :data:`!version_info` from :mod:`sqlite3`. -Patch by Hugo van Kemenade. diff --git a/Misc/NEWS.d/next/Library/2024-05-11-20-23-45.gh-issue-82805.F9bz4J.rst b/Misc/NEWS.d/next/Library/2024-05-11-20-23-45.gh-issue-82805.F9bz4J.rst deleted file mode 100644 index 8715deda7d9c41..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-11-20-23-45.gh-issue-82805.F9bz4J.rst +++ /dev/null @@ -1,5 +0,0 @@ -Support single-dot file extensions in :attr:`pathlib.PurePath.suffix` and -related attributes and methods. For example, the -:attr:`~pathlib.PurePath.suffixes` of ``PurePath('foo.bar.')`` are now -``['.bar', '.']`` rather than ``[]``. This brings file extension splitting -in line with :func:`os.path.splitext`. diff --git a/Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst b/Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst deleted file mode 100644 index fa70b954e1e9ee..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst +++ /dev/null @@ -1 +0,0 @@ -Make :mod:`pdb` return to caller frame correctly when ``f_trace`` of the caller frame is not set diff --git a/Misc/NEWS.d/next/Library/2024-05-15-01-36-08.gh-issue-73991.CGknDf.rst b/Misc/NEWS.d/next/Library/2024-05-15-01-36-08.gh-issue-73991.CGknDf.rst deleted file mode 100644 index d8e3bdf59ed092..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-15-01-36-08.gh-issue-73991.CGknDf.rst +++ /dev/null @@ -1 +0,0 @@ -Add :meth:`pathlib.Path.copy`, which copies a file or directory to another. diff --git a/Misc/NEWS.d/next/Library/2024-05-16-17-31-46.gh-issue-118643.hAWH4C.rst b/Misc/NEWS.d/next/Library/2024-05-16-17-31-46.gh-issue-118643.hAWH4C.rst deleted file mode 100644 index e86a49af74c9d6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-16-17-31-46.gh-issue-118643.hAWH4C.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an AttributeError in the :mod:`email` module when re-fold a long address -list. Also fix more cases of incorrect encoding of the address separator in the address list. diff --git a/Misc/NEWS.d/next/Library/2024-05-17-17-32-12.gh-issue-119113.kEv1Ll.rst b/Misc/NEWS.d/next/Library/2024-05-17-17-32-12.gh-issue-119113.kEv1Ll.rst deleted file mode 100644 index 195be067138b2e..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-17-17-32-12.gh-issue-119113.kEv1Ll.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix issue where :meth:`pathlib.PurePath.with_suffix` didn't raise -:exc:`TypeError` when given ``None`` as a suffix. diff --git a/Misc/NEWS.d/next/Library/2024-05-19-12-25-36.gh-issue-119105.VcR4ig.rst b/Misc/NEWS.d/next/Library/2024-05-19-12-25-36.gh-issue-119105.VcR4ig.rst deleted file mode 100644 index 30b5f97b8059f9..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-19-12-25-36.gh-issue-119105.VcR4ig.rst +++ /dev/null @@ -1 +0,0 @@ -``difflib.Differ`` is much faster for some cases of diffs where many pairs of lines are equally similar. diff --git a/Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst b/Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst deleted file mode 100644 index fd562ea4f73317..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a NameError happening in ``asyncio.staggered.staggered_race``. This -function is now tested. diff --git a/Misc/NEWS.d/next/Library/2024-05-19-18-49-04.gh-issue-119174.5GTv7d.rst b/Misc/NEWS.d/next/Library/2024-05-19-18-49-04.gh-issue-119174.5GTv7d.rst deleted file mode 100644 index 7b467b9ebd0d80..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-19-18-49-04.gh-issue-119174.5GTv7d.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix high DPI causes turtledemo(turtle-graphics examples) windows blurry -Patch by Wulian233 and Terry Jan Reedy - diff --git a/Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst b/Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst deleted file mode 100644 index e5cfbcf95a0b81..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst +++ /dev/null @@ -1,3 +0,0 @@ -When using the ``**`` operator or :func:`pow` with :class:`~fractions.Fraction` -as the base and an exponent that is not rational, a float, or a complex, the -fraction is no longer converted to a float. diff --git a/Misc/NEWS.d/next/Library/2024-05-20-20-30-57.gh-issue-111201.DAA5lC.rst b/Misc/NEWS.d/next/Library/2024-05-20-20-30-57.gh-issue-111201.DAA5lC.rst deleted file mode 100644 index 15cd79dec378ee..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-20-20-30-57.gh-issue-111201.DAA5lC.rst +++ /dev/null @@ -1 +0,0 @@ -Remove dependency to :mod:`readline` from the new Python REPL. diff --git a/Misc/NEWS.d/next/Library/2024-05-21-19-10-30.gh-issue-115225.eRmfJH.rst b/Misc/NEWS.d/next/Library/2024-05-21-19-10-30.gh-issue-115225.eRmfJH.rst deleted file mode 100644 index 2b65eaa6dd70ad..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-21-19-10-30.gh-issue-115225.eRmfJH.rst +++ /dev/null @@ -1 +0,0 @@ -Raise error on certain technically valid but pathological ISO 8601 strings passed to :meth:`datetime.time.fromisoformat` that were previously parsed incorrectly. diff --git a/Misc/NEWS.d/next/Library/2024-05-21-20-13-23.gh-issue-118911.iG8nMq.rst b/Misc/NEWS.d/next/Library/2024-05-21-20-13-23.gh-issue-118911.iG8nMq.rst deleted file mode 100644 index 4f15c1b67c9774..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-21-20-13-23.gh-issue-118911.iG8nMq.rst +++ /dev/null @@ -1,5 +0,0 @@ -In PyREPL, updated ``maybe-accept``'s logic so that if the user hits -:kbd:`Enter` twice, they are able to terminate the block even if there's -trailing whitespace. Also, now when the user hits arrow up, the cursor -is on the last functional line. This matches IPython's behavior. -Patch by Aya Elsayed. diff --git a/Misc/NEWS.d/next/Library/2024-05-21-23-39-22.gh-issue-118830.YTqvEo.rst b/Misc/NEWS.d/next/Library/2024-05-21-23-39-22.gh-issue-118830.YTqvEo.rst deleted file mode 100644 index d06499831dc009..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-21-23-39-22.gh-issue-118830.YTqvEo.rst +++ /dev/null @@ -1 +0,0 @@ -Bump :mod:`pickle` default protocol to ``5``. diff --git a/Misc/NEWS.d/next/Library/2024-05-22-21-20-43.gh-issue-118894.xHdxR_.rst b/Misc/NEWS.d/next/Library/2024-05-22-21-20-43.gh-issue-118894.xHdxR_.rst deleted file mode 100644 index ffc4ae336dc54f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-22-21-20-43.gh-issue-118894.xHdxR_.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`asyncio` REPL now has the same capabilities as PyREPL. diff --git a/Misc/NEWS.d/next/Library/2024-05-23-11-52-36.gh-issue-117398.2FG1Mk.rst b/Misc/NEWS.d/next/Library/2024-05-23-11-52-36.gh-issue-117398.2FG1Mk.rst deleted file mode 100644 index ac595f1b7fc84c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-23-11-52-36.gh-issue-117398.2FG1Mk.rst +++ /dev/null @@ -1,3 +0,0 @@ -Objects in the datetime C-API are now all statically allocated, which means -better memory safety, especially when the module is reloaded. This should be -transparent to users. diff --git a/Misc/NEWS.d/next/Library/2024-05-23-15-48-17.gh-issue-119461.82KqUW.rst b/Misc/NEWS.d/next/Library/2024-05-23-15-48-17.gh-issue-119461.82KqUW.rst deleted file mode 100644 index 48e18f42b5556a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-23-15-48-17.gh-issue-119461.82KqUW.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``socket.VMADDR_CID_LOCAL`` constant. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-05-23-22-29-59.gh-issue-119443.KAGz6S.rst b/Misc/NEWS.d/next/Library/2024-05-23-22-29-59.gh-issue-119443.KAGz6S.rst deleted file mode 100644 index 4470c566a37d88..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-23-22-29-59.gh-issue-119443.KAGz6S.rst +++ /dev/null @@ -1,2 +0,0 @@ -The interactive REPL no longer runs with ``from __future__ import -annotations`` enabled. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2024-05-24-04-05-37.gh-issue-119105.aDSRFn.rst b/Misc/NEWS.d/next/Library/2024-05-24-04-05-37.gh-issue-119105.aDSRFn.rst deleted file mode 100644 index 3205061a68ce7f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-24-04-05-37.gh-issue-119105.aDSRFn.rst +++ /dev/null @@ -1 +0,0 @@ -``difflib``'s ``DIffer.compare()`` (and so also ``ndiff``) can no longer be provoked into cubic-time behavior, or into unbounded recursion, and should generally be faster in ordinary cases too. Results may change in some cases, although that should be rare. Correctness of diffs is not affected. Some similar lines far apart may be reported as deleting one and adding the other, where before they were displayed on adjacent output lines with markup showing the intraline differences. diff --git a/Misc/NEWS.d/next/Library/2024-05-24-11-47-08.gh-issue-69214.Grl6zF.rst b/Misc/NEWS.d/next/Library/2024-05-24-11-47-08.gh-issue-69214.Grl6zF.rst deleted file mode 100644 index 8c3a36c9f56475..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-24-11-47-08.gh-issue-69214.Grl6zF.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``fcntl.ioctl()`` *request* parameter: use an ``unsigned long`` instead of -an ``unsigned int`` for the *request* parameter of :func:`fcntl.ioctl` to -support requests larger than ``UINT_MAX``. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-05-24-14-32-24.gh-issue-119506.-nMNqq.rst b/Misc/NEWS.d/next/Library/2024-05-24-14-32-24.gh-issue-119506.-nMNqq.rst deleted file mode 100644 index f9b764ae0c49b3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-24-14-32-24.gh-issue-119506.-nMNqq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :meth:`!io.TextIOWrapper.write` method breaks internal buffer when the method is called again during flushing internal buffer. diff --git a/Misc/NEWS.d/next/Library/2024-05-24-21-54-55.gh-issue-113892.JKDFqq.rst b/Misc/NEWS.d/next/Library/2024-05-24-21-54-55.gh-issue-113892.JKDFqq.rst deleted file mode 100644 index 639d5abe878344..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-24-21-54-55.gh-issue-113892.JKDFqq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Now, the method ``sock_connect`` of :class:`asyncio.ProactorEventLoop` -raises a :exc:`ValueError` if given socket is not in -non-blocking mode, as well as in other loop implementations. diff --git a/Misc/NEWS.d/next/Library/2024-05-25-00-54-26.gh-issue-119127.LpPvag.rst b/Misc/NEWS.d/next/Library/2024-05-25-00-54-26.gh-issue-119127.LpPvag.rst deleted file mode 100644 index e47e2ae89dbff0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-25-00-54-26.gh-issue-119127.LpPvag.rst +++ /dev/null @@ -1,2 +0,0 @@ -Positional arguments of :func:`functools.partial` objects -now support placeholders via :data:`functools.Placeholder`. diff --git a/Misc/NEWS.d/next/Library/2024-05-25-07-25-07.gh-issue-117865.1A0Xpi.rst b/Misc/NEWS.d/next/Library/2024-05-25-07-25-07.gh-issue-117865.1A0Xpi.rst deleted file mode 100644 index 48cd390d1bb128..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-25-07-25-07.gh-issue-117865.1A0Xpi.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the import time of the :mod:`ast` module by deferring the import of -:mod:`re`. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2024-05-25-10-40-38.gh-issue-118908.XcZiq4.rst b/Misc/NEWS.d/next/Library/2024-05-25-10-40-38.gh-issue-118908.XcZiq4.rst deleted file mode 100644 index bf58d7277fcd51..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-25-10-40-38.gh-issue-118908.XcZiq4.rst +++ /dev/null @@ -1,2 +0,0 @@ -Limit exposed globals from internal imports and definitions on new REPL -startup. Patch by Eugene Triguba and Pablo Galindo. diff --git a/Misc/NEWS.d/next/Library/2024-05-25-20-15-26.gh-issue-119555.mvHbEL.rst b/Misc/NEWS.d/next/Library/2024-05-25-20-15-26.gh-issue-119555.mvHbEL.rst deleted file mode 100644 index e16cb28b471a7a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-25-20-15-26.gh-issue-119555.mvHbEL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Catch :exc:`SyntaxError` from :func:`compile` in the runsource() method of -the InteractiveColoredConsole. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst b/Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst deleted file mode 100644 index dd23466b9d2cef..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove :class:`!ast.Num`, :class:`!ast.Str`, :class:`!ast.Bytes`, -:class:`!ast.NameConstant` and :class:`!ast.Ellipsis`. They had all emitted -deprecation warnings since Python 3.12. Patch by Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2024-05-26-21-28-11.gh-issue-119588.wlLBK5.rst b/Misc/NEWS.d/next/Library/2024-05-26-21-28-11.gh-issue-119588.wlLBK5.rst deleted file mode 100644 index 01321d8bfe2ad5..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-26-21-28-11.gh-issue-119588.wlLBK5.rst +++ /dev/null @@ -1 +0,0 @@ -``zipfile.Path.is_symlink`` now assesses if the given path is a symlink. diff --git a/Misc/NEWS.d/next/Library/2024-05-26-22-22-51.gh-issue-119594.fnQNM8.rst b/Misc/NEWS.d/next/Library/2024-05-26-22-22-51.gh-issue-119594.fnQNM8.rst deleted file mode 100644 index d2de5273edf571..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-26-22-22-51.gh-issue-119594.fnQNM8.rst +++ /dev/null @@ -1 +0,0 @@ -If one calls pow(fractions.Fraction, x, module) with modulo not None, the error message now says that the types are incompatible rather than saying pow only takes 2 arguments. Patch by Wim Jeantine-Glenn and Mark Dickinson. diff --git a/Misc/NEWS.d/next/Library/2024-05-28-00-56-59.gh-issue-89727._bxoL3.rst b/Misc/NEWS.d/next/Library/2024-05-28-00-56-59.gh-issue-89727._bxoL3.rst deleted file mode 100644 index 92222bc673350f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-28-00-56-59.gh-issue-89727._bxoL3.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix issue with :func:`os.fwalk` where a :exc:`RecursionError` was raised on -deep directory trees by adjusting the implementation to be iterative instead -of recursive. diff --git a/Misc/NEWS.d/next/Library/2024-05-28-12-15-03.gh-issue-119118.FMKz1F.rst b/Misc/NEWS.d/next/Library/2024-05-28-12-15-03.gh-issue-119118.FMKz1F.rst deleted file mode 100644 index 3cf61662fe7767..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-28-12-15-03.gh-issue-119118.FMKz1F.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix performance regression in the :mod:`tokenize` module by caching the ``line`` -token attribute and calculating the column offset more efficiently. diff --git a/Misc/NEWS.d/next/Library/2024-05-29-12-42-40.gh-issue-93963.cb1oJS.rst b/Misc/NEWS.d/next/Library/2024-05-29-12-42-40.gh-issue-93963.cb1oJS.rst deleted file mode 100644 index d093c8e35a5994..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-29-12-42-40.gh-issue-93963.cb1oJS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove deprecated names from ``importlib.abc`` as found in -``importlib.resources.abc``. diff --git a/Misc/NEWS.d/next/Library/2024-05-29-20-42-17.gh-issue-89727.5lPTTW.rst b/Misc/NEWS.d/next/Library/2024-05-29-20-42-17.gh-issue-89727.5lPTTW.rst deleted file mode 100644 index 3b73d2789fd6f9..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-29-20-42-17.gh-issue-89727.5lPTTW.rst +++ /dev/null @@ -1,3 +0,0 @@ -Partially fix issue with :func:`shutil.rmtree` where a :exc:`RecursionError` -is raised on deep directory trees. A recursion error is no longer raised -when :data:`!rmtree.avoids_symlink_attacks` is false. diff --git a/Misc/NEWS.d/next/Library/2024-05-29-21-50-05.gh-issue-119577.S3BlKJ.rst b/Misc/NEWS.d/next/Library/2024-05-29-21-50-05.gh-issue-119577.S3BlKJ.rst deleted file mode 100644 index bd2daf3fb5c16d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-29-21-50-05.gh-issue-119577.S3BlKJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -The :exc:`DeprecationWarning` emitted when testing the truth value of an -:class:`xml.etree.ElementTree.Element` now describes unconditionally -returning ``True`` in a future version rather than raising an exception in -Python 3.14. diff --git a/Misc/NEWS.d/next/Library/2024-05-30-21-37-05.gh-issue-89727.D6S9ig.rst b/Misc/NEWS.d/next/Library/2024-05-30-21-37-05.gh-issue-89727.D6S9ig.rst deleted file mode 100644 index 854c56609acb8c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-30-21-37-05.gh-issue-89727.D6S9ig.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix issue with :func:`shutil.rmtree` where a :exc:`RecursionError` is raised -on deep directory trees. diff --git a/Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst b/Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst deleted file mode 100644 index 94265e442db584..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst +++ /dev/null @@ -1 +0,0 @@ -Make :mod:`termios` ``ioctl()`` constants positive. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-05-31-13-56-21.gh-issue-119838.H6XHlE.rst b/Misc/NEWS.d/next/Library/2024-05-31-13-56-21.gh-issue-119838.H6XHlE.rst deleted file mode 100644 index 17a87327b5b1d6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-31-13-56-21.gh-issue-119838.H6XHlE.rst +++ /dev/null @@ -1,3 +0,0 @@ -In mixed arithmetic operations with :class:`~fractions.Fraction` and -complex, the fraction is now converted to :class:`float` instead of -:class:`complex`. diff --git a/Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst b/Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst deleted file mode 100644 index fd6d8d79a9d157..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-05-31-21-17-43.gh-issue-119824.CQlxWV.rst +++ /dev/null @@ -1 +0,0 @@ -Print stack entry in :mod:`pdb` when and only when user input is needed. diff --git a/Misc/NEWS.d/next/Library/2024-06-01-16-58-43.gh-issue-117398.kR0RW7.rst b/Misc/NEWS.d/next/Library/2024-06-01-16-58-43.gh-issue-117398.kR0RW7.rst deleted file mode 100644 index b0fe06663248f6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-01-16-58-43.gh-issue-117398.kR0RW7.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``_datetime`` module (C implementation for :mod:`datetime`) now supports -being imported in multiple interpreters. diff --git a/Misc/NEWS.d/next/Library/2024-06-02-13-35-11.gh-issue-81936.ETeW9x.rst b/Misc/NEWS.d/next/Library/2024-06-02-13-35-11.gh-issue-81936.ETeW9x.rst deleted file mode 100644 index d53cc73e728d54..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-02-13-35-11.gh-issue-81936.ETeW9x.rst +++ /dev/null @@ -1,3 +0,0 @@ -:meth:`!help` and :meth:`!showtopic` methods now respect a -configured *output* argument to :class:`!pydoc.Helper` and not use the -pager in such cases. Patch by Enrico Tröger. diff --git a/Misc/NEWS.d/next/Library/2024-06-02-15-09-17.gh-issue-118835.KUAuz6.rst b/Misc/NEWS.d/next/Library/2024-06-02-15-09-17.gh-issue-118835.KUAuz6.rst deleted file mode 100644 index ec9ca20a487d76..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-02-15-09-17.gh-issue-118835.KUAuz6.rst +++ /dev/null @@ -1 +0,0 @@ -Fix _pyrepl crash when using custom prompt with ANSI escape codes. diff --git a/Misc/NEWS.d/next/Library/2024-06-03-11-18-16.gh-issue-117142.kWTXQo.rst b/Misc/NEWS.d/next/Library/2024-06-03-11-18-16.gh-issue-117142.kWTXQo.rst deleted file mode 100644 index 80734ef3946300..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-03-11-18-16.gh-issue-117142.kWTXQo.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`ctypes` module may now be imported in all subinterpreters, including -those that have their own GIL. diff --git a/Misc/NEWS.d/next/Library/2024-06-04-08-57-02.gh-issue-65454.o9j4wF.rst b/Misc/NEWS.d/next/Library/2024-06-04-08-57-02.gh-issue-65454.o9j4wF.rst deleted file mode 100644 index 0b232cf8ca1baf..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-04-08-57-02.gh-issue-65454.o9j4wF.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`unittest.mock.Mock.attach_mock` no longer triggers a call to a ``PropertyMock`` being attached. diff --git a/Misc/NEWS.d/next/Library/2024-06-04-12-23-01.gh-issue-119819.WKKrYh.rst b/Misc/NEWS.d/next/Library/2024-06-04-12-23-01.gh-issue-119819.WKKrYh.rst deleted file mode 100644 index f9e49c00f671f2..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-04-12-23-01.gh-issue-119819.WKKrYh.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix regression to allow logging configuration with multiprocessing queue -types. diff --git a/Misc/NEWS.d/next/Library/2024-06-04-14-54-46.gh-issue-120029._1YdTf.rst b/Misc/NEWS.d/next/Library/2024-06-04-14-54-46.gh-issue-120029._1YdTf.rst deleted file mode 100644 index e8ea1077139f71..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-04-14-54-46.gh-issue-120029._1YdTf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Expose :meth:`symtable.Symbol.is_type_parameter` in the :mod:`symtable` -module. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-06-04-18-53-10.gh-issue-120057.RSD9_Z.rst b/Misc/NEWS.d/next/Library/2024-06-04-18-53-10.gh-issue-120057.RSD9_Z.rst deleted file mode 100644 index 955be59821ee0c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-04-18-53-10.gh-issue-120057.RSD9_Z.rst +++ /dev/null @@ -1,4 +0,0 @@ -Added the :data:`os.environ.refresh() ` method to update -:data:`os.environ` with changes to the environment made by :func:`os.putenv`, -by :func:`os.unsetenv`, or made outside Python in the same process. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-06-04-19-03-25.gh-issue-112672.K2XfZH.rst b/Misc/NEWS.d/next/Library/2024-06-04-19-03-25.gh-issue-112672.K2XfZH.rst deleted file mode 100644 index 46345bff117b19..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-04-19-03-25.gh-issue-112672.K2XfZH.rst +++ /dev/null @@ -1 +0,0 @@ -Support building :mod:`tkinter` with Tcl 9.0. diff --git a/Misc/NEWS.d/next/Library/2024-06-04-19-49-16.gh-issue-120056.5aqozw.rst b/Misc/NEWS.d/next/Library/2024-06-04-19-49-16.gh-issue-120056.5aqozw.rst deleted file mode 100644 index 0adb70f51e8a0c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-04-19-49-16.gh-issue-120056.5aqozw.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add :data:`!socket.IP_RECVERR` and :data:`!socket.IP_RECVTTL` constants -(both available since Linux 2.2). -And :data:`!socket.IP_RECVORIGDSTADDR` constant (available since Linux 2.6.29). diff --git a/Misc/NEWS.d/next/Library/2024-06-05-08-02-46.gh-issue-120108.4U9BL8.rst b/Misc/NEWS.d/next/Library/2024-06-05-08-02-46.gh-issue-120108.4U9BL8.rst deleted file mode 100644 index e310695656255d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-05-08-02-46.gh-issue-120108.4U9BL8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix calling :func:`copy.deepcopy` on :mod:`ast` trees that have been -modified to have references to parent nodes. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2024-06-05-11-03-10.gh-issue-120029.QBsw47.rst b/Misc/NEWS.d/next/Library/2024-06-05-11-03-10.gh-issue-120029.QBsw47.rst deleted file mode 100644 index d1b2c592a113ce..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-05-11-03-10.gh-issue-120029.QBsw47.rst +++ /dev/null @@ -1,4 +0,0 @@ -Expose :class:`symtable.Symbol` methods :meth:`~symtable.Symbol.is_free_class`, -:meth:`~symtable.Symbol.is_comp_iter` and :meth:`~symtable.Symbol.is_comp_cell`. -Patch by Bénédikt Tran. - diff --git a/Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst b/Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst deleted file mode 100644 index 475da88914bde3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-05-11-39-21.gh-issue-119933.ooJXQV.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add the :class:`symtable.SymbolTableType` enumeration to represent the -possible outputs of the :class:`symtable.SymbolTable.get_type` method. Patch -by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-06-05-16-30-28.gh-issue-120121.9dz8i7.rst b/Misc/NEWS.d/next/Library/2024-06-05-16-30-28.gh-issue-120121.9dz8i7.rst deleted file mode 100644 index 4f3526477c8cce..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-05-16-30-28.gh-issue-120121.9dz8i7.rst +++ /dev/null @@ -1 +0,0 @@ -Add :exc:`concurrent.futures.InvalidStateError` to module's ``__all__``. diff --git a/Misc/NEWS.d/next/Library/2024-06-06-12-07-57.gh-issue-119698.rRrprk.rst b/Misc/NEWS.d/next/Library/2024-06-06-12-07-57.gh-issue-119698.rRrprk.rst deleted file mode 100644 index d4cca1439816b0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-06-12-07-57.gh-issue-119698.rRrprk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :meth:`symtable.Class.get_methods` and document its behaviour. Patch by -Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-06-06-17-24-43.gh-issue-120161.DahNXV.rst b/Misc/NEWS.d/next/Library/2024-06-06-17-24-43.gh-issue-120161.DahNXV.rst deleted file mode 100644 index c378cac44c97bf..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-06-17-24-43.gh-issue-120161.DahNXV.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`datetime` no longer crashes in certain complex reference cycle -situations. diff --git a/Misc/NEWS.d/next/Library/2024-06-07-02-00-31.gh-issue-120157.HnWcF9.rst b/Misc/NEWS.d/next/Library/2024-06-07-02-00-31.gh-issue-120157.HnWcF9.rst deleted file mode 100644 index 3e905125797af7..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-07-02-00-31.gh-issue-120157.HnWcF9.rst +++ /dev/null @@ -1 +0,0 @@ -Remove unused constant ``concurrent.futures._base._FUTURE_STATES`` in :mod:`concurrent.futures`. Patch by Clinton Christian (pygeek). diff --git a/Misc/NEWS.d/next/Library/2024-06-07-10-10-32.gh-issue-117983.NeMR9n.rst b/Misc/NEWS.d/next/Library/2024-06-07-10-10-32.gh-issue-117983.NeMR9n.rst deleted file mode 100644 index cca97f50a20496..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-07-10-10-32.gh-issue-117983.NeMR9n.rst +++ /dev/null @@ -1,2 +0,0 @@ -Defer the ``threading`` import in ``importlib.util`` until lazy loading is -used. diff --git a/Misc/NEWS.d/next/Library/2024-06-07-11-23-31.gh-issue-71587.IjFajE.rst b/Misc/NEWS.d/next/Library/2024-06-07-11-23-31.gh-issue-71587.IjFajE.rst deleted file mode 100644 index 50a662977993f5..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-07-11-23-31.gh-issue-71587.IjFajE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash in C version of :meth:`datetime.datetime.strptime` when called again -on the restarted interpreter. diff --git a/Misc/NEWS.d/next/Library/2024-06-07-13-21-11.gh-issue-120211.Rws_gf.rst b/Misc/NEWS.d/next/Library/2024-06-07-13-21-11.gh-issue-120211.Rws_gf.rst deleted file mode 100644 index 0106f2d93318b4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-07-13-21-11.gh-issue-120211.Rws_gf.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :mod:`tkinter.ttk` with Tcl/Tk 9.0. diff --git a/Misc/NEWS.d/next/Library/2024-06-08-03-29-01.gh-issue-120254.h682ke.rst b/Misc/NEWS.d/next/Library/2024-06-08-03-29-01.gh-issue-120254.h682ke.rst deleted file mode 100644 index 33ef1c91591c54..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-08-03-29-01.gh-issue-120254.h682ke.rst +++ /dev/null @@ -1 +0,0 @@ -Added ``commands`` argument to :func:`pdb.set_trace` which allows users to send debugger commands from the source file. diff --git a/Misc/NEWS.d/next/Library/2024-06-08-09-45-31.gh-issue-120244.8o9Dzr.rst b/Misc/NEWS.d/next/Library/2024-06-08-09-45-31.gh-issue-120244.8o9Dzr.rst deleted file mode 100644 index 2354a9afac4bc2..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-08-09-45-31.gh-issue-120244.8o9Dzr.rst +++ /dev/null @@ -1 +0,0 @@ -Fix memory leak in :func:`re.sub` when the replacement string contains backreferences. diff --git a/Misc/NEWS.d/next/Library/2024-06-08-14-36-40.gh-issue-120268.MNpd1q.rst b/Misc/NEWS.d/next/Library/2024-06-08-14-36-40.gh-issue-120268.MNpd1q.rst deleted file mode 100644 index d48d43cd047f7a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-08-14-36-40.gh-issue-120268.MNpd1q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Prohibit passing ``None`` to pure-Python :meth:`datetime.date.fromtimestamp` -to achieve consistency with C-extension implementation. diff --git a/Misc/NEWS.d/next/Library/2024-06-08-15-15-29.gh-issue-114053.WQLAFG.rst b/Misc/NEWS.d/next/Library/2024-06-08-15-15-29.gh-issue-114053.WQLAFG.rst deleted file mode 100644 index be49577a712867..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-08-15-15-29.gh-issue-114053.WQLAFG.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix erroneous :exc:`NameError` when calling :func:`inspect.get_annotations` -with ``eval_str=True``` on a class that made use of :pep:`695` type -parameters in a module that had ``from __future__ import annotations`` at -the top of the file. Patch by Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2024-06-08-15-46-35.gh-issue-114053.Ub2XgJ.rst b/Misc/NEWS.d/next/Library/2024-06-08-15-46-35.gh-issue-114053.Ub2XgJ.rst deleted file mode 100644 index 8aea591da5274c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-08-15-46-35.gh-issue-114053.Ub2XgJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix edge-case bug where :func:`typing.get_type_hints` would produce -incorrect results if type parameters in a class scope were overridden by -assignments in a class scope and ``from __future__ import annotations`` -semantics were enabled. Patch by Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2024-06-08-17-41-11.gh-issue-82017.WpSTGi.rst b/Misc/NEWS.d/next/Library/2024-06-08-17-41-11.gh-issue-82017.WpSTGi.rst deleted file mode 100644 index 7decee7ff3384e..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-08-17-41-11.gh-issue-82017.WpSTGi.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added support for converting any objects that have the -:meth:`!as_integer_ratio` method to a :class:`~fractions.Fraction`. diff --git a/Misc/NEWS.d/next/Library/2024-06-09-19-53-11.gh-issue-120289.s4HXR0.rst b/Misc/NEWS.d/next/Library/2024-06-09-19-53-11.gh-issue-120289.s4HXR0.rst deleted file mode 100644 index 518f79dc446ae7..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-09-19-53-11.gh-issue-120289.s4HXR0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed the use-after-free issue in :mod:`cProfile` by disallowing -``disable()`` and ``clear()`` in external timers. diff --git a/Misc/NEWS.d/next/Library/2024-06-10-14-00-40.gh-issue-119600.jJMf4C.rst b/Misc/NEWS.d/next/Library/2024-06-10-14-00-40.gh-issue-119600.jJMf4C.rst deleted file mode 100644 index 04c9ca9c3fd737..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-10-14-00-40.gh-issue-119600.jJMf4C.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`unittest.mock.patch` to not read attributes of the target when -``new_callable`` is set. Patch by Robert Collins. diff --git a/Misc/NEWS.d/next/Library/2024-06-11-07-17-25.gh-issue-119180.iH-2zy.rst b/Misc/NEWS.d/next/Library/2024-06-11-07-17-25.gh-issue-119180.iH-2zy.rst deleted file mode 100644 index f24d7bd6b9d26c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-11-07-17-25.gh-issue-119180.iH-2zy.rst +++ /dev/null @@ -1,4 +0,0 @@ -As part of implementing :pep:`649` and :pep:`749`, add a new module -``annotationlib``. Add support for unresolved forward references in -annotations to :mod:`dataclasses`, :class:`typing.TypedDict`, and -:class:`typing.NamedTuple`. diff --git a/Misc/NEWS.d/next/Library/2024-06-11-16-34-41.gh-issue-120343.hdiXeU.rst b/Misc/NEWS.d/next/Library/2024-06-11-16-34-41.gh-issue-120343.hdiXeU.rst deleted file mode 100644 index 76714b0c394eef..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-11-16-34-41.gh-issue-120343.hdiXeU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix column offset reporting for tokens that come after multiline f-strings in the :mod:`tokenize` module. diff --git a/Misc/NEWS.d/next/Library/2024-06-12-10-00-31.gh-issue-90425.5CfkKG.rst b/Misc/NEWS.d/next/Library/2024-06-12-10-00-31.gh-issue-90425.5CfkKG.rst deleted file mode 100644 index d152af49287a0b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-12-10-00-31.gh-issue-90425.5CfkKG.rst +++ /dev/null @@ -1,2 +0,0 @@ -The OS byte in gzip headers is now always set to 255 when using -:func:`gzip.compress`. diff --git a/Misc/NEWS.d/next/Library/2024-06-12-11-54-05.gh-issue-120381.O-BNLs.rst b/Misc/NEWS.d/next/Library/2024-06-12-11-54-05.gh-issue-120381.O-BNLs.rst deleted file mode 100644 index 44f49bc19a4c99..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-12-11-54-05.gh-issue-120381.O-BNLs.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correct :func:`inspect.ismethoddescriptor` to check also for the lack of -:meth:`~object.__delete__`. Patch by Jan Kaliszewski. diff --git a/Misc/NEWS.d/next/Library/2024-06-12-15-07-58.gh-issue-120388.VuTQMT.rst b/Misc/NEWS.d/next/Library/2024-06-12-15-07-58.gh-issue-120388.VuTQMT.rst deleted file mode 100644 index d13df7d88b776c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-12-15-07-58.gh-issue-120388.VuTQMT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improve a warning message when a test method in :mod:`unittest` returns -something other than ``None``. Now we show the returned object type and -optional asyncio-related tip. diff --git a/Misc/NEWS.d/next/Library/2024-06-14-20-05-25.gh-issue-120495.OxgZKB.rst b/Misc/NEWS.d/next/Library/2024-06-14-20-05-25.gh-issue-120495.OxgZKB.rst deleted file mode 100644 index d5114c3d3c904c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-14-20-05-25.gh-issue-120495.OxgZKB.rst +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect exception handling in Tab Nanny. Patch by Wulian233. diff --git a/Misc/NEWS.d/next/Library/2024-06-15-12-04-46.gh-issue-120541.d3cc5y.rst b/Misc/NEWS.d/next/Library/2024-06-15-12-04-46.gh-issue-120541.d3cc5y.rst deleted file mode 100644 index bf8830c6c50386..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-15-12-04-46.gh-issue-120541.d3cc5y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the prompt in the "less" pager when :func:`help` is called with -non-string argument. diff --git a/Misc/NEWS.d/next/Library/2024-06-15-23-38-36.gh-issue-120284.HwsAtY.rst b/Misc/NEWS.d/next/Library/2024-06-15-23-38-36.gh-issue-120284.HwsAtY.rst deleted file mode 100644 index a2a6883c3d7686..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-15-23-38-36.gh-issue-120284.HwsAtY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow :meth:`asyncio.Runner.run` to accept :term:`awaitable` -objects instead of simply :term:`coroutine`\s. diff --git a/Misc/NEWS.d/next/Library/2024-06-16-21-33-56.gh-issue-120606.kugbwR.rst b/Misc/NEWS.d/next/Library/2024-06-16-21-33-56.gh-issue-120606.kugbwR.rst deleted file mode 100644 index 874823ea3486fb..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-16-21-33-56.gh-issue-120606.kugbwR.rst +++ /dev/null @@ -1 +0,0 @@ -Allow users to use EOF to exit ``commands`` definition in :mod:`pdb` diff --git a/Misc/NEWS.d/next/Library/2024-06-17-20-04-13.gh-issue-120633.kZC5wt.rst b/Misc/NEWS.d/next/Library/2024-06-17-20-04-13.gh-issue-120633.kZC5wt.rst deleted file mode 100644 index 9b396988205589..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-17-20-04-13.gh-issue-120633.kZC5wt.rst +++ /dev/null @@ -1 +0,0 @@ -Move scrollbar and remove tear-off menus in turtledemo. diff --git a/Misc/NEWS.d/next/Library/2024-06-18-14-45-38.gh-issue-118710.5GZZPX.rst b/Misc/NEWS.d/next/Library/2024-06-18-14-45-38.gh-issue-118710.5GZZPX.rst deleted file mode 100644 index a02d286bcecd7f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-18-14-45-38.gh-issue-118710.5GZZPX.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`ipaddress.IPv4Address` and :class:`ipaddress.IPv6Address` attributes ``version`` and ``max_prefixlen`` are now available on the class. diff --git a/Misc/NEWS.d/next/Library/2024-06-18-19-18-10.gh-issue-120683.xmRez7.rst b/Misc/NEWS.d/next/Library/2024-06-18-19-18-10.gh-issue-120683.xmRez7.rst deleted file mode 100644 index 50fc9279e4bad1..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-18-19-18-10.gh-issue-120683.xmRez7.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix an error in :class:`logging.LogRecord`, when the integer part of the -timestamp is rounded up, while the millisecond calculation truncates, -causing the log timestamp to be wrong by up to 999 ms (affected roughly 1 in -8 million timestamps). diff --git a/Misc/NEWS.d/next/Library/2024-06-19-13-20-01.gh-issue-111259.Wki5PV.rst b/Misc/NEWS.d/next/Library/2024-06-19-13-20-01.gh-issue-111259.Wki5PV.rst deleted file mode 100644 index 91ed5f550e400f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-19-13-20-01.gh-issue-111259.Wki5PV.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`re` now handles patterns like ``"[\s\S]"`` or ``"\s|\S"`` which match -any character as effectively as a dot with the ``DOTALL`` modifier -(``"(?s:.)"``). diff --git a/Misc/NEWS.d/next/Library/2024-06-19-15-06-58.gh-issue-120732.OvYV9b.rst b/Misc/NEWS.d/next/Library/2024-06-19-15-06-58.gh-issue-120732.OvYV9b.rst deleted file mode 100644 index e31c4dd3192d60..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-19-15-06-58.gh-issue-120732.OvYV9b.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``name`` passing to :class:`unittest.mock.Mock` object when using -:func:`unittest.mock.create_autospec`. diff --git a/Misc/NEWS.d/next/Library/2024-06-19-15-43-04.gh-issue-120743.CMMl2P.rst b/Misc/NEWS.d/next/Library/2024-06-19-15-43-04.gh-issue-120743.CMMl2P.rst deleted file mode 100644 index e06dcf8af26a60..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-19-15-43-04.gh-issue-120743.CMMl2P.rst +++ /dev/null @@ -1,3 +0,0 @@ -:term:`Soft deprecate ` :func:`os.popen` and :func:`os.spawn* -` functions. They should no longer be used to write new code. The -:mod:`subprocess` module is recommended instead. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-06-19-19-53-42.gh-issue-41431.gnkUc5.rst b/Misc/NEWS.d/next/Library/2024-06-19-19-53-42.gh-issue-41431.gnkUc5.rst deleted file mode 100644 index 18e3506a60c455..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-19-19-53-42.gh-issue-41431.gnkUc5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :meth:`datetime.time.strptime` and :meth:`datetime.date.strptime`. -Contributed by Wannes Boeykens. diff --git a/Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst b/Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst deleted file mode 100644 index df3cfbcdbd2e29..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst +++ /dev/null @@ -1 +0,0 @@ -Show string value of LOAD_SPECIAL oparg in :mod:`dis` output. diff --git a/Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst b/Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst deleted file mode 100644 index 8ee6bf1a9c6480..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-20-01-31-24.gh-issue-120769.PfiMrc.rst +++ /dev/null @@ -1 +0,0 @@ -Make empty line in :mod:`pdb` repeats the last command even when the command is from ``cmdqueue``. diff --git a/Misc/NEWS.d/next/Library/2024-06-21-06-37-46.gh-issue-120713.WBbQx4.rst b/Misc/NEWS.d/next/Library/2024-06-21-06-37-46.gh-issue-120713.WBbQx4.rst deleted file mode 100644 index 18386a43eddc6f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-21-06-37-46.gh-issue-120713.WBbQx4.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`datetime.datetime.strftime` now 0-pads years with less than four digits for the format specifiers ``%Y`` and ``%G`` on Linux. -Patch by Ben Hsing diff --git a/Misc/NEWS.d/next/Library/2024-06-21-12-00-16.gh-issue-120782.LOE8tj.rst b/Misc/NEWS.d/next/Library/2024-06-21-12-00-16.gh-issue-120782.LOE8tj.rst deleted file mode 100644 index 02acbd2873009b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-21-12-00-16.gh-issue-120782.LOE8tj.rst +++ /dev/null @@ -1 +0,0 @@ -Fix wrong references of the :mod:`datetime` types after reloading the module. diff --git a/Misc/NEWS.d/next/Library/2024-06-21-14-32-56.gh-issue-120811.eBmVTV.rst b/Misc/NEWS.d/next/Library/2024-06-21-14-32-56.gh-issue-120811.eBmVTV.rst deleted file mode 100644 index 62cd7b5620474a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-21-14-32-56.gh-issue-120811.eBmVTV.rst +++ /dev/null @@ -1 +0,0 @@ -Fix possible memory leak in :meth:`contextvars.Context.run`. diff --git a/Misc/NEWS.d/next/Library/2024-06-22-17-01-56.gh-issue-120678.Ik8dCg.rst b/Misc/NEWS.d/next/Library/2024-06-22-17-01-56.gh-issue-120678.Ik8dCg.rst deleted file mode 100644 index ef0d3e3299e2e9..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-22-17-01-56.gh-issue-120678.Ik8dCg.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix regression in the new REPL that meant that globals from files passed -using the ``-i`` argument would not be included in the REPL's global -namespace. Patch by Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2024-06-22-22-23-56.gh-issue-101830.1BAoxH.rst b/Misc/NEWS.d/next/Library/2024-06-22-22-23-56.gh-issue-101830.1BAoxH.rst deleted file mode 100644 index 46c18b040f30d7..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-22-22-23-56.gh-issue-101830.1BAoxH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Accessing the :mod:`tkinter` object's string representation no longer converts -the underlying Tcl object to a string on Windows. diff --git a/Misc/NEWS.d/next/Library/2024-06-22-22-52-24.gh-issue-120888.sd8I3N.rst b/Misc/NEWS.d/next/Library/2024-06-22-22-52-24.gh-issue-120888.sd8I3N.rst deleted file mode 100644 index c733ff5159aa40..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-22-22-52-24.gh-issue-120888.sd8I3N.rst +++ /dev/null @@ -1 +0,0 @@ -Upgrade pip wheel bundled with ensurepip (pip 24.1.1) diff --git a/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst b/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst deleted file mode 100644 index 890eb62010eb33..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst +++ /dev/null @@ -1,5 +0,0 @@ -Support :c:expr:`float complex`, :c:expr:`double complex` and -:c:expr:`long double complex` C types in :mod:`ctypes` as -:class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and -:class:`~ctypes.c_longdouble_complex` if the compiler has C11 complex arithmetic. -Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-06-23-11-21-27.gh-issue-120910.t0QXdB.rst b/Misc/NEWS.d/next/Library/2024-06-23-11-21-27.gh-issue-120910.t0QXdB.rst deleted file mode 100644 index 3773cdc6ee3bf3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-23-11-21-27.gh-issue-120910.t0QXdB.rst +++ /dev/null @@ -1,2 +0,0 @@ -When reading installed files from an egg, use ``relative_to(walk_up=True)`` -to honor files installed outside of the installation root. diff --git a/Misc/NEWS.d/next/Library/2024-06-23-17-50-40.gh-issue-119614.vwPGLB.rst b/Misc/NEWS.d/next/Library/2024-06-23-17-50-40.gh-issue-119614.vwPGLB.rst deleted file mode 100644 index d518265a7fe55a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-23-17-50-40.gh-issue-119614.vwPGLB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix truncation of strings with embedded null characters in some internal -operations in :mod:`tkinter`. diff --git a/Misc/NEWS.d/next/Library/2024-06-26-03-04-24.gh-issue-121018.clVSc4.rst b/Misc/NEWS.d/next/Library/2024-06-26-03-04-24.gh-issue-121018.clVSc4.rst deleted file mode 100644 index 346a89879cad41..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-26-03-04-24.gh-issue-121018.clVSc4.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed issues where :meth:`!argparse.ArgumentParser.parse_args` did not honor -``exit_on_error=False``. -Based on patch by Ben Hsing. diff --git a/Misc/NEWS.d/next/Library/2024-06-26-10-13-40.gh-issue-121025.M-XXlV.rst b/Misc/NEWS.d/next/Library/2024-06-26-10-13-40.gh-issue-121025.M-XXlV.rst deleted file mode 100644 index 38cad610396787..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-26-10-13-40.gh-issue-121025.M-XXlV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the :meth:`~object.__repr__` of :class:`functools.partialmethod`. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst b/Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst deleted file mode 100644 index 3f576eebc9a85d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst +++ /dev/null @@ -1 +0,0 @@ -CPython now detects whether its linked TLS library supports TLSv1.3 post-handshake authentication and disables that feature if support is lacking. diff --git a/Misc/NEWS.d/next/Library/2024-06-27-12-27-52.gh-issue-121027.D4K1OX.rst b/Misc/NEWS.d/next/Library/2024-06-27-12-27-52.gh-issue-121027.D4K1OX.rst deleted file mode 100644 index a450726d9afed9..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-27-12-27-52.gh-issue-121027.D4K1OX.rst +++ /dev/null @@ -1 +0,0 @@ -Make the :class:`functools.partial` object a method descriptor. diff --git a/Misc/NEWS.d/next/Library/2024-06-27-13-47-14.gh-issue-121027.jh55EC.rst b/Misc/NEWS.d/next/Library/2024-06-27-13-47-14.gh-issue-121027.jh55EC.rst deleted file mode 100644 index 8470c8b37ac83d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-27-13-47-14.gh-issue-121027.jh55EC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add a future warning in :meth:`!functools.partial.__get__`. In future Python -versions :class:`functools.partial` will be a method descriptor. diff --git a/Misc/NEWS.d/next/Library/2024-06-29-05-08-59.gh-issue-87744.rpF6Jw.rst b/Misc/NEWS.d/next/Library/2024-06-29-05-08-59.gh-issue-87744.rpF6Jw.rst deleted file mode 100644 index c0b4f349fb6dac..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-29-05-08-59.gh-issue-87744.rpF6Jw.rst +++ /dev/null @@ -1 +0,0 @@ -Fix waitpid race while calling :meth:`~asyncio.subprocess.Process.send_signal` in asyncio. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2024-06-29-15-21-12.gh-issue-121141.4evD6q.rst b/Misc/NEWS.d/next/Library/2024-06-29-15-21-12.gh-issue-121141.4evD6q.rst deleted file mode 100644 index f2dc621050ff4b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-29-15-21-12.gh-issue-121141.4evD6q.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for :func:`copy.replace` to AST nodes. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-06-29-15-23-26.gh-issue-121151.HeLEvq.rst b/Misc/NEWS.d/next/Library/2024-06-29-15-23-26.gh-issue-121151.HeLEvq.rst deleted file mode 100644 index f08b6131a702f7..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-29-15-23-26.gh-issue-121151.HeLEvq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix wrapping of long usage text of arguments inside a mutually exclusive -group in :mod:`argparse`. diff --git a/Misc/NEWS.d/next/Library/2024-06-29-19-30-15.gh-issue-121163.SJKDFq.rst b/Misc/NEWS.d/next/Library/2024-06-29-19-30-15.gh-issue-121163.SJKDFq.rst deleted file mode 100644 index 50f945ab9f1436..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-06-29-19-30-15.gh-issue-121163.SJKDFq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add support for ``all`` as an valid ``action`` for :func:`warnings.simplefilter` -and :func:`warnings.filterwarnings`. diff --git a/Misc/NEWS.d/next/Library/2024-07-01-11-23-18.gh-issue-121210.cD0zfn.rst b/Misc/NEWS.d/next/Library/2024-07-01-11-23-18.gh-issue-121210.cD0zfn.rst deleted file mode 100644 index 55d5b221bf0765..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-01-11-23-18.gh-issue-121210.cD0zfn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Handle AST nodes with missing runtime fields or attributes in -:func:`ast.compare`. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-07-02-11-34-06.gh-issue-121245.sSkDAr.rst b/Misc/NEWS.d/next/Library/2024-07-02-11-34-06.gh-issue-121245.sSkDAr.rst deleted file mode 100644 index 6e9dec2545166f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-02-11-34-06.gh-issue-121245.sSkDAr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug in the handling of the command history of the new :term:`REPL` that caused -the history file to be wiped at REPL exit. diff --git a/Misc/NEWS.d/next/Library/2024-07-03-07-25-21.gh-issue-121332.Iz6FEq.rst b/Misc/NEWS.d/next/Library/2024-07-03-07-25-21.gh-issue-121332.Iz6FEq.rst deleted file mode 100644 index 480f27e05953a6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-03-07-25-21.gh-issue-121332.Iz6FEq.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix constructor of :mod:`ast` nodes with custom ``_attributes``. Previously, -passing custom attributes would raise a :py:exc:`DeprecationWarning`. Passing -arguments to the constructor that are not in ``_fields`` or ``_attributes`` -remains deprecated. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2024-07-03-10-11-53.gh-issue-121313.D7gARW.rst b/Misc/NEWS.d/next/Library/2024-07-03-10-11-53.gh-issue-121313.D7gARW.rst deleted file mode 100644 index bb41063e684da4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-03-10-11-53.gh-issue-121313.D7gARW.rst +++ /dev/null @@ -1 +0,0 @@ -Limit the reading size in the :class:`multiprocessing.connection.Connection` class to 64 KiB to prevent memory overallocation and unnecessary memory management system calls. diff --git a/Misc/NEWS.d/next/Library/2024-07-03-14-23-04.gh-issue-119004.L5MoUu.rst b/Misc/NEWS.d/next/Library/2024-07-03-14-23-04.gh-issue-119004.L5MoUu.rst deleted file mode 100644 index 899bd163d36644..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-03-14-23-04.gh-issue-119004.L5MoUu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in :ref:`OrderedDict.__eq__ ` -when operands are mutated during the check. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-07-04-17-36-03.gh-issue-59110.IlI9Fz.rst b/Misc/NEWS.d/next/Library/2024-07-04-17-36-03.gh-issue-59110.IlI9Fz.rst deleted file mode 100644 index b8e3ee0720cfe6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-04-17-36-03.gh-issue-59110.IlI9Fz.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`zipimport` supports now namespace packages when no directory entry -exists. diff --git a/Misc/NEWS.d/next/Library/2024-07-06-12-37-10.gh-issue-121423.vnxrl4.rst b/Misc/NEWS.d/next/Library/2024-07-06-12-37-10.gh-issue-121423.vnxrl4.rst deleted file mode 100644 index 0fd89a99681292..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-06-12-37-10.gh-issue-121423.vnxrl4.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve import time of :mod:`socket` by lazy importing modules and -writing :data:`!socket.errorTab` as a constant. diff --git a/Misc/NEWS.d/next/Library/2024-07-06-16-08-39.gh-issue-119169.o0YymL.rst b/Misc/NEWS.d/next/Library/2024-07-06-16-08-39.gh-issue-119169.o0YymL.rst deleted file mode 100644 index 5d9b50d452a9cd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-06-16-08-39.gh-issue-119169.o0YymL.rst +++ /dev/null @@ -1 +0,0 @@ -Slightly speed up :func:`os.walk` by simplifying exception handling. diff --git a/Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst b/Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst deleted file mode 100644 index 98b9453ad8c843..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst +++ /dev/null @@ -1,4 +0,0 @@ -Hard-coded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace`) now -reuse the most recent ``Pdb`` instance that calls ``Pdb.set_trace()``, -instead of creating a new one each time. As a result, all the instance specific -data like ``display`` and ``commands`` are preserved across Hard-coded breakpoints. diff --git a/Misc/NEWS.d/next/Library/2024-07-08-03-45-34.gh-issue-121474.NsvrUN.rst b/Misc/NEWS.d/next/Library/2024-07-08-03-45-34.gh-issue-121474.NsvrUN.rst deleted file mode 100644 index 605f30d76f5d47..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-08-03-45-34.gh-issue-121474.NsvrUN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix missing sanity check for ``parties`` arg in :class:`threading.Barrier` -constructor. Patch by Clinton Christian (pygeek). diff --git a/Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst b/Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst deleted file mode 100644 index 15130aafbc4408..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`math` functions :func:`~math.isqrt`, :func:`~math.log`, :func:`~math.log2` and -:func:`~math.log10` now support integers larger than ``2**2**32`` on 32-bit -platforms. diff --git a/Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst b/Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst deleted file mode 100644 index 2d41fca45bcad9..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst +++ /dev/null @@ -1,3 +0,0 @@ -Support the :c:expr:`float complex` and :c:expr:`double complex` -C types in the :mod:`struct` module if the compiler has C11 complex -arithmetic. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst b/Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst deleted file mode 100644 index 1758f587157f36..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-13-06-23-24.gh-issue-121245.RfOgf4.rst +++ /dev/null @@ -1,3 +0,0 @@ -Simplify handling of the history file in ``site.register_readline()`` -helper. The ``CAN_USE_PYREPL`` variable now will be initialized, when -imported. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-07-14-06-24-02.gh-issue-57141.C3jhDh.rst b/Misc/NEWS.d/next/Library/2024-07-14-06-24-02.gh-issue-57141.C3jhDh.rst deleted file mode 100644 index 33e9ab94852e35..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-14-06-24-02.gh-issue-57141.C3jhDh.rst +++ /dev/null @@ -1,2 +0,0 @@ -The *shallow* argument to :class:`filecmp.dircmp` (new in Python 3.13) is -now keyword-only. diff --git a/Misc/NEWS.d/next/Library/2024-07-14-11-18-28.gh-issue-120930.Kuo4L0.rst b/Misc/NEWS.d/next/Library/2024-07-14-11-18-28.gh-issue-120930.Kuo4L0.rst deleted file mode 100644 index 9e11595cdb50b8..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-14-11-18-28.gh-issue-120930.Kuo4L0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a bug introduced by gh-92081 that added an incorrect extra -blank to encoded words occurring in wrapped headers. diff --git a/Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst b/Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst deleted file mode 100644 index 5706e4bffeb4a1..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-15-19-25-25.gh-issue-121798.GmuBDu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add alternative :class:`~decimal.Decimal` constructor -:meth:`Decimal.from_number() `. diff --git a/Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst b/Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst deleted file mode 100644 index 9525379587f6cd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-15-19-34-56.gh-issue-121797.qDqj59.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add alternative :class:`~fractions.Fraction` constructor -:meth:`Fraction.from_number() `. diff --git a/Misc/NEWS.d/next/Library/2024-07-16-20-49-07.gh-issue-121804.gYN-In.rst b/Misc/NEWS.d/next/Library/2024-07-16-20-49-07.gh-issue-121804.gYN-In.rst deleted file mode 100644 index 1cc1cde7c22704..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-16-20-49-07.gh-issue-121804.gYN-In.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly show error locations, when :exc:`SyntaxError` raised in new repl. -Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-07-17-09-23-03.gh-issue-121889.6se9jS.rst b/Misc/NEWS.d/next/Library/2024-07-17-09-23-03.gh-issue-121889.6se9jS.rst deleted file mode 100644 index a7babe0580b3e4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-17-09-23-03.gh-issue-121889.6se9jS.rst +++ /dev/null @@ -1 +0,0 @@ -Adjusts ``cmath.acosh(complex('0+nanj'))`` for recent C standards. diff --git a/Misc/NEWS.d/next/Library/2024-07-17-09-44-35.gh-issue-119698.WlygzR.rst b/Misc/NEWS.d/next/Library/2024-07-17-09-44-35.gh-issue-119698.WlygzR.rst deleted file mode 100644 index 5134e609e7f1ca..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-17-09-44-35.gh-issue-119698.WlygzR.rst +++ /dev/null @@ -1,3 +0,0 @@ -Due to the lack of interest for :meth:`symtable.Class.get_methods`, the -method is marked as deprecated and will be removed in Python 3.16. Patch by -Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-07-17-12-55-22.gh-issue-121268.41RmjR.rst b/Misc/NEWS.d/next/Library/2024-07-17-12-55-22.gh-issue-121268.41RmjR.rst deleted file mode 100644 index f88e363da16124..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-17-12-55-22.gh-issue-121268.41RmjR.rst +++ /dev/null @@ -1 +0,0 @@ -Remove workarounds for non-IEEE 754 systems in :mod:`cmath`. diff --git a/Misc/NEWS.d/next/Library/2024-07-21-02-00-46.gh-issue-73991.pLxdtJ.rst b/Misc/NEWS.d/next/Library/2024-07-21-02-00-46.gh-issue-73991.pLxdtJ.rst deleted file mode 100644 index 26fdd8c59b1c50..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-21-02-00-46.gh-issue-73991.pLxdtJ.rst +++ /dev/null @@ -1 +0,0 @@ -Add :meth:`pathlib.Path.move`, which moves a file or directory tree. diff --git a/Misc/NEWS.d/next/Library/2024-07-21-10-45-24.gh-issue-122081.dNrYMq.rst b/Misc/NEWS.d/next/Library/2024-07-21-10-45-24.gh-issue-122081.dNrYMq.rst deleted file mode 100644 index 4c988b16168047..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-21-10-45-24.gh-issue-122081.dNrYMq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in the :func:`!decimal.IEEEContext` optional function -available via the ``EXTRA_FUNCTIONALITY`` configuration flag. diff --git a/Misc/NEWS.d/next/Library/2024-07-21-18-03-30.gh-issue-122088.vi2bP-.rst b/Misc/NEWS.d/next/Library/2024-07-21-18-03-30.gh-issue-122088.vi2bP-.rst deleted file mode 100644 index 9c173d8c462feb..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-21-18-03-30.gh-issue-122088.vi2bP-.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`@warnings.deprecated ` now copies the -coroutine status of functions and methods so that -:func:`inspect.iscoroutinefunction` returns the correct result. diff --git a/Misc/NEWS.d/next/Library/2024-07-22-08-14-04.gh-issue-113785.6B_KNB.rst b/Misc/NEWS.d/next/Library/2024-07-22-08-14-04.gh-issue-113785.6B_KNB.rst deleted file mode 100644 index 89d44a3f79c390..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-22-08-14-04.gh-issue-113785.6B_KNB.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`csv` now correctly parses numeric fields (when used with :const:`csv.QUOTE_NONNUMERIC` or :const:`csv.QUOTE_STRINGS`) which start with an escape character. diff --git a/Misc/NEWS.d/next/Library/2024-07-22-08-57-28.gh-issue-120754.Eo5puP.rst b/Misc/NEWS.d/next/Library/2024-07-22-08-57-28.gh-issue-120754.Eo5puP.rst deleted file mode 100644 index daf184153646cd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-22-08-57-28.gh-issue-120754.Eo5puP.rst +++ /dev/null @@ -1 +0,0 @@ -``Pathlib.read_bytes`` no longer opens the file in Python's buffered I/O mode. This reduces overheads as the code reads a file in whole leading to a modest speedup. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-09-14-44.gh-issue-82951.-F5p5A.rst b/Misc/NEWS.d/next/Library/2024-07-23-09-14-44.gh-issue-82951.-F5p5A.rst deleted file mode 100644 index b3f07889119c9f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-09-14-44.gh-issue-82951.-F5p5A.rst +++ /dev/null @@ -1,3 +0,0 @@ -Serializing objects with complex ``__qualname__`` (such as unbound methods -and nested classes) by name no longer involves serializing parent objects by -value in pickle protocols < 4. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-10-59-38.gh-issue-121723.iJEf7e.rst b/Misc/NEWS.d/next/Library/2024-07-23-10-59-38.gh-issue-121723.iJEf7e.rst deleted file mode 100644 index cabb4024fb10f1..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-10-59-38.gh-issue-121723.iJEf7e.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make :func:`logging.config.dictConfig` accept any object implementing the -Queue public API. See the :ref:`queue configuration ` -section for details. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst b/Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst deleted file mode 100644 index a4282f12d9742a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an issue when reporting tracebacks corresponding to Python code -emitting an empty AST body. -Patch by Nikita Sobolev and Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-13-07-12.gh-issue-122129.PwbC8q.rst b/Misc/NEWS.d/next/Library/2024-07-23-13-07-12.gh-issue-122129.PwbC8q.rst deleted file mode 100644 index 08beb45653d24b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-13-07-12.gh-issue-122129.PwbC8q.rst +++ /dev/null @@ -1 +0,0 @@ -Improve support of method descriptors and wrappers in the help title. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-15-11-13.gh-issue-122163.4wRUuM.rst b/Misc/NEWS.d/next/Library/2024-07-23-15-11-13.gh-issue-122163.4wRUuM.rst deleted file mode 100644 index a4625c2a0e50e3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-15-11-13.gh-issue-122163.4wRUuM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add notes for JSON serialization errors that allow to identify the source of -the error. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst b/Misc/NEWS.d/next/Library/2024-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst deleted file mode 100644 index 7eeb9f67ad4b3a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-15-30-23.gh-issue-122170.Z9gi3Y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Handle :exc:`ValueError`\s raised by :func:`os.stat` in :mod:`linecache`. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-17-13-10.gh-issue-119180.5PZELo.rst b/Misc/NEWS.d/next/Library/2024-07-23-17-13-10.gh-issue-119180.5PZELo.rst deleted file mode 100644 index d65e89f7523b0a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-17-13-10.gh-issue-119180.5PZELo.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix handling of classes with custom metaclasses in -``annotationlib.get_annotations``. diff --git a/Misc/NEWS.d/next/Library/2024-07-23-22-26-00.gh-issue-119180.B2IVT8.rst b/Misc/NEWS.d/next/Library/2024-07-23-22-26-00.gh-issue-119180.B2IVT8.rst deleted file mode 100644 index 13f51e4c42f4a0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-23-22-26-00.gh-issue-119180.B2IVT8.rst +++ /dev/null @@ -1,7 +0,0 @@ -As part of :pep:`749`, add the following attributes for customizing -evaluation of annotation scopes: - -* ``evaluate_value`` on :class:`typing.TypeAliasType` -* ``evaluate_bound``, ``evaluate_constraints``, and ``evaluate_default`` on :class:`typing.TypeVar` -* ``evaluate_default`` on :class:`typing.ParamSpec` -* ``evaluate_default`` on :class:`typing.TypeVarTuple` diff --git a/Misc/NEWS.d/next/Library/2024-07-24-08-48-22.gh-issue-122213.o3pdgA.rst b/Misc/NEWS.d/next/Library/2024-07-24-08-48-22.gh-issue-122213.o3pdgA.rst deleted file mode 100644 index 833a2a676f9298..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-24-08-48-22.gh-issue-122213.o3pdgA.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add notes for pickle serialization errors that allow to identify the source -of the error. diff --git a/Misc/NEWS.d/next/Library/2024-07-25-15-41-14.gh-issue-105733.o3koJA.rst b/Misc/NEWS.d/next/Library/2024-07-25-15-41-14.gh-issue-105733.o3koJA.rst deleted file mode 100644 index 60c5e69d2f6f9c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-25-15-41-14.gh-issue-105733.o3koJA.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`ctypes.ARRAY` is now :term:`soft deprecated`: it no longer emits deprecation -warnings and is not scheduled for removal. diff --git a/Misc/NEWS.d/next/Library/2024-07-26-21-21-13.gh-issue-122332.fvw88r.rst b/Misc/NEWS.d/next/Library/2024-07-26-21-21-13.gh-issue-122332.fvw88r.rst deleted file mode 100644 index 55bb1dc44add1b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-26-21-21-13.gh-issue-122332.fvw88r.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed segfault with :meth:`asyncio.Task.get_coro` when using an eager task -factory. diff --git a/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst b/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst deleted file mode 100644 index 83dd28d4ac575b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`email` headers with embedded newlines are now quoted on output. The -:mod:`~email.generator` will now refuse to serialize (write) headers that -are unsafely folded or delimited; see -:attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas -Bloemsaat and Petr Viktorin in :gh:`121650`.) diff --git a/Misc/NEWS.d/next/Library/2024-07-29-10-24-48.gh-issue-122311.xChV1b.rst b/Misc/NEWS.d/next/Library/2024-07-29-10-24-48.gh-issue-122311.xChV1b.rst deleted file mode 100644 index 8d70c610a8dad6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-29-10-24-48.gh-issue-122311.xChV1b.rst +++ /dev/null @@ -1 +0,0 @@ -Fix some error messages in :mod:`pickle`. diff --git a/Misc/NEWS.d/next/Library/2024-07-29-16-47-08.gh-issue-122400.fM0YSv.rst b/Misc/NEWS.d/next/Library/2024-07-29-16-47-08.gh-issue-122400.fM0YSv.rst deleted file mode 100644 index 8c47e94f78d9f0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-29-16-47-08.gh-issue-122400.fM0YSv.rst +++ /dev/null @@ -1,3 +0,0 @@ -Handle :exc:`ValueError`\s raised by :func:`os.stat` in -:class:`filecmp.dircmp` and :func:`filecmp.cmpfiles`. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-07-30-04-27-55.gh-issue-122272.6Wwa1V.rst b/Misc/NEWS.d/next/Library/2024-07-30-04-27-55.gh-issue-122272.6Wwa1V.rst deleted file mode 100644 index 943010b9c16c3c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-30-04-27-55.gh-issue-122272.6Wwa1V.rst +++ /dev/null @@ -1,2 +0,0 @@ -On some platforms such as Linux, year with century was not 0-padded when formatted by :meth:`~.datetime.strftime` with C99-specific specifiers ``'%C'`` or ``'%F'``. The 0-padding behavior is now guaranteed when the format specifiers ``'%C'`` and ``'%F'`` are supported by the C library. -Patch by Ben Hsing diff --git a/Misc/NEWS.d/next/Library/2024-07-30-14-46-16.gh-issue-87320.-Yk1wb.rst b/Misc/NEWS.d/next/Library/2024-07-30-14-46-16.gh-issue-87320.-Yk1wb.rst deleted file mode 100644 index 4322b719c690c2..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-30-14-46-16.gh-issue-87320.-Yk1wb.rst +++ /dev/null @@ -1,3 +0,0 @@ -In :class:`code.InteractiveInterpreter`, handle exceptions caused by calling a -non-default :func:`sys.excepthook`. Before, the exception bubbled up to the -caller, ending the :term:`REPL`. diff --git a/Misc/NEWS.d/next/Library/2024-07-30-15-57-07.gh-issue-122459.AYIoeN.rst b/Misc/NEWS.d/next/Library/2024-07-30-15-57-07.gh-issue-122459.AYIoeN.rst deleted file mode 100644 index 595504048302da..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-30-15-57-07.gh-issue-122459.AYIoeN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Optimize :mod:`pickling ` by name objects without the ``__module__`` -attribute. diff --git a/Misc/NEWS.d/next/Library/2024-07-30-21-29-30.gh-issue-122334.LeoE1x.rst b/Misc/NEWS.d/next/Library/2024-07-30-21-29-30.gh-issue-122334.LeoE1x.rst deleted file mode 100644 index cef801c950faa6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-30-21-29-30.gh-issue-122334.LeoE1x.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when importing :mod:`ssl` after the main interpreter restarts. diff --git a/Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst b/Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst deleted file mode 100644 index 8af016e7c82fcb..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-31-14-55-41.gh-issue-82378.eZvYmR.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make sure that the new :term:`REPL` interprets :data:`sys.tracebacklimit` in -the same way that the classic REPL did. diff --git a/Misc/NEWS.d/next/Library/2024-07-31-15-08-42.gh-issue-116622.aKxIQA.rst b/Misc/NEWS.d/next/Library/2024-07-31-15-08-42.gh-issue-116622.aKxIQA.rst deleted file mode 100644 index fc65b4d973b27d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-31-15-08-42.gh-issue-116622.aKxIQA.rst +++ /dev/null @@ -1,2 +0,0 @@ -On Android, the ``FICLONE`` and ``FICLONERANGE`` constants are no longer -exposed by :mod:`fcntl`, as these ioctls are blocked by SELinux. diff --git a/Misc/NEWS.d/next/Library/2024-07-31-20-43-21.gh-issue-122478.sCU2Le.rst b/Misc/NEWS.d/next/Library/2024-07-31-20-43-21.gh-issue-122478.sCU2Le.rst deleted file mode 100644 index 6071324593a9ed..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-07-31-20-43-21.gh-issue-122478.sCU2Le.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove internal frames from tracebacks shown in -:class:`code.InteractiveInterpreter` with non-default :func:`sys.excepthook`. -Save correct tracebacks in :attr:`sys.last_traceback` and update ``__traceback__`` attribute of :attr:`sys.last_value` and :attr:`sys.last_exc`. diff --git a/Misc/NEWS.d/next/Library/2024-08-03-06-51-08.gh-issue-122637.gpas8J.rst b/Misc/NEWS.d/next/Library/2024-08-03-06-51-08.gh-issue-122637.gpas8J.rst deleted file mode 100644 index 2ded33d75b35bd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-03-06-51-08.gh-issue-122637.gpas8J.rst +++ /dev/null @@ -1 +0,0 @@ -Adjust ``cmath.tanh(nanj)`` and ``cmath.tanh(infj)`` for recent C standards. diff --git a/Misc/NEWS.d/next/Library/2024-08-04-14-07-18.gh-issue-118814.uiyks1.rst b/Misc/NEWS.d/next/Library/2024-08-04-14-07-18.gh-issue-118814.uiyks1.rst deleted file mode 100644 index 14ef6c070603ae..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-04-14-07-18.gh-issue-118814.uiyks1.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the :class:`typing.TypeVar` constructor when name is passed by keyword. diff --git a/Misc/NEWS.d/next/Library/2024-08-06-07-24-00.gh-issue-118974.qamsCQ.rst b/Misc/NEWS.d/next/Library/2024-08-06-07-24-00.gh-issue-118974.qamsCQ.rst deleted file mode 100644 index 79480a69c1a90e..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-06-07-24-00.gh-issue-118974.qamsCQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``decorator`` parameter to :func:`dataclasses.make_dataclass` -to customize the functional creation of dataclasses. diff --git a/Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst b/Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst deleted file mode 100644 index 3f3e870b0b9565..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve import time of :mod:`pprint` by around seven times. Patch by Hugo -van Kemenade. diff --git a/Misc/NEWS.d/next/Library/2024-08-06-18-07-19.gh-issue-122744.kCzNDI.rst b/Misc/NEWS.d/next/Library/2024-08-06-18-07-19.gh-issue-122744.kCzNDI.rst deleted file mode 100644 index 18ac3dd10d6553..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-06-18-07-19.gh-issue-122744.kCzNDI.rst +++ /dev/null @@ -1 +0,0 @@ -Bump the version of pip bundled in ensurepip to version 24.2. diff --git a/Misc/NEWS.d/next/Library/2024-08-07-11-57-41.gh-issue-122311.LDExnJ.rst b/Misc/NEWS.d/next/Library/2024-08-07-11-57-41.gh-issue-122311.LDExnJ.rst deleted file mode 100644 index 07ade2034bfcf5..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-07-11-57-41.gh-issue-122311.LDExnJ.rst +++ /dev/null @@ -1,5 +0,0 @@ -Improve errors in the :mod:`pickle` module. :exc:`~pickle.PicklingError` is -now raised more often instead of :exc:`UnicodeEncodeError`, -:exc:`ValueError` and :exc:`AttributeError`, and the original exception is -chained to it. Improve and unify error messages in Python and C -implementations. diff --git a/Misc/NEWS.d/next/Library/2024-08-07-14-12-19.gh-issue-105376.QbGPdE.rst b/Misc/NEWS.d/next/Library/2024-08-07-14-12-19.gh-issue-105376.QbGPdE.rst deleted file mode 100644 index 9756a14cbcf67e..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-07-14-12-19.gh-issue-105376.QbGPdE.rst +++ /dev/null @@ -1,3 +0,0 @@ -Restore the deprecated :mod:`logging` ``warn()`` method. It was removed in -Python 3.13 alpha 1. Keep the deprecated ``warn()`` method in Python 3.13. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-08-07-17-41-16.gh-issue-116263.EcXir0.rst b/Misc/NEWS.d/next/Library/2024-08-07-17-41-16.gh-issue-116263.EcXir0.rst deleted file mode 100644 index 167ca943b3527c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-07-17-41-16.gh-issue-116263.EcXir0.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`logging.handlers.RotatingFileHandler` no longer rolls over empty log -files. diff --git a/Misc/NEWS.d/next/Library/2024-08-10-10-21-44.gh-issue-122858.ZC1rJD.rst b/Misc/NEWS.d/next/Library/2024-08-10-10-21-44.gh-issue-122858.ZC1rJD.rst deleted file mode 100644 index d452ad6a4f6d90..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-10-10-21-44.gh-issue-122858.ZC1rJD.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecate :func:`!asyncio.iscoroutinefunction` in favor of -:func:`inspect.iscoroutinefunction`. diff --git a/Misc/NEWS.d/next/Library/2024-08-10-14-16-59.gh-issue-122873.XlHaUn.rst b/Misc/NEWS.d/next/Library/2024-08-10-14-16-59.gh-issue-122873.XlHaUn.rst deleted file mode 100644 index 002ebd9d925956..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-10-14-16-59.gh-issue-122873.XlHaUn.rst +++ /dev/null @@ -1,3 +0,0 @@ -Enable :mod:`json` module to work as a script using the :option:`-m` switch: ``python -m json``. -See the :ref:`JSON command-line interface ` documentation. -Patch by Trey Hunner. diff --git a/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst b/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst deleted file mode 100644 index 1be44c906c4f30..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`zipfile.Path` objects now sanitize names from the zipfile. diff --git a/Misc/NEWS.d/next/Library/2024-08-11-14-23-07.gh-issue-122903.xktZta.rst b/Misc/NEWS.d/next/Library/2024-08-11-14-23-07.gh-issue-122903.xktZta.rst deleted file mode 100644 index c2a1e64d1f6db1..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-11-14-23-07.gh-issue-122903.xktZta.rst +++ /dev/null @@ -1,2 +0,0 @@ -``zipfile.Path.glob`` now correctly matches directories instead of -silently omitting them. diff --git a/Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst b/Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst deleted file mode 100644 index 7713d805155f9a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`inspect.getsource` for generated classes with Python base classes -(e.g. enums). diff --git a/Misc/NEWS.d/next/Library/2024-08-15-09-45-34.gh-issue-121735._1q0qf.rst b/Misc/NEWS.d/next/Library/2024-08-15-09-45-34.gh-issue-121735._1q0qf.rst deleted file mode 100644 index e10b2e760bc063..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-15-09-45-34.gh-issue-121735._1q0qf.rst +++ /dev/null @@ -1,3 +0,0 @@ -When working with zip archives, importlib.resources now properly honors -module-adjacent references (e.g. ``files(pkg.mod)`` and not just -``files(pkg)``). diff --git a/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst b/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst deleted file mode 100644 index 2faf85092a0f8a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add support for :const:`~configparser.UNNAMED_SECTION` -in :meth:`configparser.ConfigParser.add_section`. diff --git a/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst b/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst deleted file mode 100644 index 6a234561fe31a3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst +++ /dev/null @@ -1 +0,0 @@ -Fix quadratic complexity in parsing ``"``-quoted cookie values with backslashes by :mod:`http.cookies`. diff --git a/Misc/NEWS.d/next/Library/2024-08-17-08-17-20.gh-issue-123085.7Io2yH.rst b/Misc/NEWS.d/next/Library/2024-08-17-08-17-20.gh-issue-123085.7Io2yH.rst deleted file mode 100644 index 2e09401ceb5b56..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-17-08-17-20.gh-issue-123085.7Io2yH.rst +++ /dev/null @@ -1,3 +0,0 @@ -In a bare call to :func:`importlib.resources.files`, ensure the caller's -frame is properly detected when ``importlib.resources`` is itself available -as a compiled module only (no source). diff --git a/Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst b/Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst deleted file mode 100644 index eb01d66d98aef6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-18-08-25-32.gh-issue-123084.rf8izX.rst +++ /dev/null @@ -1,4 +0,0 @@ -Deprecate :class:`!shutil.ExecError`, which hasn't been -raised by any :mod:`shutil` function since Python 3.4. It's -now an alias for :exc:`RuntimeError`. - diff --git a/Misc/NEWS.d/next/Library/2024-08-19-17-37-18.gh-issue-122909.kP12SK.rst b/Misc/NEWS.d/next/Library/2024-08-19-17-37-18.gh-issue-122909.kP12SK.rst deleted file mode 100644 index 50eb4afd10791b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-19-17-37-18.gh-issue-122909.kP12SK.rst +++ /dev/null @@ -1,3 +0,0 @@ -In urllib.request when URLError is raised opening an ftp URL, the exception -argument is now consistently a string. Earlier versions passed either a -string or an ftplib exception instance as the argument to URLError. diff --git a/Misc/NEWS.d/next/Library/2024-08-20-14-22-49.gh-issue-123165.vOZZOA.rst b/Misc/NEWS.d/next/Library/2024-08-20-14-22-49.gh-issue-123165.vOZZOA.rst deleted file mode 100644 index 05728adc0be388..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-20-14-22-49.gh-issue-123165.vOZZOA.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for rendering :class:`~dis.Positions` in :mod:`dis`. diff --git a/Misc/NEWS.d/next/Library/2024-08-20-18-02-27.gh-issue-85110.8_iDQy.rst b/Misc/NEWS.d/next/Library/2024-08-20-18-02-27.gh-issue-85110.8_iDQy.rst deleted file mode 100644 index f22fac16b79c0b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-20-18-02-27.gh-issue-85110.8_iDQy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Preserve relative path in URL without netloc in -:func:`urllib.parse.urlunsplit` and :func:`urllib.parse.urlunparse`. diff --git a/Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst b/Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst deleted file mode 100644 index 5a31a00f2758f4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst +++ /dev/null @@ -1,3 +0,0 @@ -:meth:`xml.etree.ElementTree.Element.extend` and -:class:`~xml.etree.ElementTree.Element` assignment no longer hide the internal -exception if an erroneous generator is passed. Patch by Bar Harel. diff --git a/Misc/NEWS.d/next/Library/2024-08-22-11-25-19.gh-issue-122546.BSmeE7.rst b/Misc/NEWS.d/next/Library/2024-08-22-11-25-19.gh-issue-122546.BSmeE7.rst deleted file mode 100644 index 55681eced77666..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-22-11-25-19.gh-issue-122546.BSmeE7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Consistently use same file name for different exceptions in the new repl. -Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-08-22-20-10-13.gh-issue-123243.Kifj1L.rst b/Misc/NEWS.d/next/Library/2024-08-22-20-10-13.gh-issue-123243.Kifj1L.rst deleted file mode 100644 index cf52585020111f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-22-20-10-13.gh-issue-123243.Kifj1L.rst +++ /dev/null @@ -1 +0,0 @@ -Fix memory leak in :mod:`!_decimal`. diff --git a/Misc/NEWS.d/next/Library/2024-08-23-15-49-10.gh-issue-116810.QLBUU8.rst b/Misc/NEWS.d/next/Library/2024-08-23-15-49-10.gh-issue-116810.QLBUU8.rst deleted file mode 100644 index 0e5256e7151c5a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-23-15-49-10.gh-issue-116810.QLBUU8.rst +++ /dev/null @@ -1,4 +0,0 @@ -Resolve a memory leak introduced in CPython 3.10's :mod:`ssl` when the -:attr:`ssl.SSLSocket.session` property was accessed. Speeds up read and -write access to said property by no longer unnecessarily cloning session -objects via serialization. diff --git a/Misc/NEWS.d/next/Library/2024-08-23-22-01-30.gh-issue-76960.vsANPu.rst b/Misc/NEWS.d/next/Library/2024-08-23-22-01-30.gh-issue-76960.vsANPu.rst deleted file mode 100644 index acb0a991e4c93d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-23-22-01-30.gh-issue-76960.vsANPu.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix :func:`urllib.parse.urljoin` and :func:`urllib.parse.urldefrag` for URIs -containing empty components. For example, :func:`!urljoin` with relative -reference "?" now sets empty query and removes fragment. -Preserve empty components (authority, params, query, fragment) in :func:`!urljoin`. -Preserve empty components (authority, params, query) in :func:`!urldefrag`. diff --git a/Misc/NEWS.d/next/Library/2024-08-24-00-03-01.gh-issue-123240.uFPG3l.rst b/Misc/NEWS.d/next/Library/2024-08-24-00-03-01.gh-issue-123240.uFPG3l.rst deleted file mode 100644 index e6ea6c33f89762..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-24-00-03-01.gh-issue-123240.uFPG3l.rst +++ /dev/null @@ -1 +0,0 @@ -Raise audit events for the :func:`input` in the new REPL. diff --git a/Misc/NEWS.d/next/Library/2024-08-24-06-05-41.gh-issue-123228.jR_5O5.rst b/Misc/NEWS.d/next/Library/2024-08-24-06-05-41.gh-issue-123228.jR_5O5.rst deleted file mode 100644 index 99b3c0ca5eef28..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-24-06-05-41.gh-issue-123228.jR_5O5.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix return type for -:func:`!_pyrepl.readline._ReadlineWrapper.get_line_buffer` to be -:func:`str`. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-08-25-16-59-20.gh-issue-73991.1w8u3K.rst b/Misc/NEWS.d/next/Library/2024-08-25-16-59-20.gh-issue-73991.1w8u3K.rst deleted file mode 100644 index 4ad5a06709de73..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-25-16-59-20.gh-issue-73991.1w8u3K.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :meth:`pathlib.Path.copy_into` and :meth:`~pathlib.Path.move_into`, -which copy and move files and directories into *existing* directories. diff --git a/Misc/NEWS.d/next/Library/2024-08-26-13-45-20.gh-issue-123270.gXHvNJ.rst b/Misc/NEWS.d/next/Library/2024-08-26-13-45-20.gh-issue-123270.gXHvNJ.rst deleted file mode 100644 index ee9fde6a9ed87a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-26-13-45-20.gh-issue-123270.gXHvNJ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Applied a more surgical fix for malformed payloads in :class:`zipfile.Path` -causing infinite loops (gh-122905) without breaking contents using -legitimate characters. diff --git a/Misc/NEWS.d/next/Library/2024-08-26-18-48-13.gh-issue-119518.QFYH9q.rst b/Misc/NEWS.d/next/Library/2024-08-26-18-48-13.gh-issue-119518.QFYH9q.rst deleted file mode 100644 index 819295f7306fa4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-26-18-48-13.gh-issue-119518.QFYH9q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Speed up normalization of :class:`pathlib.PurePath` and -:class:`~pathlib.Path` objects by not interning string parts. diff --git a/Misc/NEWS.d/next/Library/2024-08-26-19-36-00.gh-issue-123340.mQKI1H.rst b/Misc/NEWS.d/next/Library/2024-08-26-19-36-00.gh-issue-123340.mQKI1H.rst deleted file mode 100644 index 8a462b2300466e..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-26-19-36-00.gh-issue-123340.mQKI1H.rst +++ /dev/null @@ -1 +0,0 @@ -Show string value of :opcode:`IS_OP` oparg in :mod:`dis` output. diff --git a/Misc/NEWS.d/next/Library/2024-08-27-10-30-37.gh-issue-123341.5e-fjt.rst b/Misc/NEWS.d/next/Library/2024-08-27-10-30-37.gh-issue-123341.5e-fjt.rst deleted file mode 100644 index 61561eeb807023..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-27-10-30-37.gh-issue-123341.5e-fjt.rst +++ /dev/null @@ -1 +0,0 @@ -Add :meth:`~object.__class_getitem__` to :class:`!tkinter.Event` for type subscript support at runtime. Patch by Adonis Rakateli. diff --git a/Misc/NEWS.d/next/Library/2024-08-27-12-11-00.gh-issue-123363.gKuJp6.rst b/Misc/NEWS.d/next/Library/2024-08-27-12-11-00.gh-issue-123363.gKuJp6.rst deleted file mode 100644 index c1f92c4d54dbb0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-27-12-11-00.gh-issue-123363.gKuJp6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Show string value of :opcode:`CONTAINS_OP` oparg in :mod:`dis` output. -Patch by Alexandr153. diff --git a/Misc/NEWS.d/next/Library/2024-08-27-12-38-42.gh-issue-123089.vA7iFR.rst b/Misc/NEWS.d/next/Library/2024-08-27-12-38-42.gh-issue-123089.vA7iFR.rst deleted file mode 100644 index 74cbdd551350f7..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-27-12-38-42.gh-issue-123089.vA7iFR.rst +++ /dev/null @@ -1 +0,0 @@ -Make :class:`weakref.WeakSet` safe against concurrent mutations while it is being iterated. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2024-08-28-13-03-36.gh-issue-123409.lW0YF-.rst b/Misc/NEWS.d/next/Library/2024-08-28-13-03-36.gh-issue-123409.lW0YF-.rst deleted file mode 100644 index 7c6aab632b674a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-28-13-03-36.gh-issue-123409.lW0YF-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :attr:`ipaddress.IPv6Address.reverse_pointer` output according to -:rfc:`RFC 3596, §2.5 <3596#section-2.5>`. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-08-28-20-08-19.gh-issue-123448.tItJlp.rst b/Misc/NEWS.d/next/Library/2024-08-28-20-08-19.gh-issue-123448.tItJlp.rst deleted file mode 100644 index a57c133d43545f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-28-20-08-19.gh-issue-123448.tItJlp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed memory leak of :class:`typing.NoDefault` by moving it to the static types -array. diff --git a/Misc/NEWS.d/next/Library/2024-08-29-09-27-12.gh-issue-123446._I_mMr.rst b/Misc/NEWS.d/next/Library/2024-08-29-09-27-12.gh-issue-123446._I_mMr.rst deleted file mode 100644 index 871b2fb2b646e7..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-29-09-27-12.gh-issue-123446._I_mMr.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix empty function name in :exc:`TypeError` when :func:`csv.reader`, -:func:`csv.writer`, or :func:`csv.register_dialect` are used without the -required args. diff --git a/Misc/NEWS.d/next/Library/2024-08-29-14-51-36.gh-issue-123430.M7wXl9.rst b/Misc/NEWS.d/next/Library/2024-08-29-14-51-36.gh-issue-123430.M7wXl9.rst deleted file mode 100644 index 0afdad7917fa8f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-29-14-51-36.gh-issue-123430.M7wXl9.rst +++ /dev/null @@ -1 +0,0 @@ -Pages generated by the :mod:`http.server` module allow the browser to apply its default dark mode. diff --git a/Misc/NEWS.d/next/Library/2024-08-30-09-01-35.gh-issue-123504.lJ9_BB.rst b/Misc/NEWS.d/next/Library/2024-08-30-09-01-35.gh-issue-123504.lJ9_BB.rst deleted file mode 100644 index ea504d3532dc44..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-30-09-01-35.gh-issue-123504.lJ9_BB.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed reference leak in the finalization of :mod:`tkinter`. diff --git a/Misc/NEWS.d/next/Library/2024-08-31-12-34-44.gh-issue-123374.3kE7rb.rst b/Misc/NEWS.d/next/Library/2024-08-31-12-34-44.gh-issue-123374.3kE7rb.rst deleted file mode 100644 index 2fac9079b69e44..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-08-31-12-34-44.gh-issue-123374.3kE7rb.rst +++ /dev/null @@ -1 +0,0 @@ -Remove check for redefined memo entry in :func:`pickletools.dis`. diff --git a/Misc/NEWS.d/next/Library/2024-09-02-20-34-04.gh-issue-123339.czgcSu.rst b/Misc/NEWS.d/next/Library/2024-09-02-20-34-04.gh-issue-123339.czgcSu.rst deleted file mode 100644 index e388541f1c2c19..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-02-20-34-04.gh-issue-123339.czgcSu.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix :func:`inspect.getsource` for classes in :mod:`collections.abc` and -:mod:`decimal` (for pure Python implementation) modules. -:func:`inspect.getcomments` now raises OSError instead of IndexError if the -``__firstlineno__`` value for a class is out of bound. diff --git a/Misc/NEWS.d/next/Library/2024-09-04-18-23-43.gh-issue-123657.Oks4So.rst b/Misc/NEWS.d/next/Library/2024-09-04-18-23-43.gh-issue-123657.Oks4So.rst deleted file mode 100644 index efebd21e26962a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-04-18-23-43.gh-issue-123657.Oks4So.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash and memory leak in :func:`decimal.getcontext`. It crashed when using -a thread-local context by ``--with-decimal-contextvar=no``. diff --git a/Misc/NEWS.d/next/Library/2024-09-06-00-00-43.gh-issue-122765.tx4hsr.rst b/Misc/NEWS.d/next/Library/2024-09-06-00-00-43.gh-issue-122765.tx4hsr.rst deleted file mode 100644 index 8a1bc4bce81d76..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-06-00-00-43.gh-issue-122765.tx4hsr.rst +++ /dev/null @@ -1 +0,0 @@ -Fix unbalanced quote errors occurring when activate.csh in :mod:`venv` was sourced with a custom prompt containing unpaired quotes or newlines. diff --git a/Misc/NEWS.d/next/Library/2024-09-06-01-35-11.gh-issue-123756.Ozbhke.rst b/Misc/NEWS.d/next/Library/2024-09-06-01-35-11.gh-issue-123756.Ozbhke.rst deleted file mode 100644 index 258dd591fce767..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-06-01-35-11.gh-issue-123756.Ozbhke.rst +++ /dev/null @@ -1 +0,0 @@ -Added a new argument ``mode`` to :class:`pdb.Pdb`. Only allow :mod:`pdb` from command line to use ``restart`` command. diff --git a/Misc/NEWS.d/next/Library/2024-09-06-10-17-54.gh-issue-84808.ION67Z.rst b/Misc/NEWS.d/next/Library/2024-09-06-10-17-54.gh-issue-84808.ION67Z.rst deleted file mode 100644 index c804c5974241bf..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-06-10-17-54.gh-issue-84808.ION67Z.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix error handling in :py:class:`~socket.socket` method -:py:func:`~socket.socket.connect_ex` on platforms where -:c:data:`errno` can be negative. diff --git a/Misc/NEWS.d/next/Library/2024-09-10-11-26-14.gh-issue-123892.2gzIrz.rst b/Misc/NEWS.d/next/Library/2024-09-10-11-26-14.gh-issue-123892.2gzIrz.rst deleted file mode 100644 index bef534427d9a67..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-10-11-26-14.gh-issue-123892.2gzIrz.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``"_wmi"`` to :data:`sys.stdlib_module_names`. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-09-11-13-33-19.gh-issue-123935.fRZ_56.rst b/Misc/NEWS.d/next/Library/2024-09-11-13-33-19.gh-issue-123935.fRZ_56.rst deleted file mode 100644 index de720c3714c6ff..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-11-13-33-19.gh-issue-123935.fRZ_56.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix parent slots detection for dataclasses that inherit from classes with -``__dictoffset__``. diff --git a/Misc/NEWS.d/next/Library/2024-09-11-19-05-32.gh-issue-123945.jLwybB.rst b/Misc/NEWS.d/next/Library/2024-09-11-19-05-32.gh-issue-123945.jLwybB.rst deleted file mode 100644 index 26b0ac80b1b3fd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-11-19-05-32.gh-issue-123945.jLwybB.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a bug where :mod:`argparse` doesn't recognize negative numbers with underscores diff --git a/Misc/NEWS.d/next/Library/2024-09-11-19-12-23.gh-issue-123968.OwHON_.rst b/Misc/NEWS.d/next/Library/2024-09-11-19-12-23.gh-issue-123968.OwHON_.rst deleted file mode 100644 index 4d4894716b7144..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-11-19-12-23.gh-issue-123968.OwHON_.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the command-line interface for the :mod:`random` module to select floats between 0 and N, not 1 and N. diff --git a/Misc/NEWS.d/next/Library/2024-09-12-10-55-19.gh-issue-124016.ncs0hd.rst b/Misc/NEWS.d/next/Library/2024-09-12-10-55-19.gh-issue-124016.ncs0hd.rst deleted file mode 100644 index ac2aa8a983be5d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-12-10-55-19.gh-issue-124016.ncs0hd.rst +++ /dev/null @@ -1 +0,0 @@ -Update :mod:`unicodedata` database to Unicode 16.0.0. diff --git a/Misc/NEWS.d/next/Library/2024-09-13-10-34-19.gh-issue-123934.yMe7mL.rst b/Misc/NEWS.d/next/Library/2024-09-13-10-34-19.gh-issue-123934.yMe7mL.rst deleted file mode 100644 index 641c21331e3e54..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-13-10-34-19.gh-issue-123934.yMe7mL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :class:`unittest.mock.MagicMock` resetting magic methods return values -after ``.reset_mock(return_value=True)`` was called. diff --git a/Misc/NEWS.d/next/Library/2024-09-16-12-31-48.gh-issue-123978.z3smEu.rst b/Misc/NEWS.d/next/Library/2024-09-16-12-31-48.gh-issue-123978.z3smEu.rst deleted file mode 100644 index e5b3229122b509..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-16-12-31-48.gh-issue-123978.z3smEu.rst +++ /dev/null @@ -1 +0,0 @@ -Remove broken :func:`time.thread_time` and :func:`time.thread_time_ns` on NetBSD. diff --git a/Misc/NEWS.d/next/Library/2024-09-17-18-06-42.gh-issue-124171.PHCvRJ.rst b/Misc/NEWS.d/next/Library/2024-09-17-18-06-42.gh-issue-124171.PHCvRJ.rst deleted file mode 100644 index c2f0bb14f55251..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-17-18-06-42.gh-issue-124171.PHCvRJ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add workaround for broken :c:func:`!fmod()` implementations on Windows, that -loose zero sign (e.g. ``fmod(-10, 1)`` returns ``0.0``). Patch by Sergey B -Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2024-09-18-17-45-52.gh-issue-124212.n6kIby.rst b/Misc/NEWS.d/next/Library/2024-09-18-17-45-52.gh-issue-124212.n6kIby.rst deleted file mode 100644 index 7848f26511e282..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-18-17-45-52.gh-issue-124212.n6kIby.rst +++ /dev/null @@ -1 +0,0 @@ -Fix invalid variable in :mod:`venv` handling of failed symlink on Windows diff --git a/Misc/NEWS.d/next/Library/2024-09-19-00-09-48.gh-issue-84559.IrxvQe.rst b/Misc/NEWS.d/next/Library/2024-09-19-00-09-48.gh-issue-84559.IrxvQe.rst deleted file mode 100644 index a4428e20f3ccdd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-19-00-09-48.gh-issue-84559.IrxvQe.rst +++ /dev/null @@ -1,5 +0,0 @@ -The default :mod:`multiprocessing` start method on Linux and other POSIX -systems has been changed away from often unsafe ``"fork"`` to ``"forkserver"`` -(when the platform supports sending file handles over pipes as most do) or -``"spawn"``. Mac and Windows are unchanged as they already default to -``"spawn"``. diff --git a/Misc/NEWS.d/next/Library/2024-09-19-03-46-59.gh-issue-87041.9Ox7Bv.rst b/Misc/NEWS.d/next/Library/2024-09-19-03-46-59.gh-issue-87041.9Ox7Bv.rst deleted file mode 100644 index 47a5f0c7ba520f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-19-03-46-59.gh-issue-87041.9Ox7Bv.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a bug in :mod:`argparse` where lengthy subparser argument help is incorrectly indented. diff --git a/Misc/NEWS.d/next/Library/2024-09-19-10-36-18.gh-issue-81691.Hyhp_U.rst b/Misc/NEWS.d/next/Library/2024-09-19-10-36-18.gh-issue-81691.Hyhp_U.rst deleted file mode 100644 index 8f0108502efde6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-19-10-36-18.gh-issue-81691.Hyhp_U.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix handling of multiple ``"--"`` (double dashes) in :mod:`argparse`. Only -the first one has now been removed, all subsequent ones are now taken -literally. diff --git a/Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst b/Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst deleted file mode 100644 index 1bd333f485a2ab..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed potential crash when using :mod:`struct` to process zero-width -'Pascal string' fields (``0p``). diff --git a/Misc/NEWS.d/next/Library/2024-09-19-16-00-22.gh-issue-111513.6jHm02.rst b/Misc/NEWS.d/next/Library/2024-09-19-16-00-22.gh-issue-111513.6jHm02.rst deleted file mode 100644 index c6b85f9cd72255..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-19-16-00-22.gh-issue-111513.6jHm02.rst +++ /dev/null @@ -1 +0,0 @@ -Improve the error message that may be raised by :meth:`datetime.date.fromtimestamp`. diff --git a/Misc/NEWS.d/next/Library/2024-09-19-20-15-00.gh-issue-124217.j0KlQB.rst b/Misc/NEWS.d/next/Library/2024-09-19-20-15-00.gh-issue-124217.j0KlQB.rst deleted file mode 100644 index 46f9866f8d427c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-19-20-15-00.gh-issue-124217.j0KlQB.rst +++ /dev/null @@ -1 +0,0 @@ -Add RFC 9637 reserved IPv6 block ``3fff::/20`` in :mod:`ipaddress` module. diff --git a/Misc/NEWS.d/next/Library/2024-09-20-12-23-11.gh-issue-53780.mrV1zi.rst b/Misc/NEWS.d/next/Library/2024-09-20-12-23-11.gh-issue-53780.mrV1zi.rst deleted file mode 100644 index fb700c722c8a8b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-20-12-23-11.gh-issue-53780.mrV1zi.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`argparse` now ignores the first ``"--"`` (double dash) between an option and command. diff --git a/Misc/NEWS.d/next/Library/2024-09-20-18-23-19.gh-issue-100980.8nVAB6.rst b/Misc/NEWS.d/next/Library/2024-09-20-18-23-19.gh-issue-100980.8nVAB6.rst deleted file mode 100644 index 2279c205caeced..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-20-18-23-19.gh-issue-100980.8nVAB6.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :attr:`~ctypes.Structure._fields_` attribute of -:class:`ctypes.Structure` and :class:`~ctypes.Union` is no longer set if -the setattr operation raises an error. diff --git a/Misc/NEWS.d/next/Library/2024-09-21-19-02-37.gh-issue-59317.OAhNZZ.rst b/Misc/NEWS.d/next/Library/2024-09-21-19-02-37.gh-issue-59317.OAhNZZ.rst deleted file mode 100644 index 0b1df9e3b7dea8..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-21-19-02-37.gh-issue-59317.OAhNZZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix parsing positional argument with :ref:`nargs` equal to ``'?'`` or ``'*'`` -if it is preceded by an option and another positional argument. diff --git a/Misc/NEWS.d/next/Library/2024-09-21-22-32-21.gh-issue-72795.naLmkX.rst b/Misc/NEWS.d/next/Library/2024-09-21-22-32-21.gh-issue-72795.naLmkX.rst deleted file mode 100644 index 15c0918097367f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-21-22-32-21.gh-issue-72795.naLmkX.rst +++ /dev/null @@ -1,4 +0,0 @@ -Positional arguments with :ref:`nargs` equal to ``'*'`` or -:data:`!argparse.REMAINDER` are no longer required. This allows to use -positional argument with ``nargs='*'`` and without ``default`` in mutually -exclusive group and improves error message about required arguments. diff --git a/Misc/NEWS.d/next/Library/2024-09-21-23-56-41.gh-issue-63143.YKu-LQ.rst b/Misc/NEWS.d/next/Library/2024-09-21-23-56-41.gh-issue-63143.YKu-LQ.rst deleted file mode 100644 index cb031fd601a9bd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-21-23-56-41.gh-issue-63143.YKu-LQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix parsing mutually exclusive arguments in :mod:`argparse`. Arguments with -the value identical to the default value (e.g. booleans, small integers, -empty or 1-character strings) are no longer considered "not present". diff --git a/Misc/NEWS.d/next/Library/2024-09-23-17-33-47.gh-issue-104860.O86OSc.rst b/Misc/NEWS.d/next/Library/2024-09-23-17-33-47.gh-issue-104860.O86OSc.rst deleted file mode 100644 index 707c4d651cb5e6..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-23-17-33-47.gh-issue-104860.O86OSc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix disallowing abbreviation of single-dash long options in :mod:`argparse` -with ``allow_abbrev=False``. diff --git a/Misc/NEWS.d/next/Library/2024-09-23-18-26-17.gh-issue-90562.Yj566G.rst b/Misc/NEWS.d/next/Library/2024-09-23-18-26-17.gh-issue-90562.Yj566G.rst deleted file mode 100644 index 7a389fefc6c54b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-23-18-26-17.gh-issue-90562.Yj566G.rst +++ /dev/null @@ -1,3 +0,0 @@ -Modify dataclasses to support zero-argument super() when ``slots=True`` is -specified. This works by modifying all references to ``__class__`` to point -to the newly created class. diff --git a/Misc/NEWS.d/next/Library/2024-09-24-00-01-24.gh-issue-124400.0XCgfe.rst b/Misc/NEWS.d/next/Library/2024-09-24-00-01-24.gh-issue-124400.0XCgfe.rst deleted file mode 100644 index 25ee01e3108bf8..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-24-00-01-24.gh-issue-124400.0XCgfe.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a :mod:`pdb` bug where ``until`` has no effect when it appears in a ``commands`` sequence. Also avoid printing the frame information at a breakpoint that has a command list containing a command that resumes execution. diff --git a/Misc/NEWS.d/next/Library/2024-09-24-12-34-48.gh-issue-124345.s3vKql.rst b/Misc/NEWS.d/next/Library/2024-09-24-12-34-48.gh-issue-124345.s3vKql.rst deleted file mode 100644 index dff902d8c6139a..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-24-12-34-48.gh-issue-124345.s3vKql.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`argparse` vim supports abbreviated single-dash long options separated -by ``=`` from its value. diff --git a/Misc/NEWS.d/next/Library/2024-09-24-13-32-16.gh-issue-124176.6hmOPz.rst b/Misc/NEWS.d/next/Library/2024-09-24-13-32-16.gh-issue-124176.6hmOPz.rst deleted file mode 100644 index 38c030668b6b42..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-24-13-32-16.gh-issue-124176.6hmOPz.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add support for :func:`dataclasses.dataclass` in -:func:`unittest.mock.create_autospec`. Now ``create_autospec`` will check -for potential dataclasses and use :func:`dataclasses.fields` function to -retrieve the spec information. diff --git a/Misc/NEWS.d/next/Library/2024-09-24-19-32-14.gh-issue-123014.zVcfkZ.rst b/Misc/NEWS.d/next/Library/2024-09-24-19-32-14.gh-issue-123014.zVcfkZ.rst deleted file mode 100644 index 53dbabd9480ddb..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-24-19-32-14.gh-issue-123014.zVcfkZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`os.pidfd_open` and :func:`signal.pidfd_send_signal` are now -unavailable when building against Android API levels older than 31, since -the underlying system calls may cause a crash. diff --git a/Misc/NEWS.d/next/Library/2024-09-24-21-15-27.gh-issue-123017.dSAr2f.rst b/Misc/NEWS.d/next/Library/2024-09-24-21-15-27.gh-issue-123017.dSAr2f.rst deleted file mode 100644 index 45fe4786fa6563..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-24-21-15-27.gh-issue-123017.dSAr2f.rst +++ /dev/null @@ -1,2 +0,0 @@ -Due to unreliable results on some devices, :func:`time.strftime` no longer -accepts negative years on Android. diff --git a/Misc/NEWS.d/next/Library/2024-09-24-22-38-51.gh-issue-123884.iEPTK4.rst b/Misc/NEWS.d/next/Library/2024-09-24-22-38-51.gh-issue-123884.iEPTK4.rst deleted file mode 100644 index 55f1d4b41125c3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-24-22-38-51.gh-issue-123884.iEPTK4.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixed bug in itertools.tee() handling of other tee inputs (a tee in a tee). -The output now has the promised *n* independent new iterators. Formerly, -the first iterator was identical (not independent) to the input iterator. -This would sometimes give surprising results. diff --git a/Misc/NEWS.d/next/Library/2024-09-25-10-25-57.gh-issue-53834.uyIckw.rst b/Misc/NEWS.d/next/Library/2024-09-25-10-25-57.gh-issue-53834.uyIckw.rst deleted file mode 100644 index 20ba1534f5e99d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-25-10-25-57.gh-issue-53834.uyIckw.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix support of arguments with :ref:`choices` in :mod:`argparse`. Positional -arguments with :ref:`nargs` equal to ``'?'`` or ``'*'`` no longer check -:ref:`default` against ``choices``. Optional arguments with ``nargs`` equal -to ``'?'`` no longer check :ref:`const` against ``choices``. diff --git a/Misc/NEWS.d/next/Library/2024-09-25-12-14-58.gh-issue-124498.Ozxs55.rst b/Misc/NEWS.d/next/Library/2024-09-25-12-14-58.gh-issue-124498.Ozxs55.rst deleted file mode 100644 index 4dbf4eb709733d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-25-12-14-58.gh-issue-124498.Ozxs55.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :class:`typing.TypeAliasType` not to be generic, when ``type_params`` is -an empty tuple. diff --git a/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst b/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst deleted file mode 100644 index 1a8c1427b6b9b9..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash related to an integer overflow in :func:`curses.resizeterm` -and :func:`curses.resize_term`. diff --git a/Misc/NEWS.d/next/Library/2024-09-25-18-08-29.gh-issue-80259.kO5Tw7.rst b/Misc/NEWS.d/next/Library/2024-09-25-18-08-29.gh-issue-80259.kO5Tw7.rst deleted file mode 100644 index bb451cdd9ae44c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-25-18-08-29.gh-issue-80259.kO5Tw7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :mod:`argparse` support of positional arguments with ``nargs='?'``, -``default=argparse.SUPPRESS`` and specified ``type``. diff --git a/Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst b/Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst deleted file mode 100644 index 33ae037ae56b0b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed crash when using :func:`gc.get_referents` on a capsule object. diff --git a/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst b/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst deleted file mode 100644 index 39dde4c774ba5d..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst +++ /dev/null @@ -1 +0,0 @@ -Improve the accuracy of :mod:`bdb`'s check for the possibility of breakpoint in a frame. This makes it possible to disable unnecessary events in functions. diff --git a/Misc/NEWS.d/next/Library/2024-09-26-00-35-24.gh-issue-116750.X1aMHI.rst b/Misc/NEWS.d/next/Library/2024-09-26-00-35-24.gh-issue-116750.X1aMHI.rst deleted file mode 100644 index cf9dacf4007c28..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-26-00-35-24.gh-issue-116750.X1aMHI.rst +++ /dev/null @@ -1 +0,0 @@ -Provide :func:`sys.monitoring.clear_tool_id` to unregister all events and callbacks set by the tool. diff --git a/Misc/NEWS.d/next/Library/2024-09-26-09-18-09.gh-issue-61181.dwjmch.rst b/Misc/NEWS.d/next/Library/2024-09-26-09-18-09.gh-issue-61181.dwjmch.rst deleted file mode 100644 index 801a5fdd4abd4f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-26-09-18-09.gh-issue-61181.dwjmch.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix support of :ref:`choices` with string value in :mod:`argparse`. Substrings -of the specified string no longer considered valid values. diff --git a/Misc/NEWS.d/next/Library/2024-09-26-13-43-39.gh-issue-124594.peYhsP.rst b/Misc/NEWS.d/next/Library/2024-09-26-13-43-39.gh-issue-124594.peYhsP.rst deleted file mode 100644 index ac48bd84930745..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-26-13-43-39.gh-issue-124594.peYhsP.rst +++ /dev/null @@ -1 +0,0 @@ -All :mod:`asyncio` REPL prompts run in the same :class:`context `. Contributed by Bartosz Sławecki. diff --git a/Misc/NEWS.d/next/Library/2024-09-26-22-14-12.gh-issue-58573.hozbm9.rst b/Misc/NEWS.d/next/Library/2024-09-26-22-14-12.gh-issue-58573.hozbm9.rst deleted file mode 100644 index 37d64ee536ff49..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-26-22-14-12.gh-issue-58573.hozbm9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix conflicts between abbreviated long options in the parent parser and -subparsers in :mod:`argparse`. diff --git a/Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst b/Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst deleted file mode 100644 index 913a84de5fe6a3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-27-06-39-32.gh-issue-101552.xYkzag.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add an *annoation_format* parameter to :func:`inspect.signature`. Add an -*quote_annotation_strings* parameter to :meth:`inspect.Signature.format`. Use the -new functionality to improve the display of annotations in signatures in -:mod:`pydoc`. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2024-09-27-15-16-04.gh-issue-116850.dBkR0-.rst b/Misc/NEWS.d/next/Library/2024-09-27-15-16-04.gh-issue-116850.dBkR0-.rst deleted file mode 100644 index 62639a16c52aa0..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-27-15-16-04.gh-issue-116850.dBkR0-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :mod:`argparse` for namespaces with not directly writable dict (e.g. -classes). diff --git a/Misc/NEWS.d/next/Library/2024-09-30-19-59-28.gh-issue-66436.4gYN_n.rst b/Misc/NEWS.d/next/Library/2024-09-30-19-59-28.gh-issue-66436.4gYN_n.rst deleted file mode 100644 index 69a77b01902873..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-30-19-59-28.gh-issue-66436.4gYN_n.rst +++ /dev/null @@ -1,4 +0,0 @@ -Improved :ref:`prog` default value for :class:`argparse.ArgumentParser`. It -will now include the name of the Python executable along with the module or -package name, or the path to a directory, ZIP file, or directory within a -ZIP file if the code was run that way. diff --git a/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst b/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst deleted file mode 100644 index d9d1bbcf5a2fe4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix :class:`typing.TypeAliasType` with incorrect ``type_params`` argument. -Now it raises a :exc:`TypeError` when a type parameter without a default -follows one with a default, and when an entry in the ``type_params`` tuple -is not a type parameter object. diff --git a/Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst b/Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst deleted file mode 100644 index 3e87eb457d9911..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-01-02-31-13.gh-issue-124693.qzbXKB.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a bug where :mod:`argparse` doesn't recognize negative complex numbers or negative numbers using scientific notation. diff --git a/Misc/NEWS.d/next/Library/2024-10-01-12-43-42.gh-issue-124835.SVyp3K.rst b/Misc/NEWS.d/next/Library/2024-10-01-12-43-42.gh-issue-124835.SVyp3K.rst deleted file mode 100644 index 09e5a046f83e49..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-01-12-43-42.gh-issue-124835.SVyp3K.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make :func:`tomllib.loads` raise :exc:`TypeError` not :exc:`AttributeError` -on bad input types that do not have the ``replace`` attribute. Improve error -message when :class:`bytes` is received. diff --git a/Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst b/Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst deleted file mode 100644 index 553f206bf26337..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-01-13-11-53.gh-issue-85935.CTwJUy.rst +++ /dev/null @@ -1,4 +0,0 @@ -:meth:`argparse.ArgumentParser.add_argument` now raises an exception if -an :ref:`action` that does not consume arguments (like 'store_const' or -'store_true') or explicit ``nargs=0`` are specified for positional -arguments. diff --git a/Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst b/Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst deleted file mode 100644 index 89610fa44bf743..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed :exc:`AssertionError` when using :func:`!asyncio.staggered.staggered_race` with :attr:`asyncio.eager_task_factory`. diff --git a/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst b/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst deleted file mode 100644 index c05d24a7c5aacb..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst +++ /dev/null @@ -1 +0,0 @@ -Fix reference cycles left in tracebacks in :func:`asyncio.open_connection` when used with ``happy_eyeballs_delay`` diff --git a/Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst b/Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst deleted file mode 100644 index f45f00e48a3830..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-01-23-29-09.gh-issue-91818.Kz8cPI.rst +++ /dev/null @@ -1,4 +0,0 @@ -The CLI of many modules (:mod:`ast`, :mod:`ensurepip`, :mod:`json`, -:mod:`pdb`, :mod:`sqlite3`, :mod:`tokenize`, :mod:`venv`) now uses the -actual executable name instead of simply "python" to display in the usage -message. diff --git a/Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst b/Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst deleted file mode 100644 index 6f5ad12d2c2981..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-02-15-05-45.gh-issue-124653.tqsTu9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix detection of the minimal Queue API needed by the :mod:`logging` module. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst b/Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst deleted file mode 100644 index 106a8b81140520..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-02-16-35-07.gh-issue-65865.S2D4wq.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`argparse` now raises early error for invalid ``help`` arguments to -:meth:`~argparse.ArgumentParser.add_argument`, -:meth:`~argparse.ArgumentParser.add_subparsers` and :meth:`!add_parser`. diff --git a/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst deleted file mode 100644 index f208793859bbf8..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow calling :func:`os.path.exists` and :func:`os.path.lexists` with -keyword arguments on Windows. Fixes a regression in 3.13.0. diff --git a/Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst b/Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst deleted file mode 100644 index 0e708ed11d21b5..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-02-22-53-48.gh-issue-90102.4qX52R.rst +++ /dev/null @@ -1,3 +0,0 @@ -Skip the ``isatty`` system call during open() when the file is known to not -be a character device. This provides a slight performance improvement when -reading whole files. diff --git a/Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst b/Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst deleted file mode 100644 index a7d6251f1e071f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-03-05-00-25.gh-issue-117151.Prdw_W.rst +++ /dev/null @@ -1,3 +0,0 @@ -The default buffer size used by :func:`shutil.copyfileobj` has been -increased from 64k to 256k on non-Windows platforms. It was already larger -on Windows. diff --git a/Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst b/Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst deleted file mode 100644 index 66af712c5ae5a8..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-03-17-13-22.gh-issue-124944.YyLAzf.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``SO_ORIGINAL_DST`` to the :mod:`socket` module. diff --git a/Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst b/Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst deleted file mode 100644 index b637b895d0b803..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-03-19-16-38.gh-issue-123961.ik1Dgs.rst +++ /dev/null @@ -1,2 +0,0 @@ -Convert :mod:`curses` to multi-phase initialization (:pep:`489`), thereby -fixing reference leaks at interpreter shutdown. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst b/Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst deleted file mode 100644 index 6895cffcf545fd..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-03-20-45-57.gh-issue-53203.3Sk4Ia.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix :func:`time.strptime` for ``%c`` and ``%x`` formats in many locales: -Arabic, Bislama, Breton, Bodo, Kashubian, Chuvash, Estonian, French, Irish, -Ge'ez, Gurajati, Manx Gaelic, Hebrew, Hindi, Chhattisgarhi, Haitian Kreyol, -Japanese, Kannada, Korean, Marathi, Malay, Norwegian, Nynorsk, Punjabi, -Rajasthani, Tok Pisin, Yoruba, Yue Chinese, Yau/Nungon and Chinese. diff --git a/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst b/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst deleted file mode 100644 index 534d5bb8c898da..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst +++ /dev/null @@ -1 +0,0 @@ -Fix refcycles in exceptions raised from :class:`asyncio.TaskGroup` and the python implementation of :class:`asyncio.Future` diff --git a/Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst b/Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst deleted file mode 100644 index 65388e0b4e7ee4..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-04-12-43-03.gh-issue-69998.DVqOXX.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :func:`locale.nl_langinfo` in case when different categories have -different locales. The function now sets temporarily the ``LC_CTYPE`` locale -in some cases. This temporary change affects other threads. diff --git a/Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst b/Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst deleted file mode 100644 index 332d6bb54d80c7..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-05-15-49-53.gh-issue-124960.Bol9hT.rst +++ /dev/null @@ -1 +0,0 @@ -Fix support for the ``barry_as_FLUFL`` future flag in the new REPL. diff --git a/Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst b/Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst deleted file mode 100644 index b5082b90721d42..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-08-12-09-09.gh-issue-124969._VBQLq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``locale.nl_langinfo(locale.ALT_DIGITS)``. Now it returns a tuple of up -to 100 strings (an empty tuple on most locales). Previously it returned the -first item of that tuple or an empty string. diff --git a/Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst b/Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst deleted file mode 100644 index c582a2dfe7243c..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-08-13-28-22.gh-issue-125096.Vz0W5g.rst +++ /dev/null @@ -1,5 +0,0 @@ -If the :envvar:`PYTHON_BASIC_REPL` environment variable is set, the -:mod:`site` module no longer imports the :mod:`!_pyrepl` module. Moreover, -the :mod:`site` module now respects :option:`-E` and :option:`-I` command -line options: ignore :envvar:`PYTHON_BASIC_REPL` in this case. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst deleted file mode 100644 index 9f1fd871e1d0b5..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix an issue where providing a :class:`pathlib.PurePath` object as an -initializer argument to a second :class:`~pathlib.PurePath` object with a -different :attr:`~pathlib.PurePath.parser` resulted in arguments to the -former object's initializer being joined by the latter object's parser. diff --git a/Misc/NEWS.d/next/Library/2024-10-09-07-09-00.gh-issue-125118.J9rQ1S.rst b/Misc/NEWS.d/next/Library/2024-10-09-07-09-00.gh-issue-125118.J9rQ1S.rst deleted file mode 100644 index 5d57cdbbbc2fe9..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-09-07-09-00.gh-issue-125118.J9rQ1S.rst +++ /dev/null @@ -1 +0,0 @@ -Don't copy arbitrary values to :c:expr:`_Bool` in the :mod:`struct` module. diff --git a/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst deleted file mode 100644 index 20f9c0b9c78b12..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix inheritance of nested mutually exclusive groups from parent parser in -:class:`argparse.ArgumentParser`. Previously, all nested mutually exclusive -groups lost their connection to the group containing them and were displayed -as belonging directly to the parser. diff --git a/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst b/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst deleted file mode 100644 index f64d15917da1fc..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst +++ /dev/null @@ -1,2 +0,0 @@ -Keep :mod:`tkinter` TCL paths in venv pointing to base installation on -Windows. diff --git a/Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst b/Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst deleted file mode 100644 index abe37fefedc3be..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-10-19-57-35.gh-issue-125254.RtZxXS.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a bug where ArgumentError includes the incorrect ambiguous option in :mod:`argparse`. diff --git a/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst b/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst deleted file mode 100644 index 49f84d9711819f..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix data race when creating :class:`zoneinfo.ZoneInfo` objects in the free -threading build. diff --git a/Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst b/Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst deleted file mode 100644 index fab524ea0185c2..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-11-04-04-38.gh-issue-125260.PeZ0Mb.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :func:`gzip.compress` *mtime* parameter now defaults to 0 for reproducible output. -Patch by Bernhard M. Wiedemann and Adam Turner. diff --git a/Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst b/Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst deleted file mode 100644 index d0860457c8e813..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst +++ /dev/null @@ -1 +0,0 @@ -Make :class:`~weakref.WeakKeyDictionary` and :class:`~weakref.WeakValueDictionary` safe against concurrent mutations from other threads. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst b/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst deleted file mode 100644 index ef7975ebcb376b..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Workaround for old libffi versions is added. Module ctypes supports -:c:expr:`double complex` only with libffi >= 3.3.0. Patch by Mikhail Efimov. diff --git a/Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst b/Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst deleted file mode 100644 index cdfa8c191e8242..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-13-20-21-35.gh-issue-53203.Rz1c8A.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`time.strptime` for ``%c``, ``%x`` and ``%X`` formats in many -locales that use non-ASCII digits, like Persian, Burmese, Odia and Shan. diff --git a/Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst b/Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst deleted file mode 100644 index c366b0ad4040d3..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-14-02-27-03.gh-issue-100141.NuAcwa.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed the bug where :mod:`pdb` will be stuck in an infinite loop when debugging an empty file. diff --git a/Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst b/Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst deleted file mode 100644 index c890ecec8beaf8..00000000000000 --- a/Misc/NEWS.d/next/Library/2024-10-14-04-44-12.gh-issue-125422.MlVuC6.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed the bug where :mod:`pdb` and :mod:`bdb` can step into the bottom caller frame. diff --git a/Misc/NEWS.d/next/Security/2024-05-01-20-57-09.gh-issue-118486.K44KJG.rst b/Misc/NEWS.d/next/Security/2024-05-01-20-57-09.gh-issue-118486.K44KJG.rst deleted file mode 100644 index 8ac48aac816a60..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-05-01-20-57-09.gh-issue-118486.K44KJG.rst +++ /dev/null @@ -1,4 +0,0 @@ -:func:`os.mkdir` on Windows now accepts *mode* of ``0o700`` to restrict -the new directory to the current user. This fixes :cve:`2024-4030` -affecting :func:`tempfile.mkdtemp` in scenarios where the base temporary -directory is more permissive than the default. diff --git a/Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst b/Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst deleted file mode 100644 index bfec178f6318a7..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixes creation of ACLs in :func:`os.mkdir` on Windows to work correctly on -non-English machines. diff --git a/Misc/NEWS.d/next/Security/2024-06-25-04-42-43.gh-issue-112301.god4IC.rst b/Misc/NEWS.d/next/Security/2024-06-25-04-42-43.gh-issue-112301.god4IC.rst deleted file mode 100644 index 68058a06f0bf49..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-06-25-04-42-43.gh-issue-112301.god4IC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add default compiler options to improve security. Enable --Wimplicit-fallthrough, -fstack-protector-strong, -Wtrampolines. diff --git a/Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst b/Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst deleted file mode 100644 index 81f918bfe2b255..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove backtracking from tarfile header parsing for ``hdrcharset``, PAX, and -GNU sparse headers. diff --git a/Misc/NEWS.d/next/Security/2024-07-08-23-39-04.gh-issue-112301.TD8G01.rst b/Misc/NEWS.d/next/Security/2024-07-08-23-39-04.gh-issue-112301.TD8G01.rst deleted file mode 100644 index d9b48993a2fb1a..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-07-08-23-39-04.gh-issue-112301.TD8G01.rst +++ /dev/null @@ -1,2 +0,0 @@ -Enable runtime protections for glibc to abort execution when unsafe behavior is encountered, -for all platforms except Windows. diff --git a/Misc/NEWS.d/next/Security/2024-07-18-13-17-47.gh-issue-121957.QemKLU.rst b/Misc/NEWS.d/next/Security/2024-07-18-13-17-47.gh-issue-121957.QemKLU.rst deleted file mode 100644 index 49ccc5e14633cd..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-07-18-13-17-47.gh-issue-121957.QemKLU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed missing audit events around interactive use of Python, now also -properly firing for ``python -i``, as well as for ``python -m asyncio``. The -events in question are ``cpython.run_stdin`` and ``cpython.run_startup``. diff --git a/Misc/NEWS.d/next/Security/2024-07-22-13-11-28.gh-issue-122133.0mPeta.rst b/Misc/NEWS.d/next/Security/2024-07-22-13-11-28.gh-issue-122133.0mPeta.rst deleted file mode 100644 index 3544eb3824d0da..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-07-22-13-11-28.gh-issue-122133.0mPeta.rst +++ /dev/null @@ -1,5 +0,0 @@ -Authenticate the socket connection for the ``socket.socketpair()`` fallback -on platforms where ``AF_UNIX`` is not available like Windows. - -Patch by Gregory P. Smith and Seth Larson . Reported by Ellie - diff --git a/Misc/NEWS.d/next/Security/2024-07-24-05-18-25.gh-issue-112301.lfINgZ.rst b/Misc/NEWS.d/next/Security/2024-07-24-05-18-25.gh-issue-112301.lfINgZ.rst deleted file mode 100644 index 81237e735ebdb7..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-07-24-05-18-25.gh-issue-112301.lfINgZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add macOS warning tracking to warning check tooling. -Patch by Nate Ohlson. diff --git a/Misc/NEWS.d/next/Security/2024-08-06-00-06-23.gh-issue-112301.4k4lw6.rst b/Misc/NEWS.d/next/Security/2024-08-06-00-06-23.gh-issue-112301.4k4lw6.rst deleted file mode 100644 index 0bd2f4d7810a78..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-08-06-00-06-23.gh-issue-112301.4k4lw6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ability to ignore warnings per file with warning count in warning checking tooling. -Patch by Nate Ohlson. diff --git a/Misc/NEWS.d/next/Security/2024-08-07-10-42-13.gh-issue-122792.oiTMo9.rst b/Misc/NEWS.d/next/Security/2024-08-07-10-42-13.gh-issue-122792.oiTMo9.rst deleted file mode 100644 index 18e293ba0c03b5..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-08-07-10-42-13.gh-issue-122792.oiTMo9.rst +++ /dev/null @@ -1,3 +0,0 @@ -Changed IPv4-mapped ``ipaddress.IPv6Address`` to consistently use the mapped IPv4 -address value for deciding properties. Properties which have their behavior fixed -are ``is_multicast``, ``is_reserved``, ``is_link_local``, ``is_global``, and ``is_unspecified``. diff --git a/Misc/NEWS.d/next/Security/2024-08-14-19-43-57.gh-issue-112301.IQUcOy.rst b/Misc/NEWS.d/next/Security/2024-08-14-19-43-57.gh-issue-112301.IQUcOy.rst deleted file mode 100644 index 9750cf203eef86..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-08-14-19-43-57.gh-issue-112301.IQUcOy.rst +++ /dev/null @@ -1 +0,0 @@ -Enable compiler options that warn of potential security vulnerabilities. diff --git a/Misc/NEWS.d/next/Security/2024-09-04-12-41-35.gh-issue-123678.N41y9n.rst b/Misc/NEWS.d/next/Security/2024-09-04-12-41-35.gh-issue-123678.N41y9n.rst deleted file mode 100644 index b70f578415fdc2..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-09-04-12-41-35.gh-issue-123678.N41y9n.rst +++ /dev/null @@ -1 +0,0 @@ -Upgrade libexpat to 2.6.3 diff --git a/Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst b/Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst deleted file mode 100644 index f4a49302372647..00000000000000 --- a/Misc/NEWS.d/next/Security/2024-10-09-20-08-13.gh-issue-125140.YgNWRB.rst +++ /dev/null @@ -1 +0,0 @@ -Remove the current directory from ``sys.path`` when using PyREPL. diff --git a/Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst b/Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst deleted file mode 100644 index cc368d4bdffbd2..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-08-03-17-26-55.gh-issue-107562.ZnbscS.rst +++ /dev/null @@ -1,3 +0,0 @@ -Test certificates have been updated to expire far in the future. This allows -testing Y2038 with system time set to after that, so that actual Y2038 -issues can be exposed, and not masked by expired certificate errors. diff --git a/Misc/NEWS.d/next/Tests/2024-05-04-22-56-41.gh-issue-101525.LHK166.rst b/Misc/NEWS.d/next/Tests/2024-05-04-22-56-41.gh-issue-101525.LHK166.rst deleted file mode 100644 index ae8001ad373119..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-05-04-22-56-41.gh-issue-101525.LHK166.rst +++ /dev/null @@ -1,2 +0,0 @@ -Skip ``test_gdb`` if the binary is relocated by BOLT. -Patch by Donghee Na. diff --git a/Misc/NEWS.d/next/Tests/2024-05-18-10-59-27.gh-issue-119050.g4qiH7.rst b/Misc/NEWS.d/next/Tests/2024-05-18-10-59-27.gh-issue-119050.g4qiH7.rst deleted file mode 100644 index cfc70c16b2b279..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-05-18-10-59-27.gh-issue-119050.g4qiH7.rst +++ /dev/null @@ -1,2 +0,0 @@ -regrtest test runner: Add XML support to the refleak checker (-R option). -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2024-05-20-18-06-31.gh-issue-119273.hf-yhX.rst b/Misc/NEWS.d/next/Tests/2024-05-20-18-06-31.gh-issue-119273.hf-yhX.rst deleted file mode 100644 index 905b4e3a1c9043..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-05-20-18-06-31.gh-issue-119273.hf-yhX.rst +++ /dev/null @@ -1,3 +0,0 @@ -Python test runner no longer runs tests using TTY (ex: test_ioctl) in a -process group (using ``setsid()``). Previously, tests using TTY were -skipped. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst b/Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst deleted file mode 100644 index bf28d8bb77b8a2..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``--single-process`` command line option to Python test runner (regrtest). -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2024-06-20-12-51-26.gh-issue-120801.lMVXC9.rst b/Misc/NEWS.d/next/Tests/2024-06-20-12-51-26.gh-issue-120801.lMVXC9.rst deleted file mode 100644 index 8559cb8b99c384..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-06-20-12-51-26.gh-issue-120801.lMVXC9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Cleaned up fixtures for importlib.metadata tests and consolidated behavior -with 'test.support.os_helper'. diff --git a/Misc/NEWS.d/next/Tests/2024-07-01-09-04-32.gh-issue-121188.XbuTVa.rst b/Misc/NEWS.d/next/Tests/2024-07-01-09-04-32.gh-issue-121188.XbuTVa.rst deleted file mode 100644 index c92002d8fe3cd2..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-01-09-04-32.gh-issue-121188.XbuTVa.rst +++ /dev/null @@ -1,3 +0,0 @@ -When creating the JUnit XML file, regrtest now escapes characters which are -invalid in XML, such as the chr(27) control character used in ANSI escape -sequences. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2024-07-01-16-15-06.gh-issue-121200.4Pc-gc.rst b/Misc/NEWS.d/next/Tests/2024-07-01-16-15-06.gh-issue-121200.4Pc-gc.rst deleted file mode 100644 index 01e0d9b9f217d4..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-01-16-15-06.gh-issue-121200.4Pc-gc.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``test_expanduser_pwd2()`` of ``test_posixpath``. Call ``getpwnam()`` -to get ``pw_dir``, since it can be different than ``getpwall()`` ``pw_dir``. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2024-07-03-14-41-00.gh-issue-121160.LEtiTd.rst b/Misc/NEWS.d/next/Tests/2024-07-03-14-41-00.gh-issue-121160.LEtiTd.rst deleted file mode 100644 index 2c8c9ac7201836..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-03-14-41-00.gh-issue-121160.LEtiTd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add a test for :func:`readline.set_history_length`. Note that this test may -fail on readline libraries. diff --git a/Misc/NEWS.d/next/Tests/2024-07-04-15-10-29.gh-issue-121084.qxcd5d.rst b/Misc/NEWS.d/next/Tests/2024-07-04-15-10-29.gh-issue-121084.qxcd5d.rst deleted file mode 100644 index b91ea8acfadbf1..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-04-15-10-29.gh-issue-121084.qxcd5d.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix test_typing random leaks. Clear typing ABC caches when running tests for -refleaks (``-R`` option): call ``_abc_caches_clear()`` on typing abstract -classes and their subclasses. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2024-07-13-11-04-44.gh-issue-99242.aGxnwz.rst b/Misc/NEWS.d/next/Tests/2024-07-13-11-04-44.gh-issue-99242.aGxnwz.rst deleted file mode 100644 index 7d904f26a36ff2..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-13-11-04-44.gh-issue-99242.aGxnwz.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`os.getloadavg` may throw :exc:`OSError` when running regression tests -under certain conditions (e.g. chroot). This error is now caught and -ignored, since reporting load average is optional. diff --git a/Misc/NEWS.d/next/Tests/2024-07-13-11-48-20.gh-issue-59022.fYNbQ8.rst b/Misc/NEWS.d/next/Tests/2024-07-13-11-48-20.gh-issue-59022.fYNbQ8.rst deleted file mode 100644 index e1acebe922cfdf..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-13-11-48-20.gh-issue-59022.fYNbQ8.rst +++ /dev/null @@ -1 +0,0 @@ -Add tests for :func:`pkgutil.extend_path`. Patch by Andreas Stocker. diff --git a/Misc/NEWS.d/next/Tests/2024-07-13-21-55-58.gh-issue-112301.YJS1dl.rst b/Misc/NEWS.d/next/Tests/2024-07-13-21-55-58.gh-issue-112301.YJS1dl.rst deleted file mode 100644 index d5718ed4be7606..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-13-21-55-58.gh-issue-112301.YJS1dl.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add tooling to check for changes in compiler warnings. -Patch by Nate Ohlson. diff --git a/Misc/NEWS.d/next/Tests/2024-07-17-08-25-06.gh-issue-121921.HW8CIS.rst b/Misc/NEWS.d/next/Tests/2024-07-17-08-25-06.gh-issue-121921.HW8CIS.rst deleted file mode 100644 index ef14fa9dfbd466..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-07-17-08-25-06.gh-issue-121921.HW8CIS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update ``Lib/test/crashers/bogus_code_obj.py`` so that it crashes properly -again. diff --git a/Misc/NEWS.d/next/Tests/2024-09-17-22-21-58.gh-issue-124190.3fWhiX.rst b/Misc/NEWS.d/next/Tests/2024-09-17-22-21-58.gh-issue-124190.3fWhiX.rst deleted file mode 100644 index 819b1ca49235fc..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-09-17-22-21-58.gh-issue-124190.3fWhiX.rst +++ /dev/null @@ -1 +0,0 @@ -Add capability to ignore entire files or directories in check warning CI tool diff --git a/Misc/NEWS.d/next/Tests/2024-09-18-18-39-21.gh-issue-124213.AQq_xg.rst b/Misc/NEWS.d/next/Tests/2024-09-18-18-39-21.gh-issue-124213.AQq_xg.rst deleted file mode 100644 index 021fbefb635af1..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-09-18-18-39-21.gh-issue-124213.AQq_xg.rst +++ /dev/null @@ -1,3 +0,0 @@ -Detect whether the test suite is running inside a systemd-nspawn container -with ``--suppress-sync=true`` option, and skip the ``test_os`` -and ``test_mmap`` tests that are failing in this scenario. diff --git a/Misc/NEWS.d/next/Tests/2024-09-25-12-39-34.gh-issue-124378.Ywwgia.rst b/Misc/NEWS.d/next/Tests/2024-09-25-12-39-34.gh-issue-124378.Ywwgia.rst deleted file mode 100644 index 9ddcca0eb6036d..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-09-25-12-39-34.gh-issue-124378.Ywwgia.rst +++ /dev/null @@ -1 +0,0 @@ -Updated ``test_ttk`` to pass with Tcl/Tk 8.6.15. diff --git a/Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst b/Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst deleted file mode 100644 index c7181eb9c1f3a9..00000000000000 --- a/Misc/NEWS.d/next/Tests/2024-10-07-14-13-38.gh-issue-125041.PKLWDf.rst +++ /dev/null @@ -1,3 +0,0 @@ -Re-enable skipped tests for :mod:`zlib` on the s390x architecture: only skip -checks of the compressed bytes, which can be different between zlib's -software implementation and the hardware-accelerated implementation. diff --git a/Misc/NEWS.d/next/Tools-Demos/2024-09-04-10-07-51.gh-issue-123418.1eIFZb.rst b/Misc/NEWS.d/next/Tools-Demos/2024-09-04-10-07-51.gh-issue-123418.1eIFZb.rst deleted file mode 100644 index fb9ac9e4f96725..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2024-09-04-10-07-51.gh-issue-123418.1eIFZb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update GitHub CI workflows to use OpenSSL 3.0.15 and multissltests to use -3.0.15, 3.1.7, and 3.2.3. diff --git a/Misc/NEWS.d/next/Windows/2022-04-20-18-32-30.gh-issue-79846.Vggv3f.rst b/Misc/NEWS.d/next/Windows/2022-04-20-18-32-30.gh-issue-79846.Vggv3f.rst deleted file mode 100644 index 82c26701e0e0bc..00000000000000 --- a/Misc/NEWS.d/next/Windows/2022-04-20-18-32-30.gh-issue-79846.Vggv3f.rst +++ /dev/null @@ -1,2 +0,0 @@ -Makes :code:`ssl.create_default_context()` ignore invalid certificates in -the Windows certificate store diff --git a/Misc/NEWS.d/next/Windows/2024-04-24-05-16-32.gh-issue-118209.Ryyzlz.rst b/Misc/NEWS.d/next/Windows/2024-04-24-05-16-32.gh-issue-118209.Ryyzlz.rst deleted file mode 100644 index da70b2528919e1..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-04-24-05-16-32.gh-issue-118209.Ryyzlz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid crashing in :mod:`mmap` on Windows when the mapped memory is inaccessible -due to file system errors or access violations. diff --git a/Misc/NEWS.d/next/Windows/2024-04-24-22-50-33.gh-issue-117505.gcTb_p.rst b/Misc/NEWS.d/next/Windows/2024-04-24-22-50-33.gh-issue-117505.gcTb_p.rst deleted file mode 100644 index 0931687ecc521c..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-04-24-22-50-33.gh-issue-117505.gcTb_p.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes an issue with the Windows installer not running ensurepip in a fully isolated environment. This could cause unexpected interactions with the user site-packages. diff --git a/Misc/NEWS.d/next/Windows/2024-05-22-19-43-29.gh-issue-119070._enton.rst b/Misc/NEWS.d/next/Windows/2024-05-22-19-43-29.gh-issue-119070._enton.rst deleted file mode 100644 index aab26f57209864..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-05-22-19-43-29.gh-issue-119070._enton.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixes ``py.exe`` handling of shebangs like ``/usr/bin/env python3.12``, -which were previously interpreted as ``python3.exe`` instead of -``python3.12.exe``. diff --git a/Misc/NEWS.d/next/Windows/2024-05-25-18-43-10.gh-issue-111201.SLPJIx.rst b/Misc/NEWS.d/next/Windows/2024-05-25-18-43-10.gh-issue-111201.SLPJIx.rst deleted file mode 100644 index f3918ed633d78c..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-05-25-18-43-10.gh-issue-111201.SLPJIx.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for new pyrepl on Windows diff --git a/Misc/NEWS.d/next/Windows/2024-05-29-11-06-12.gh-issue-119690.8q6e1p.rst b/Misc/NEWS.d/next/Windows/2024-05-29-11-06-12.gh-issue-119690.8q6e1p.rst deleted file mode 100644 index 84dd2161aa1db8..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-05-29-11-06-12.gh-issue-119690.8q6e1p.rst +++ /dev/null @@ -1 +0,0 @@ -Adds Unicode support and fixes audit events for ``_winapi.CreateNamedPipe``. diff --git a/Misc/NEWS.d/next/Windows/2024-05-30-17-39-25.gh-issue-119679.mZC87w.rst b/Misc/NEWS.d/next/Windows/2024-05-30-17-39-25.gh-issue-119679.mZC87w.rst deleted file mode 100644 index db9e798d3ddcb8..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-05-30-17-39-25.gh-issue-119679.mZC87w.rst +++ /dev/null @@ -1 +0,0 @@ -Ensures correct import libraries are included in Windows installs. diff --git a/Misc/NEWS.d/next/Windows/2024-07-19-21-50-54.gh-issue-100256.GDrKba.rst b/Misc/NEWS.d/next/Windows/2024-07-19-21-50-54.gh-issue-100256.GDrKba.rst deleted file mode 100644 index f0156ddd4772ed..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-07-19-21-50-54.gh-issue-100256.GDrKba.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`mimetypes` no longer fails when it encounters an inaccessible registry key. diff --git a/Misc/NEWS.d/next/Windows/2024-08-01-10-55-15.gh-issue-122573.4-UCFY.rst b/Misc/NEWS.d/next/Windows/2024-08-01-10-55-15.gh-issue-122573.4-UCFY.rst deleted file mode 100644 index 5cc69e206debf5..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-08-01-10-55-15.gh-issue-122573.4-UCFY.rst +++ /dev/null @@ -1 +0,0 @@ -The Windows build of CPython now requires 3.10 or newer. diff --git a/Misc/NEWS.d/next/Windows/2024-08-29-16-13-45.gh-issue-123476.m2DFS4.rst b/Misc/NEWS.d/next/Windows/2024-08-29-16-13-45.gh-issue-123476.m2DFS4.rst deleted file mode 100644 index 801214edc315ff..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-08-29-16-13-45.gh-issue-123476.m2DFS4.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for ``socket.TCP_QUICKACK`` on Windows platforms. diff --git a/Misc/NEWS.d/next/Windows/2024-09-04-09-59-18.gh-issue-123418.QaMC12.rst b/Misc/NEWS.d/next/Windows/2024-09-04-09-59-18.gh-issue-123418.QaMC12.rst deleted file mode 100644 index c2b47dc40652dc..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-09-04-09-59-18.gh-issue-123418.QaMC12.rst +++ /dev/null @@ -1 +0,0 @@ -Updated Windows build to use OpenSSL 3.0.15. diff --git a/Misc/NEWS.d/next/Windows/2024-09-10-19-23-00.gh-issue-123915.yZMEDO.rst b/Misc/NEWS.d/next/Windows/2024-09-10-19-23-00.gh-issue-123915.yZMEDO.rst deleted file mode 100644 index 026b09d3601272..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-09-10-19-23-00.gh-issue-123915.yZMEDO.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure that ``Tools\msi\buildrelease.bat`` uses different directories for AMD64 and ARM64 builds. diff --git a/Misc/NEWS.d/next/Windows/2024-09-20-11-18-50.gh-issue-124254.iPin-L.rst b/Misc/NEWS.d/next/Windows/2024-09-20-11-18-50.gh-issue-124254.iPin-L.rst deleted file mode 100644 index b93e356edb501d..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-09-20-11-18-50.gh-issue-124254.iPin-L.rst +++ /dev/null @@ -1 +0,0 @@ -Ensures experimental free-threaded binaries remain installed when updating. diff --git a/Misc/NEWS.d/next/Windows/2024-09-24-19-04-56.gh-issue-124448.srVT3d.rst b/Misc/NEWS.d/next/Windows/2024-09-24-19-04-56.gh-issue-124448.srVT3d.rst deleted file mode 100644 index ca9845a8daea9d..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-09-24-19-04-56.gh-issue-124448.srVT3d.rst +++ /dev/null @@ -1 +0,0 @@ -Updated bundled Tcl/Tk to 8.6.15. diff --git a/Misc/NEWS.d/next/Windows/2024-09-27-13-40-25.gh-issue-124609.WaKk8G.rst b/Misc/NEWS.d/next/Windows/2024-09-27-13-40-25.gh-issue-124609.WaKk8G.rst deleted file mode 100644 index 203868a8fee39c..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-09-27-13-40-25.gh-issue-124609.WaKk8G.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``_Py_ThreadId`` for Windows builds using MinGW. Patch by Tony Roberts. diff --git a/Misc/NEWS.d/next/Windows/2024-09-27-15-07-30.gh-issue-124487.7LrwHC.rst b/Misc/NEWS.d/next/Windows/2024-09-27-15-07-30.gh-issue-124487.7LrwHC.rst deleted file mode 100644 index 93fb68d28c702e..00000000000000 --- a/Misc/NEWS.d/next/Windows/2024-09-27-15-07-30.gh-issue-124487.7LrwHC.rst +++ /dev/null @@ -1 +0,0 @@ -Increases Windows required OS and API level to Windows 10. diff --git a/Misc/NEWS.d/next/macOS/2024-09-04-11-55-29.gh-issue-123418.8P4bmN.rst b/Misc/NEWS.d/next/macOS/2024-09-04-11-55-29.gh-issue-123418.8P4bmN.rst deleted file mode 100644 index d01afce8a12350..00000000000000 --- a/Misc/NEWS.d/next/macOS/2024-09-04-11-55-29.gh-issue-123418.8P4bmN.rst +++ /dev/null @@ -1 +0,0 @@ -Updated macOS installer build to use OpenSSL 3.0.15. diff --git a/Misc/NEWS.d/next/macOS/2024-09-07-12-14-54.gh-issue-123797.yFDeug.rst b/Misc/NEWS.d/next/macOS/2024-09-07-12-14-54.gh-issue-123797.yFDeug.rst deleted file mode 100644 index f126bd0d39bf59..00000000000000 --- a/Misc/NEWS.d/next/macOS/2024-09-07-12-14-54.gh-issue-123797.yFDeug.rst +++ /dev/null @@ -1 +0,0 @@ -Check for runtime availability of ``ptsname_r`` function on macos. diff --git a/Misc/NEWS.d/next/macOS/2024-09-24-10-48-46.gh-issue-124448.bFMrS6.rst b/Misc/NEWS.d/next/macOS/2024-09-24-10-48-46.gh-issue-124448.bFMrS6.rst deleted file mode 100644 index 6d57aa1ee190d6..00000000000000 --- a/Misc/NEWS.d/next/macOS/2024-09-24-10-48-46.gh-issue-124448.bFMrS6.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled Tcl/Tk in macOS installer to 8.6.15. diff --git a/README.rst b/README.rst index 7dd3660b198784..3f694771e090cb 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.14.0 alpha 0 +This is Python version 3.14.0 alpha 1 ===================================== .. image:: https://github.com/python/cpython/actions/workflows/build.yml/badge.svg?branch=main&event=push From 12eaadc0ad33411bb02945d700b6ed7e758bb188 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 15 Oct 2024 12:56:33 -0700 Subject: [PATCH 197/247] gh-58956: Set f_trace on frames with breakpoints after setting a new breakpoint (#124454) --- Lib/bdb.py | 8 +++++ Lib/test/test_pdb.py | 30 +++++++++++++++++++ ...4-09-24-18-16-59.gh-issue-58956.0wFrBR.rst | 1 + 3 files changed, 39 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2024-09-24-18-16-59.gh-issue-58956.0wFrBR.rst diff --git a/Lib/bdb.py b/Lib/bdb.py index 9755d61dd2696c..81bba8a130f97c 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -461,6 +461,14 @@ def set_break(self, filename, lineno, temporary=False, cond=None, return 'Line %s:%d does not exist' % (filename, lineno) self._add_to_breaks(filename, lineno) bp = Breakpoint(filename, lineno, temporary, cond, funcname) + # After we set a new breakpoint, we need to search through all frames + # and set f_trace to trace_dispatch if there could be a breakpoint in + # that frame. + frame = self.enterframe + while frame: + if self.break_anywhere(frame): + frame.f_trace = self.trace_dispatch + frame = frame.f_back return None def _load_breaks(self): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 456effc010954a..8136c591a33001 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3396,6 +3396,36 @@ def test_issue26053(self): self.assertRegex(res, "Restarting .* with arguments:\na b c") self.assertRegex(res, "Restarting .* with arguments:\nd e f") + def test_issue58956(self): + # Set a breakpoint in a function that already exists on the call stack + # should enable the trace function for the frame. + script = """ + import bar + def foo(): + ret = bar.bar() + pass + foo() + """ + commands = """ + b bar.bar + c + b main.py:5 + c + p ret + quit + """ + bar = """ + def bar(): + return 42 + """ + with open('bar.py', 'w') as f: + f.write(textwrap.dedent(bar)) + self.addCleanup(os_helper.unlink, 'bar.py') + stdout, stderr = self.run_pdb_script(script, commands) + lines = stdout.splitlines() + self.assertIn('-> pass', lines) + self.assertIn('(Pdb) 42', lines) + def test_step_into_botframe(self): # gh-125422 # pdb should not be able to step into the botframe (bdb.py) diff --git a/Misc/NEWS.d/next/Library/2024-09-24-18-16-59.gh-issue-58956.0wFrBR.rst b/Misc/NEWS.d/next/Library/2024-09-24-18-16-59.gh-issue-58956.0wFrBR.rst new file mode 100644 index 00000000000000..a882a632fddf1b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-24-18-16-59.gh-issue-58956.0wFrBR.rst @@ -0,0 +1 @@ +Fixed a bug in :mod:`pdb` where sometimes the breakpoint won't trigger if it was set on a function which is already in the call stack. From fee8fe5858c05599efb014bf4538ef8d52baa45c Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Wed, 16 Oct 2024 00:25:20 +0300 Subject: [PATCH 198/247] Issue template: Remove 3.8 and add 3.14 version (#125552) --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 395516f29b037c..7b7810cf6965fd 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -34,12 +34,12 @@ body: label: "CPython versions tested on:" multiple: true options: - - "3.8" - "3.9" - "3.10" - "3.11" - "3.12" - "3.13" + - "3.14" - "CPython main branch" validations: required: true From 299d02090f216d8cc90374013efb3ccb8de16ecc Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 16 Oct 2024 00:44:52 +0300 Subject: [PATCH 199/247] Post 3.14.0a1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index c7a9496a35ed92..f7b33a8038570b 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.14.0a1" +#define PY_VERSION "3.14.0a1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 7453b8f15c77a8f3b07a5049450436079476c465 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Tue, 15 Oct 2024 17:08:00 -0500 Subject: [PATCH 200/247] Update verison options in crash issue template (GH-125555) --- .github/ISSUE_TEMPLATE/crash.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 6d73f7cae5c0ae..58da2dfe0c7354 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -27,12 +27,12 @@ body: label: "CPython versions tested on:" multiple: true options: - - "3.8" - "3.9" - "3.10" - "3.11" - "3.12" - "3.13" + - "3.14" - "CPython main branch" validations: required: true From bee112a94d688c8048ddeddaa7bbd5150aecad11 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Wed, 16 Oct 2024 14:53:21 +0300 Subject: [PATCH 201/247] gh-124872: Replace enter/exit events with "switched" (#125532) Users want to know when the current context switches to a different context object. Right now this happens when and only when a context is entered or exited, so the enter and exit events are synonymous with "switched". However, if the changes proposed for gh-99633 are implemented, the current context will also switch for reasons other than context enter or exit. Since users actually care about context switches and not enter or exit, replace the enter and exit events with a single switched event. The former exit event was emitted just before exiting the context. The new switched event is emitted after the context is exited to match the semantics users expect of an event with a past-tense name. If users need the ability to clean up before the switch takes effect, another event type can be added in the future. It is not added here because YAGNI. I skipped 0 in the enum as a matter of practice. Skipping 0 makes it easier to troubleshoot when code forgets to set zeroed memory, and it aligns with best practices for other tools (e.g., https://protobuf.dev/programming-guides/dos-donts/#unspecified-enum). Co-authored-by: Richard Hansen Co-authored-by: Victor Stinner --- Doc/c-api/contextvars.rst | 14 ++--- Include/cpython/context.h | 17 ++---- Lib/test/test_capi/test_watchers.py | 87 +++++++++++++++------------- Modules/_testcapi/watchers.c | 79 +++++++++++++------------ Python/context.c | 31 ++++++---- Tools/c-analyzer/cpython/ignored.tsv | 4 +- 6 files changed, 118 insertions(+), 114 deletions(-) diff --git a/Doc/c-api/contextvars.rst b/Doc/c-api/contextvars.rst index 8eba54a80dc80d..b7c6550ff34aac 100644 --- a/Doc/c-api/contextvars.rst +++ b/Doc/c-api/contextvars.rst @@ -123,16 +123,10 @@ Context object management functions: Enumeration of possible context object watcher events: - - ``Py_CONTEXT_EVENT_ENTER``: A context has been entered, causing the - :term:`current context` to switch to it. The object passed to the watch - callback is the now-current :class:`contextvars.Context` object. Each - enter event will eventually have a corresponding exit event for the same - context object after any subsequently entered contexts have themselves been - exited. - - ``Py_CONTEXT_EVENT_EXIT``: A context is about to be exited, which will - cause the :term:`current context` to switch back to what it was before the - context was entered. The object passed to the watch callback is the - still-current :class:`contextvars.Context` object. + - ``Py_CONTEXT_SWITCHED``: The :term:`current context` has switched to a + different context. The object passed to the watch callback is the + now-current :class:`contextvars.Context` object, or None if no context is + current. .. versionadded:: 3.14 diff --git a/Include/cpython/context.h b/Include/cpython/context.h index 3c9be7873b9399..3a7a4b459c09ad 100644 --- a/Include/cpython/context.h +++ b/Include/cpython/context.h @@ -29,20 +29,11 @@ PyAPI_FUNC(int) PyContext_Exit(PyObject *); typedef enum { /* - * A context has been entered, causing the "current context" to switch to - * it. The object passed to the watch callback is the now-current - * contextvars.Context object. Each enter event will eventually have a - * corresponding exit event for the same context object after any - * subsequently entered contexts have themselves been exited. + * The current context has switched to a different context. The object + * passed to the watch callback is the now-current contextvars.Context + * object, or None if no context is current. */ - Py_CONTEXT_EVENT_ENTER, - /* - * A context is about to be exited, which will cause the "current context" - * to switch back to what it was before the context was entered. The - * object passed to the watch callback is the still-current - * contextvars.Context object. - */ - Py_CONTEXT_EVENT_EXIT, + Py_CONTEXT_SWITCHED = 1, } PyContextEvent; /* diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py index f21d2627c6094b..4bb764bf9d0963 100644 --- a/Lib/test/test_capi/test_watchers.py +++ b/Lib/test/test_capi/test_watchers.py @@ -577,68 +577,66 @@ class TestContextObjectWatchers(unittest.TestCase): def context_watcher(self, which_watcher): wid = _testcapi.add_context_watcher(which_watcher) try: - yield wid + switches = _testcapi.get_context_switches(which_watcher) + except ValueError: + switches = None + try: + yield switches finally: _testcapi.clear_context_watcher(wid) - def assert_event_counts(self, exp_enter_0, exp_exit_0, - exp_enter_1, exp_exit_1): - self.assertEqual( - exp_enter_0, _testcapi.get_context_watcher_num_enter_events(0)) - self.assertEqual( - exp_exit_0, _testcapi.get_context_watcher_num_exit_events(0)) - self.assertEqual( - exp_enter_1, _testcapi.get_context_watcher_num_enter_events(1)) - self.assertEqual( - exp_exit_1, _testcapi.get_context_watcher_num_exit_events(1)) + def assert_event_counts(self, want_0, want_1): + self.assertEqual(len(_testcapi.get_context_switches(0)), want_0) + self.assertEqual(len(_testcapi.get_context_switches(1)), want_1) def test_context_object_events_dispatched(self): # verify that all counts are zero before any watchers are registered - self.assert_event_counts(0, 0, 0, 0) + self.assert_event_counts(0, 0) # verify that all counts remain zero when a context object is # entered and exited with no watchers registered ctx = contextvars.copy_context() - ctx.run(self.assert_event_counts, 0, 0, 0, 0) - self.assert_event_counts(0, 0, 0, 0) + ctx.run(self.assert_event_counts, 0, 0) + self.assert_event_counts(0, 0) # verify counts are as expected when first watcher is registered with self.context_watcher(0): - self.assert_event_counts(0, 0, 0, 0) - ctx.run(self.assert_event_counts, 1, 0, 0, 0) - self.assert_event_counts(1, 1, 0, 0) + self.assert_event_counts(0, 0) + ctx.run(self.assert_event_counts, 1, 0) + self.assert_event_counts(2, 0) # again with second watcher registered with self.context_watcher(1): - self.assert_event_counts(1, 1, 0, 0) - ctx.run(self.assert_event_counts, 2, 1, 1, 0) - self.assert_event_counts(2, 2, 1, 1) + self.assert_event_counts(2, 0) + ctx.run(self.assert_event_counts, 3, 1) + self.assert_event_counts(4, 2) # verify counts are reset and don't change after both watchers are cleared - ctx.run(self.assert_event_counts, 0, 0, 0, 0) - self.assert_event_counts(0, 0, 0, 0) + ctx.run(self.assert_event_counts, 0, 0) + self.assert_event_counts(0, 0) - def test_enter_error(self): - with self.context_watcher(2): - with catch_unraisable_exception() as cm: - ctx = contextvars.copy_context() - ctx.run(int, 0) - self.assertEqual( - cm.unraisable.err_msg, - "Exception ignored in " - f"Py_CONTEXT_EVENT_EXIT watcher callback for {ctx!r}" - ) - self.assertEqual(str(cm.unraisable.exc_value), "boom!") + def test_callback_error(self): + ctx_outer = contextvars.copy_context() + ctx_inner = contextvars.copy_context() + unraisables = [] - def test_exit_error(self): - ctx = contextvars.copy_context() - def _in_context(stack): - stack.enter_context(self.context_watcher(2)) + def _in_outer(): + with self.context_watcher(2): + with catch_unraisable_exception() as cm: + ctx_inner.run(lambda: unraisables.append(cm.unraisable)) + unraisables.append(cm.unraisable) - with catch_unraisable_exception() as cm: - with ExitStack() as stack: - ctx.run(_in_context, stack) - self.assertEqual(str(cm.unraisable.exc_value), "boom!") + try: + ctx_outer.run(_in_outer) + self.assertEqual([x.err_msg for x in unraisables], + ["Exception ignored in Py_CONTEXT_SWITCHED " + f"watcher callback for {ctx!r}" + for ctx in [ctx_inner, ctx_outer]]) + self.assertEqual([str(x.exc_value) for x in unraisables], + ["boom!", "boom!"]) + finally: + # Break reference cycle + unraisables = None def test_clear_out_of_range_watcher_id(self): with self.assertRaisesRegex(ValueError, r"Invalid context watcher ID -1"): @@ -654,5 +652,12 @@ def test_allocate_too_many_watchers(self): with self.assertRaisesRegex(RuntimeError, r"no more context watcher IDs available"): _testcapi.allocate_too_many_context_watchers() + def test_exit_base_context(self): + ctx = contextvars.Context() + _testcapi.clear_context_stack() + with self.context_watcher(0) as switches: + ctx.run(lambda: None) + self.assertEqual(switches, [ctx, None]) + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index b4233d07134aea..321d3aeffb6ad1 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -626,16 +626,12 @@ allocate_too_many_func_watchers(PyObject *self, PyObject *args) // Test contexct object watchers #define NUM_CONTEXT_WATCHERS 2 static int context_watcher_ids[NUM_CONTEXT_WATCHERS] = {-1, -1}; -static int num_context_object_enter_events[NUM_CONTEXT_WATCHERS] = {0, 0}; -static int num_context_object_exit_events[NUM_CONTEXT_WATCHERS] = {0, 0}; +static PyObject *context_switches[NUM_CONTEXT_WATCHERS]; static int handle_context_watcher_event(int which_watcher, PyContextEvent event, PyObject *ctx) { - if (event == Py_CONTEXT_EVENT_ENTER) { - num_context_object_enter_events[which_watcher]++; - } - else if (event == Py_CONTEXT_EVENT_EXIT) { - num_context_object_exit_events[which_watcher]++; + if (event == Py_CONTEXT_SWITCHED) { + PyList_Append(context_switches[which_watcher], ctx); } else { return -1; @@ -667,31 +663,28 @@ error_context_event_handler(PyContextEvent event, PyObject *ctx) { static PyObject * add_context_watcher(PyObject *self, PyObject *which_watcher) { - int watcher_id; + static const PyContext_WatchCallback callbacks[] = { + &first_context_watcher_callback, + &second_context_watcher_callback, + &error_context_event_handler, + }; assert(PyLong_Check(which_watcher)); long which_l = PyLong_AsLong(which_watcher); - if (which_l == 0) { - watcher_id = PyContext_AddWatcher(first_context_watcher_callback); - context_watcher_ids[0] = watcher_id; - num_context_object_enter_events[0] = 0; - num_context_object_exit_events[0] = 0; - } - else if (which_l == 1) { - watcher_id = PyContext_AddWatcher(second_context_watcher_callback); - context_watcher_ids[1] = watcher_id; - num_context_object_enter_events[1] = 0; - num_context_object_exit_events[1] = 0; - } - else if (which_l == 2) { - watcher_id = PyContext_AddWatcher(error_context_event_handler); - } - else { + if (which_l < 0 || which_l >= (long)Py_ARRAY_LENGTH(callbacks)) { PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l); return NULL; } + int watcher_id = PyContext_AddWatcher(callbacks[which_l]); if (watcher_id < 0) { return NULL; } + if (which_l >= 0 && which_l < NUM_CONTEXT_WATCHERS) { + context_watcher_ids[which_l] = watcher_id; + Py_XSETREF(context_switches[which_l], PyList_New(0)); + if (context_switches[which_l] == NULL) { + return NULL; + } + } return PyLong_FromLong(watcher_id); } @@ -708,8 +701,7 @@ clear_context_watcher(PyObject *self, PyObject *watcher_id) for (int i = 0; i < NUM_CONTEXT_WATCHERS; i++) { if (watcher_id_l == context_watcher_ids[i]) { context_watcher_ids[i] = -1; - num_context_object_enter_events[i] = 0; - num_context_object_exit_events[i] = 0; + Py_CLEAR(context_switches[i]); } } } @@ -717,21 +709,34 @@ clear_context_watcher(PyObject *self, PyObject *watcher_id) } static PyObject * -get_context_watcher_num_enter_events(PyObject *self, PyObject *watcher_id) +clear_context_stack(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { - assert(PyLong_Check(watcher_id)); - long watcher_id_l = PyLong_AsLong(watcher_id); - assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); - return PyLong_FromLong(num_context_object_enter_events[watcher_id_l]); + PyThreadState *tstate = PyThreadState_Get(); + if (tstate->context == NULL) { + Py_RETURN_NONE; + } + if (((PyContext *)tstate->context)->ctx_prev != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "must first exit all non-base contexts"); + return NULL; + } + Py_CLEAR(tstate->context); + Py_RETURN_NONE; } static PyObject * -get_context_watcher_num_exit_events(PyObject *self, PyObject *watcher_id) +get_context_switches(PyObject *Py_UNUSED(self), PyObject *watcher_id) { assert(PyLong_Check(watcher_id)); long watcher_id_l = PyLong_AsLong(watcher_id); - assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); - return PyLong_FromLong(num_context_object_exit_events[watcher_id_l]); + if (watcher_id_l < 0 || watcher_id_l >= NUM_CONTEXT_WATCHERS) { + PyErr_Format(PyExc_ValueError, "invalid watcher %ld", watcher_id_l); + return NULL; + } + if (context_switches[watcher_id_l] == NULL) { + return PyList_New(0); + } + return Py_NewRef(context_switches[watcher_id_l]); } static PyObject * @@ -835,10 +840,8 @@ static PyMethodDef test_methods[] = { // Code object watchers. {"add_context_watcher", add_context_watcher, METH_O, NULL}, {"clear_context_watcher", clear_context_watcher, METH_O, NULL}, - {"get_context_watcher_num_enter_events", - get_context_watcher_num_enter_events, METH_O, NULL}, - {"get_context_watcher_num_exit_events", - get_context_watcher_num_exit_events, METH_O, NULL}, + {"clear_context_stack", clear_context_stack, METH_NOARGS, NULL}, + {"get_context_switches", get_context_switches, METH_O, NULL}, {"allocate_too_many_context_watchers", (PyCFunction) allocate_too_many_context_watchers, METH_NOARGS, NULL}, {NULL}, diff --git a/Python/context.c b/Python/context.c index 8bc487a33c890b..95aa82206270f9 100644 --- a/Python/context.c +++ b/Python/context.c @@ -102,10 +102,8 @@ PyContext_CopyCurrent(void) static const char * context_event_name(PyContextEvent event) { switch (event) { - case Py_CONTEXT_EVENT_ENTER: - return "Py_CONTEXT_EVENT_ENTER"; - case Py_CONTEXT_EVENT_EXIT: - return "Py_CONTEXT_EVENT_EXIT"; + case Py_CONTEXT_SWITCHED: + return "Py_CONTEXT_SWITCHED"; default: return "?"; } @@ -115,6 +113,13 @@ context_event_name(PyContextEvent event) { static void notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyObject *ctx) { + if (ctx == NULL) { + // This will happen after exiting the last context in the stack, which + // can occur if context_get was never called before entering a context + // (e.g., called `contextvars.Context().run()` on a fresh thread, as + // PyContext_Enter doesn't call context_get). + ctx = Py_None; + } assert(Py_REFCNT(ctx) > 0); PyInterpreterState *interp = ts->interp; assert(interp->_initialized); @@ -175,6 +180,16 @@ PyContext_ClearWatcher(int watcher_id) } +static inline void +context_switched(PyThreadState *ts) +{ + ts->context_ver++; + // ts->context is used instead of context_get() because context_get() might + // throw if ts->context is NULL. + notify_context_watchers(ts, Py_CONTEXT_SWITCHED, ts->context); +} + + static int _PyContext_Enter(PyThreadState *ts, PyObject *octx) { @@ -191,9 +206,7 @@ _PyContext_Enter(PyThreadState *ts, PyObject *octx) ctx->ctx_entered = 1; ts->context = Py_NewRef(ctx); - ts->context_ver++; - - notify_context_watchers(ts, Py_CONTEXT_EVENT_ENTER, octx); + context_switched(ts); return 0; } @@ -227,13 +240,11 @@ _PyContext_Exit(PyThreadState *ts, PyObject *octx) return -1; } - notify_context_watchers(ts, Py_CONTEXT_EVENT_EXIT, octx); Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev); - ts->context_ver++; ctx->ctx_prev = NULL; ctx->ctx_entered = 0; - + context_switched(ts); return 0; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index e6c599a2ac4a46..2605825d3d0078 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -455,8 +455,8 @@ Modules/_testcapi/watchers.c - pyfunc_watchers - Modules/_testcapi/watchers.c - func_watcher_ids - Modules/_testcapi/watchers.c - func_watcher_callbacks - Modules/_testcapi/watchers.c - context_watcher_ids - -Modules/_testcapi/watchers.c - num_context_object_enter_events - -Modules/_testcapi/watchers.c - num_context_object_exit_events - +Modules/_testcapi/watchers.c - context_switches - +Modules/_testcapi/watchers.c add_context_watcher callbacks - Modules/_testcapimodule.c - BasicStaticTypes - Modules/_testcapimodule.c - num_basic_static_types_used - Modules/_testcapimodule.c - ContainerNoGC_members - From 51410d8bdcfe0fd215f94a098dc6cd0919c648a1 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 16 Oct 2024 08:51:15 -0400 Subject: [PATCH 202/247] gh-125217: Turn off optimization around_PyEval_EvalFrameDefault to avoid MSVC crash (#125477) --- Python/ceval.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Python/ceval.c b/Python/ceval.c index f4e0add3034707..43776e773e0deb 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -761,6 +761,16 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch) * so consume 3 units of C stack */ #define PY_EVAL_C_STACK_UNITS 2 +#if defined(_MSC_VER) && defined(_Py_USING_PGO) && defined(_Py_JIT) +/* _PyEval_EvalFrameDefault is too large to optimize for speed with + PGO on MSVC when the JIT is enabled. Disable that optimization + around this function only. If this is fixed upstream, we should + gate this on the version of MSVC. + */ +# pragma optimize("t", off) +/* This setting is reversed below following _PyEval_EvalFrameDefault */ +#endif + PyObject* _Py_HOT_FUNCTION _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) { @@ -1136,6 +1146,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } +#if defined(_MSC_VER) && defined(_Py_USING_PGO) && defined(_Py_JIT) +# pragma optimize("", on) +#endif + #if defined(__GNUC__) # pragma GCC diagnostic pop #elif defined(_MSC_VER) /* MS_WINDOWS */ From feda9aa73ab95d17a291db22c416146f8e70edeb Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Wed, 16 Oct 2024 14:13:07 +0100 Subject: [PATCH 203/247] gh-125444: Fix illegal instruction for older Arm architectures (#125574) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Arm v5 it is not possible to get the thread ID via c13 register hence the illegal instruction. The c13 register started to provide thread ID since Arm v6K architecture variant. Other variants of Arm v6 (T2, Z and base) don’t provide the thread ID via c13. For the sake of simplicity we group v5 and v6 together and consider that instructions for Arm v7 only. --- Include/internal/mimalloc/mimalloc/prim.h | 4 ++-- Include/object.h | 2 +- .../2024-10-16-12-12-39.gh-issue-125444.9tG2X6.rst | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-12-12-39.gh-issue-125444.9tG2X6.rst diff --git a/Include/internal/mimalloc/mimalloc/prim.h b/Include/internal/mimalloc/mimalloc/prim.h index 8a60d528458e6c..322ab29e6b41c2 100644 --- a/Include/internal/mimalloc/mimalloc/prim.h +++ b/Include/internal/mimalloc/mimalloc/prim.h @@ -151,9 +151,9 @@ static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept { // If you test on another platform and it works please send a PR :-) // see also https://akkadia.org/drepper/tls.pdf for more info on the TLS register. #elif defined(__GNUC__) && ( \ - (defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__))) \ + (defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \ || (defined(__APPLE__) && (defined(__x86_64__) || defined(__aarch64__))) \ - || (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__))) \ + || (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \ || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ || (defined(__OpenBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ ) diff --git a/Include/object.h b/Include/object.h index 5be4dedadc20eb..7e1b0966fc5e34 100644 --- a/Include/object.h +++ b/Include/object.h @@ -192,7 +192,7 @@ _Py_ThreadId(void) __asm__("movq %%gs:0, %0" : "=r" (tid)); // x86_64 macOSX uses GS #elif defined(__x86_64__) __asm__("movq %%fs:0, %0" : "=r" (tid)); // x86_64 Linux, BSD uses FS -#elif defined(__arm__) +#elif defined(__arm__) && __ARM_ARCH >= 7 __asm__ ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tid)); #elif defined(__aarch64__) && defined(__APPLE__) __asm__ ("mrs %0, tpidrro_el0" : "=r" (tid)); diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-12-12-39.gh-issue-125444.9tG2X6.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-12-12-39.gh-issue-125444.9tG2X6.rst new file mode 100644 index 00000000000000..13c1e745edf8d5 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-12-12-39.gh-issue-125444.9tG2X6.rst @@ -0,0 +1 @@ +Fix illegal instruction for older Arm architectures. Patch by Diego Russo, testing by Ross Burton. From e4d90be84536746a966478acc4c0cf43a201f492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 16 Oct 2024 15:24:41 +0200 Subject: [PATCH 204/247] gh-125584: Require network resource in ``test_urllib2.HandlerTests.test_ftp_error`` (#125586) --- Lib/test/test_urllib2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 19179fdc9508ca..b90ccc2f125b93 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -794,6 +794,7 @@ def connect_ftp(self, user, passwd, host, port, dirs, self.assertEqual(headers.get("Content-type"), mimetype) self.assertEqual(int(headers["Content-length"]), len(data)) + @support.requires_resource("network") def test_ftp_error(self): class ErrorFTPHandler(urllib.request.FTPHandler): def __init__(self, exception): From d83fcf8371f2f33c7797bc8f5423a8bca8c46e5c Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Wed, 16 Oct 2024 17:27:19 +0300 Subject: [PATCH 205/247] CI: Bump Python to 3.13 and mypy to 1.12 in mypy workflow (#125592) * Bump mypy to 1.12 & Python to 3.13 * Remove unnecessary `type: ignore` --- .github/workflows/mypy.yml | 2 +- Tools/clinic/libclinic/converter.py | 4 +--- Tools/requirements-dev.txt | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 1b2d998182e0f7..e5b05302b5ac27 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: "3.13" cache: pip cache-dependency-path: Tools/requirements-dev.txt - run: pip install -r Tools/requirements-dev.txt diff --git a/Tools/clinic/libclinic/converter.py b/Tools/clinic/libclinic/converter.py index 2abf06dc4e89a2..86853bb4fba253 100644 --- a/Tools/clinic/libclinic/converter.py +++ b/Tools/clinic/libclinic/converter.py @@ -545,9 +545,7 @@ def closure(f: CConverterClassT) -> CConverterClassT: if not kwargs: added_f = f else: - # type ignore due to a mypy regression :( - # https://github.com/python/mypy/issues/17646 - added_f = functools.partial(f, **kwargs) # type: ignore[misc] + added_f = functools.partial(f, **kwargs) if format_unit: legacy_converters[format_unit] = added_f return f diff --git a/Tools/requirements-dev.txt b/Tools/requirements-dev.txt index 408a9ea6607f9e..57f0b982b00f5d 100644 --- a/Tools/requirements-dev.txt +++ b/Tools/requirements-dev.txt @@ -1,6 +1,6 @@ # Requirements file for external linters and checks we run on # Tools/clinic, Tools/cases_generator/, and Tools/peg_generator/ in CI -mypy==1.11.2 +mypy==1.12 # needed for peg_generator: types-psutil==6.0.0.20240901 From 760872efecb95017db8e38a8eda614bf23d2a22c Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Wed, 16 Oct 2024 11:39:17 -0400 Subject: [PATCH 206/247] gh-125451: Fix deadlock in ProcessPoolExecutor shutdown (#125492) There was a deadlock when `ProcessPoolExecutor` shuts down at the same time that a queueing thread handles an error processing a task. Don't use `_shutdown_lock` to protect the `_ThreadWakeup` pipes -- use an internal lock instead. This fixes the ordering deadlock where the `ExecutorManagerThread` holds the `_shutdown_lock` and joins the queueing thread, while the queueing thread is attempting to acquire the `_shutdown_lock` while closing the `_ThreadWakeup`. --- Lib/concurrent/futures/process.py | 50 ++++++++----------- .../test_concurrent_futures/test_shutdown.py | 3 -- ...-10-14-17-29-34.gh-issue-125451.fmP3T9.rst | 2 + 3 files changed, 23 insertions(+), 32 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-14-17-29-34.gh-issue-125451.fmP3T9.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 7092b4757b5429..42eee72bc1457f 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -68,27 +68,31 @@ class _ThreadWakeup: def __init__(self): self._closed = False + self._lock = threading.Lock() self._reader, self._writer = mp.Pipe(duplex=False) def close(self): - # Please note that we do not take the shutdown lock when + # Please note that we do not take the self._lock when # calling clear() (to avoid deadlocking) so this method can # only be called safely from the same thread as all calls to - # clear() even if you hold the shutdown lock. Otherwise we + # clear() even if you hold the lock. Otherwise we # might try to read from the closed pipe. - if not self._closed: - self._closed = True - self._writer.close() - self._reader.close() + with self._lock: + if not self._closed: + self._closed = True + self._writer.close() + self._reader.close() def wakeup(self): - if not self._closed: - self._writer.send_bytes(b"") + with self._lock: + if not self._closed: + self._writer.send_bytes(b"") def clear(self): - if not self._closed: - while self._reader.poll(): - self._reader.recv_bytes() + if self._closed: + raise RuntimeError('operation on closed _ThreadWakeup') + while self._reader.poll(): + self._reader.recv_bytes() def _python_exit(): @@ -167,10 +171,8 @@ def __init__(self, work_id, fn, args, kwargs): class _SafeQueue(Queue): """Safe Queue set exception to the future object linked to a job""" - def __init__(self, max_size=0, *, ctx, pending_work_items, shutdown_lock, - thread_wakeup): + def __init__(self, max_size=0, *, ctx, pending_work_items, thread_wakeup): self.pending_work_items = pending_work_items - self.shutdown_lock = shutdown_lock self.thread_wakeup = thread_wakeup super().__init__(max_size, ctx=ctx) @@ -179,8 +181,7 @@ def _on_queue_feeder_error(self, e, obj): tb = format_exception(type(e), e, e.__traceback__) e.__cause__ = _RemoteTraceback('\n"""\n{}"""'.format(''.join(tb))) work_item = self.pending_work_items.pop(obj.work_id, None) - with self.shutdown_lock: - self.thread_wakeup.wakeup() + self.thread_wakeup.wakeup() # work_item can be None if another process terminated. In this # case, the executor_manager_thread fails all work_items # with BrokenProcessPool @@ -296,12 +297,10 @@ def __init__(self, executor): # if there is no pending work item. def weakref_cb(_, thread_wakeup=self.thread_wakeup, - shutdown_lock=self.shutdown_lock, mp_util_debug=mp.util.debug): mp_util_debug('Executor collected: triggering callback for' ' QueueManager wakeup') - with shutdown_lock: - thread_wakeup.wakeup() + thread_wakeup.wakeup() self.executor_reference = weakref.ref(executor, weakref_cb) @@ -429,11 +428,6 @@ def wait_result_broken_or_wakeup(self): elif wakeup_reader in ready: is_broken = False - # No need to hold the _shutdown_lock here because: - # 1. we're the only thread to use the wakeup reader - # 2. we're also the only thread to call thread_wakeup.close() - # 3. we want to avoid a possible deadlock when both reader and writer - # would block (gh-105829) self.thread_wakeup.clear() return result_item, is_broken, cause @@ -721,10 +715,9 @@ def __init__(self, max_workers=None, mp_context=None, # as it could result in a deadlock if a worker process dies with the # _result_queue write lock still acquired. # - # _shutdown_lock must be locked to access _ThreadWakeup.close() and - # .wakeup(). Care must also be taken to not call clear or close from - # more than one thread since _ThreadWakeup.clear() is not protected by - # the _shutdown_lock + # Care must be taken to only call clear and close from the + # executor_manager_thread, since _ThreadWakeup.clear() is not protected + # by a lock. self._executor_manager_thread_wakeup = _ThreadWakeup() # Create communication channels for the executor @@ -735,7 +728,6 @@ def __init__(self, max_workers=None, mp_context=None, self._call_queue = _SafeQueue( max_size=queue_size, ctx=self._mp_context, pending_work_items=self._pending_work_items, - shutdown_lock=self._shutdown_lock, thread_wakeup=self._executor_manager_thread_wakeup) # Killed worker processes can produce spurious "broken pipe" # tracebacks in the queue's own worker thread. But we detect killed diff --git a/Lib/test/test_concurrent_futures/test_shutdown.py b/Lib/test/test_concurrent_futures/test_shutdown.py index ba3618614a9bf9..7a4065afd46fc8 100644 --- a/Lib/test/test_concurrent_futures/test_shutdown.py +++ b/Lib/test/test_concurrent_futures/test_shutdown.py @@ -253,9 +253,6 @@ def test_cancel_futures_wait_false(self): class ProcessPoolShutdownTest(ExecutorShutdownTest): - # gh-125451: 'lock' cannot be serialized, the test is broken - # and hangs randomly - @unittest.skipIf(True, "broken test") def test_processes_terminate(self): def acquire_lock(lock): lock.acquire() diff --git a/Misc/NEWS.d/next/Library/2024-10-14-17-29-34.gh-issue-125451.fmP3T9.rst b/Misc/NEWS.d/next/Library/2024-10-14-17-29-34.gh-issue-125451.fmP3T9.rst new file mode 100644 index 00000000000000..589988d4d6273f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-14-17-29-34.gh-issue-125451.fmP3T9.rst @@ -0,0 +1,2 @@ +Fix deadlock when :class:`concurrent.futures.ProcessPoolExecutor` shuts down +concurrently with an error when feeding a job to a worker process. From aab3210271136ad8e8fecd927b806602c463e1f2 Mon Sep 17 00:00:00 2001 From: Cornelius Roemer Date: Wed, 16 Oct 2024 22:53:30 +0200 Subject: [PATCH 207/247] gh-125615: Fix grammar nit in tutorial's interactive interpreter appendix (GH-125617) Replace "without ... nor" with "with neither ... nor" --- Doc/tutorial/appendix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/appendix.rst b/Doc/tutorial/appendix.rst index da664f2f360ff1..6a1611afadb57c 100644 --- a/Doc/tutorial/appendix.rst +++ b/Doc/tutorial/appendix.rst @@ -20,7 +20,7 @@ This one supports color, multiline editing, history browsing, and paste mode. To disable color, see :ref:`using-on-controlling-color` for details. Function keys provide some additional functionality. :kbd:`F1` enters the interactive help browser :mod:`pydoc`. -:kbd:`F2` allows for browsing command-line history without output nor the +:kbd:`F2` allows for browsing command-line history with neither output nor the :term:`>>>` and :term:`...` prompts. :kbd:`F3` enters "paste mode", which makes pasting larger blocks of code easier. Press :kbd:`F3` to return to the regular prompt. From aecbc2e6f40f8066f478c2d0f3be5b550e36cfd3 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Wed, 16 Oct 2024 17:01:42 -0500 Subject: [PATCH 208/247] gh-115382: Fix cross compiles when host and target use same SOABI Co-authored-by: Erlend E. Aasland --- Lib/sysconfig/__init__.py | 15 ++++++++++++++- Lib/test/libregrtest/main.py | 1 + Lib/test/pythoninfo.py | 1 + ...2024-03-03-20-28-23.gh-issue-115382.97hJFE.rst | 1 + configure | 2 +- configure.ac | 2 +- 6 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2024-03-03-20-28-23.gh-issue-115382.97hJFE.rst diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py index 80aef3447117e5..43f9276799b848 100644 --- a/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py @@ -340,7 +340,20 @@ def _init_posix(vars): """Initialize the module as appropriate for POSIX systems.""" # _sysconfigdata is generated at build time, see _generate_posix_vars() name = _get_sysconfigdata_name() - _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) + + # For cross builds, the path to the target's sysconfigdata must be specified + # so it can be imported. It cannot be in PYTHONPATH, as foreign modules in + # sys.path can cause crashes when loaded by the host interpreter. + # Rely on truthiness as a valueless env variable is still an empty string. + # See OS X note in _generate_posix_vars re _sysconfigdata. + if (path := os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')): + from importlib.machinery import FileFinder, SourceFileLoader, SOURCE_SUFFIXES + from importlib.util import module_from_spec + spec = FileFinder(path, (SourceFileLoader, SOURCE_SUFFIXES)).find_spec(name) + _temp = module_from_spec(spec) + spec.loader.exec_module(_temp) + else: + _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) build_time_vars = _temp.build_time_vars vars.update(build_time_vars) diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index f693a788048694..2ef4349552bf5f 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -594,6 +594,7 @@ def _add_cross_compile_opts(self, regrtest_opts): '_PYTHON_PROJECT_BASE', '_PYTHON_HOST_PLATFORM', '_PYTHON_SYSCONFIGDATA_NAME', + "_PYTHON_SYSCONFIGDATA_PATH", 'PYTHONPATH' } old_environ = os.environ diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 05a28bda2d38ba..0b2e4b1c1988c4 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -334,6 +334,7 @@ def format_groups(groups): "_PYTHON_HOST_PLATFORM", "_PYTHON_PROJECT_BASE", "_PYTHON_SYSCONFIGDATA_NAME", + "_PYTHON_SYSCONFIGDATA_PATH", "__PYVENV_LAUNCHER__", # Sanitizer options diff --git a/Misc/NEWS.d/next/Build/2024-03-03-20-28-23.gh-issue-115382.97hJFE.rst b/Misc/NEWS.d/next/Build/2024-03-03-20-28-23.gh-issue-115382.97hJFE.rst new file mode 100644 index 00000000000000..f8d19651fc5854 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-03-03-20-28-23.gh-issue-115382.97hJFE.rst @@ -0,0 +1 @@ +Fix cross compile failures when the host and target SOABIs match. diff --git a/configure b/configure index 17c70d25f9e70c..b11f41d5379958 100755 --- a/configure +++ b/configure @@ -3708,7 +3708,7 @@ fi fi ac_cv_prog_PYTHON_FOR_REGEN=$with_build_python PYTHON_FOR_FREEZE="$with_build_python" - PYTHON_FOR_BUILD='_PYTHON_PROJECT_BASE=$(abs_builddir) _PYTHON_HOST_PLATFORM=$(_PYTHON_HOST_PLATFORM) PYTHONPATH=$(shell test -f pybuilddir.txt && echo $(abs_builddir)/`cat pybuilddir.txt`:)$(srcdir)/Lib _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) '$with_build_python + PYTHON_FOR_BUILD='_PYTHON_PROJECT_BASE=$(abs_builddir) _PYTHON_HOST_PLATFORM=$(_PYTHON_HOST_PLATFORM) PYTHONPATH=$(srcdir)/Lib _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) _PYTHON_SYSCONFIGDATA_PATH=$(shell test -f pybuilddir.txt && echo $(abs_builddir)/`cat pybuilddir.txt`) '$with_build_python { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_build_python" >&5 printf "%s\n" "$with_build_python" >&6; } diff --git a/configure.ac b/configure.ac index 56daa8b0f79bc0..d5bc739c34c90f 100644 --- a/configure.ac +++ b/configure.ac @@ -164,7 +164,7 @@ AC_ARG_WITH([build-python], dnl Build Python interpreter is used for regeneration and freezing. ac_cv_prog_PYTHON_FOR_REGEN=$with_build_python PYTHON_FOR_FREEZE="$with_build_python" - PYTHON_FOR_BUILD='_PYTHON_PROJECT_BASE=$(abs_builddir) _PYTHON_HOST_PLATFORM=$(_PYTHON_HOST_PLATFORM) PYTHONPATH=$(shell test -f pybuilddir.txt && echo $(abs_builddir)/`cat pybuilddir.txt`:)$(srcdir)/Lib _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) '$with_build_python + PYTHON_FOR_BUILD='_PYTHON_PROJECT_BASE=$(abs_builddir) _PYTHON_HOST_PLATFORM=$(_PYTHON_HOST_PLATFORM) PYTHONPATH=$(srcdir)/Lib _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) _PYTHON_SYSCONFIGDATA_PATH=$(shell test -f pybuilddir.txt && echo $(abs_builddir)/`cat pybuilddir.txt`) '$with_build_python AC_MSG_RESULT([$with_build_python]) ], [ AS_VAR_IF([cross_compiling], [yes], From 8e7b2a1161744c7d3d90966a65ed6ae1019a65cb Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 16 Oct 2024 23:05:20 +0100 Subject: [PATCH 209/247] gh-125550: Enable py.exe to detect Store installs of 3.14 (GH-125551) --- .../2024-10-15-21-28-43.gh-issue-125550.hmGWCP.rst | 2 ++ PC/launcher2.c | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2024-10-15-21-28-43.gh-issue-125550.hmGWCP.rst diff --git a/Misc/NEWS.d/next/Windows/2024-10-15-21-28-43.gh-issue-125550.hmGWCP.rst b/Misc/NEWS.d/next/Windows/2024-10-15-21-28-43.gh-issue-125550.hmGWCP.rst new file mode 100644 index 00000000000000..c3ae00c74b3d91 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2024-10-15-21-28-43.gh-issue-125550.hmGWCP.rst @@ -0,0 +1,2 @@ +Enable the :ref:`launcher` to detect Python 3.14 installs from the Windows +Store. diff --git a/PC/launcher2.c b/PC/launcher2.c index b372044e353202..befcbe30600f2c 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -1962,6 +1962,7 @@ struct AppxSearchInfo { struct AppxSearchInfo APPX_SEARCH[] = { // Releases made through the Store + { L"PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0", L"3.14", 10 }, { L"PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0", L"3.13", 10 }, { L"PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0", L"3.12", 10 }, { L"PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0", L"3.11", 10 }, @@ -1970,8 +1971,9 @@ struct AppxSearchInfo APPX_SEARCH[] = { { L"PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0", L"3.8", 10 }, // Side-loadable releases. Note that the publisher ID changes whenever we - // renew our code-signing certificate, so the newer ID has a higher - // priority (lower sortKey) + // change our code signing certificate subject, so the newer IDs have higher + // priorities (lower sortKey) + { L"PythonSoftwareFoundation.Python.3.14_3847v3x7pw1km", L"3.14", 11 }, { L"PythonSoftwareFoundation.Python.3.13_3847v3x7pw1km", L"3.13", 11 }, { L"PythonSoftwareFoundation.Python.3.12_3847v3x7pw1km", L"3.12", 11 }, { L"PythonSoftwareFoundation.Python.3.11_3847v3x7pw1km", L"3.11", 11 }, @@ -2054,7 +2056,8 @@ struct StoreSearchInfo { struct StoreSearchInfo STORE_SEARCH[] = { - { L"3", /* 3.12 */ L"9NCVDN91XZQP" }, + { L"3", /* 3.13 */ L"9PNRBTZXMB4Z" }, + { L"3.14", L"9NTRHQCBBPR8" }, { L"3.13", L"9PNRBTZXMB4Z" }, { L"3.12", L"9NCVDN91XZQP" }, { L"3.11", L"9NRWMJP3717K" }, From a38fef4439139743e3334c1d69f24cafdf4d71da Mon Sep 17 00:00:00 2001 From: Furkan Onder Date: Thu, 17 Oct 2024 01:42:29 +0300 Subject: [PATCH 210/247] gh-125620: Remove unnecessary import of subprocess in spawnv_passfds (#125624) Remove unnecessary import of subprocess in multiprocessing.util.spawnv_passfds. --- Lib/multiprocessing/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py index d48ef8a86b34e1..b7192042b9cf47 100644 --- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -438,7 +438,6 @@ def _flush_std_streams(): def spawnv_passfds(path, args, passfds): import _posixsubprocess - import subprocess passfds = tuple(sorted(map(int, passfds))) errpipe_read, errpipe_write = os.pipe() try: From a5a7f5e16d8c3938d266703ea8fba8ffee3e3ae5 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 16 Oct 2024 16:50:46 -0600 Subject: [PATCH 211/247] gh-124694: Add concurrent.futures.InterpreterPoolExecutor (gh-124548) This is an implementation of InterpreterPoolExecutor that builds on ThreadPoolExecutor. (Note that this is not tied to PEP 734, which is strictly about adding a new stdlib module.) Possible future improvements: * support passing a script for the initializer or to submit() * support passing (most) arbitrary functions without pickling * support passing closures * optionally exec functions against __main__ instead of the their original module --- Doc/library/asyncio-dev.rst | 6 +- Doc/library/asyncio-eventloop.rst | 9 +- Doc/library/asyncio-llapi-index.rst | 2 +- Doc/library/concurrent.futures.rst | 135 ++++++- Doc/whatsnew/3.14.rst | 8 + Lib/concurrent/futures/__init__.py | 12 +- Lib/concurrent/futures/interpreter.py | 241 ++++++++++++ Lib/concurrent/futures/thread.py | 90 +++-- Lib/test/test_concurrent_futures/executor.py | 4 +- .../test_interpreter_pool.py | 346 ++++++++++++++++++ Lib/test/test_concurrent_futures/util.py | 5 + ...-09-27-15-42-55.gh-issue-124694.uUy32y.rst | 6 + 12 files changed, 826 insertions(+), 38 deletions(-) create mode 100644 Lib/concurrent/futures/interpreter.py create mode 100644 Lib/test/test_concurrent_futures/test_interpreter_pool.py create mode 100644 Misc/NEWS.d/next/Library/2024-09-27-15-42-55.gh-issue-124694.uUy32y.rst diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index a9c3a0183bb72d..44b507a9811116 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -103,7 +103,8 @@ To handle signals the event loop must be run in the main thread. The :meth:`loop.run_in_executor` method can be used with a -:class:`concurrent.futures.ThreadPoolExecutor` to execute +:class:`concurrent.futures.ThreadPoolExecutor` or +:class:`~concurrent.futures.InterpreterPoolExecutor` to execute blocking code in a different OS thread without blocking the OS thread that the event loop runs in. @@ -128,7 +129,8 @@ if a function performs a CPU-intensive calculation for 1 second, all concurrent asyncio Tasks and IO operations would be delayed by 1 second. -An executor can be used to run a task in a different thread or even in +An executor can be used to run a task in a different thread, +including in a different interpreter, or even in a different process to avoid blocking the OS thread with the event loop. See the :meth:`loop.run_in_executor` method for more details. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 943683f6b8a7f6..14fd153f640f05 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1305,6 +1305,12 @@ Executing code in thread or process pools pool, cpu_bound) print('custom process pool', result) + # 4. Run in a custom interpreter pool: + with concurrent.futures.InterpreterPoolExecutor() as pool: + result = await loop.run_in_executor( + pool, cpu_bound) + print('custom interpreter pool', result) + if __name__ == '__main__': asyncio.run(main()) @@ -1329,7 +1335,8 @@ Executing code in thread or process pools Set *executor* as the default executor used by :meth:`run_in_executor`. *executor* must be an instance of - :class:`~concurrent.futures.ThreadPoolExecutor`. + :class:`~concurrent.futures.ThreadPoolExecutor`, which includes + :class:`~concurrent.futures.InterpreterPoolExecutor`. .. versionchanged:: 3.11 *executor* must be an instance of diff --git a/Doc/library/asyncio-llapi-index.rst b/Doc/library/asyncio-llapi-index.rst index 3e21054aa4fe9e..f5af888f31f186 100644 --- a/Doc/library/asyncio-llapi-index.rst +++ b/Doc/library/asyncio-llapi-index.rst @@ -96,7 +96,7 @@ See also the main documentation section about the - Invoke a callback *at* the given time. -.. rubric:: Thread/Process Pool +.. rubric:: Thread/Interpreter/Process Pool .. list-table:: :widths: 50 50 :class: full-width-table diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index ce72127127c7a6..45a73705f10e92 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -15,9 +15,10 @@ The :mod:`concurrent.futures` module provides a high-level interface for asynchronously executing callables. The asynchronous execution can be performed with threads, using -:class:`ThreadPoolExecutor`, or separate processes, using -:class:`ProcessPoolExecutor`. Both implement the same interface, which is -defined by the abstract :class:`Executor` class. +:class:`ThreadPoolExecutor` or :class:`InterpreterPoolExecutor`, +or separate processes, using :class:`ProcessPoolExecutor`. +Each implements the same interface, which is defined +by the abstract :class:`Executor` class. .. include:: ../includes/wasm-notavail.rst @@ -63,7 +64,8 @@ Executor Objects setting *chunksize* to a positive integer. For very long iterables, using a large value for *chunksize* can significantly improve performance compared to the default size of 1. With - :class:`ThreadPoolExecutor`, *chunksize* has no effect. + :class:`ThreadPoolExecutor` and :class:`InterpreterPoolExecutor`, + *chunksize* has no effect. .. versionchanged:: 3.5 Added the *chunksize* argument. @@ -227,6 +229,111 @@ ThreadPoolExecutor Example print('%r page is %d bytes' % (url, len(data))) +InterpreterPoolExecutor +----------------------- + +The :class:`InterpreterPoolExecutor` class uses a pool of interpreters +to execute calls asynchronously. It is a :class:`ThreadPoolExecutor` +subclass, which means each worker is running in its own thread. +The difference here is that each worker has its own interpreter, +and runs each task using that interpreter. + +The biggest benefit to using interpreters instead of only threads +is true multi-core parallelism. Each interpreter has its own +:term:`Global Interpreter Lock `, so code +running in one interpreter can run on one CPU core, while code in +another interpreter runs unblocked on a different core. + +The tradeoff is that writing concurrent code for use with multiple +interpreters can take extra effort. However, this is because it +forces you to be deliberate about how and when interpreters interact, +and to be explicit about what data is shared between interpreters. +This results in several benefits that help balance the extra effort, +including true multi-core parallelism, For example, code written +this way can make it easier to reason about concurrency. Another +major benefit is that you don't have to deal with several of the +big pain points of using threads, like nrace conditions. + +Each worker's interpreter is isolated from all the other interpreters. +"Isolated" means each interpreter has its own runtime state and +operates completely independently. For example, if you redirect +:data:`sys.stdout` in one interpreter, it will not be automatically +redirected any other interpreter. If you import a module in one +interpreter, it is not automatically imported in any other. You +would need to import the module separately in interpreter where +you need it. In fact, each module imported in an interpreter is +a completely separate object from the same module in a different +interpreter, including :mod:`sys`, :mod:`builtins`, +and even ``__main__``. + +Isolation means a mutable object, or other data, cannot be used +by more than one interpreter at the same time. That effectively means +interpreters cannot actually share such objects or data. Instead, +each interpreter must have its own copy, and you will have to +synchronize any changes between the copies manually. Immutable +objects and data, like the builtin singletons, strings, and tuples +of immutable objects, don't have these limitations. + +Communicating and synchronizing between interpreters is most effectively +done using dedicated tools, like those proposed in :pep:`734`. One less +efficient alternative is to serialize with :mod:`pickle` and then send +the bytes over a shared :mod:`socket ` or +:func:`pipe `. + +.. class:: InterpreterPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=(), shared=None) + + A :class:`ThreadPoolExecutor` subclass that executes calls asynchronously + using a pool of at most *max_workers* threads. Each thread runs + tasks in its own interpreter. The worker interpreters are isolated + from each other, which means each has its own runtime state and that + they can't share any mutable objects or other data. Each interpreter + has its own :term:`Global Interpreter Lock `, + which means code run with this executor has true multi-core parallelism. + + The optional *initializer* and *initargs* arguments have the same + meaning as for :class:`!ThreadPoolExecutor`: the initializer is run + when each worker is created, though in this case it is run.in + the worker's interpreter. The executor serializes the *initializer* + and *initargs* using :mod:`pickle` when sending them to the worker's + interpreter. + + .. note:: + Functions defined in the ``__main__`` module cannot be pickled + and thus cannot be used. + + .. note:: + The executor may replace uncaught exceptions from *initializer* + with :class:`~concurrent.futures.interpreter.ExecutionFailed`. + + The optional *shared* argument is a :class:`dict` of objects that all + interpreters in the pool share. The *shared* items are added to each + interpreter's ``__main__`` module. Not all objects are shareable. + Shareable objects include the builtin singletons, :class:`str` + and :class:`bytes`, and :class:`memoryview`. See :pep:`734` + for more info. + + Other caveats from parent :class:`ThreadPoolExecutor` apply here. + +:meth:`~Executor.submit` and :meth:`~Executor.map` work like normal, +except the worker serializes the callable and arguments using +:mod:`pickle` when sending them to its interpreter. The worker +likewise serializes the return value when sending it back. + +.. note:: + Functions defined in the ``__main__`` module cannot be pickled + and thus cannot be used. + +When a worker's current task raises an uncaught exception, the worker +always tries to preserve the exception as-is. If that is successful +then it also sets the ``__cause__`` to a corresponding +:class:`~concurrent.futures.interpreter.ExecutionFailed` +instance, which contains a summary of the original exception. +In the uncommon case that the worker is not able to preserve the +original as-is then it directly preserves the corresponding +:class:`~concurrent.futures.interpreter.ExecutionFailed` +instance instead. + + ProcessPoolExecutor ------------------- @@ -574,6 +681,26 @@ Exception classes .. versionadded:: 3.7 +.. currentmodule:: concurrent.futures.interpreter + +.. exception:: BrokenInterpreterPool + + Derived from :exc:`~concurrent.futures.thread.BrokenThreadPool`, + this exception class is raised when one of the workers + of a :class:`~concurrent.futures.InterpreterPoolExecutor` + has failed initializing. + + .. versionadded:: next + +.. exception:: ExecutionFailed + + Raised from :class:`~concurrent.futures.InterpreterPoolExecutor` when + the given initializer fails or from + :meth:`~concurrent.futures.Executor.submit` when there's an uncaught + exception from the submitted task. + + .. versionadded:: next + .. currentmodule:: concurrent.futures.process .. exception:: BrokenProcessPool diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index b106578fe9e8b0..9543af3c7ca225 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -225,6 +225,14 @@ ast * The ``repr()`` output for AST nodes now includes more information. (Contributed by Tomas R in :gh:`116022`.) +concurrent.futures +------------------ + +* Add :class:`~concurrent.futures.InterpreterPoolExecutor`, + which exposes "subinterpreters (multiple Python interpreters in the + same process) to Python code. This is separate from the proposed API + in :pep:`734`. + (Contributed by Eric Snow in :gh:`124548`.) ctypes ------ diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index 72de617a5b6f61..7ada7431c1ab8c 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -29,6 +29,7 @@ 'Executor', 'wait', 'as_completed', + 'InterpreterPoolExecutor', 'ProcessPoolExecutor', 'ThreadPoolExecutor', ) @@ -39,7 +40,7 @@ def __dir__(): def __getattr__(name): - global ProcessPoolExecutor, ThreadPoolExecutor + global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor if name == 'ProcessPoolExecutor': from .process import ProcessPoolExecutor as pe @@ -51,4 +52,13 @@ def __getattr__(name): ThreadPoolExecutor = te return te + if name == 'InterpreterPoolExecutor': + try: + from .interpreter import InterpreterPoolExecutor as ie + except ModuleNotFoundError: + ie = InterpreterPoolExecutor = None + else: + InterpreterPoolExecutor = ie + return ie + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/concurrent/futures/interpreter.py b/Lib/concurrent/futures/interpreter.py new file mode 100644 index 00000000000000..fd7941adb766bb --- /dev/null +++ b/Lib/concurrent/futures/interpreter.py @@ -0,0 +1,241 @@ +"""Implements InterpreterPoolExecutor.""" + +import contextlib +import pickle +import textwrap +from . import thread as _thread +import _interpreters +import _interpqueues + + +class ExecutionFailed(_interpreters.InterpreterError): + """An unhandled exception happened during execution.""" + + def __init__(self, excinfo): + msg = excinfo.formatted + if not msg: + if excinfo.type and excinfo.msg: + msg = f'{excinfo.type.__name__}: {excinfo.msg}' + else: + msg = excinfo.type.__name__ or excinfo.msg + super().__init__(msg) + self.excinfo = excinfo + + def __str__(self): + try: + formatted = self.excinfo.errdisplay + except Exception: + return super().__str__() + else: + return textwrap.dedent(f""" +{super().__str__()} + +Uncaught in the interpreter: + +{formatted} + """.strip()) + + +UNBOUND = 2 # error; this should not happen. + + +class WorkerContext(_thread.WorkerContext): + + @classmethod + def prepare(cls, initializer, initargs, shared): + def resolve_task(fn, args, kwargs): + if isinstance(fn, str): + # XXX Circle back to this later. + raise TypeError('scripts not supported') + if args or kwargs: + raise ValueError(f'a script does not take args or kwargs, got {args!r} and {kwargs!r}') + data = textwrap.dedent(fn) + kind = 'script' + # Make sure the script compiles. + # Ideally we wouldn't throw away the resulting code + # object. However, there isn't much to be done until + # code objects are shareable and/or we do a better job + # of supporting code objects in _interpreters.exec(). + compile(data, '', 'exec') + else: + # Functions defined in the __main__ module can't be pickled, + # so they can't be used here. In the future, we could possibly + # borrow from multiprocessing to work around this. + data = pickle.dumps((fn, args, kwargs)) + kind = 'function' + return (data, kind) + + if initializer is not None: + try: + initdata = resolve_task(initializer, initargs, {}) + except ValueError: + if isinstance(initializer, str) and initargs: + raise ValueError(f'an initializer script does not take args, got {initargs!r}') + raise # re-raise + else: + initdata = None + def create_context(): + return cls(initdata, shared) + return create_context, resolve_task + + @classmethod + @contextlib.contextmanager + def _capture_exc(cls, resultsid): + try: + yield + except BaseException as exc: + # Send the captured exception out on the results queue, + # but still leave it unhandled for the interpreter to handle. + err = pickle.dumps(exc) + _interpqueues.put(resultsid, (None, err), 1, UNBOUND) + raise # re-raise + + @classmethod + def _send_script_result(cls, resultsid): + _interpqueues.put(resultsid, (None, None), 0, UNBOUND) + + @classmethod + def _call(cls, func, args, kwargs, resultsid): + with cls._capture_exc(resultsid): + res = func(*args or (), **kwargs or {}) + # Send the result back. + try: + _interpqueues.put(resultsid, (res, None), 0, UNBOUND) + except _interpreters.NotShareableError: + res = pickle.dumps(res) + _interpqueues.put(resultsid, (res, None), 1, UNBOUND) + + @classmethod + def _call_pickled(cls, pickled, resultsid): + fn, args, kwargs = pickle.loads(pickled) + cls._call(fn, args, kwargs, resultsid) + + def __init__(self, initdata, shared=None): + self.initdata = initdata + self.shared = dict(shared) if shared else None + self.interpid = None + self.resultsid = None + + def __del__(self): + if self.interpid is not None: + self.finalize() + + def _exec(self, script): + assert self.interpid is not None + excinfo = _interpreters.exec(self.interpid, script, restrict=True) + if excinfo is not None: + raise ExecutionFailed(excinfo) + + def initialize(self): + assert self.interpid is None, self.interpid + self.interpid = _interpreters.create(reqrefs=True) + try: + _interpreters.incref(self.interpid) + + maxsize = 0 + fmt = 0 + self.resultsid = _interpqueues.create(maxsize, fmt, UNBOUND) + + self._exec(f'from {__name__} import WorkerContext') + + if self.shared: + _interpreters.set___main___attrs( + self.interpid, self.shared, restrict=True) + + if self.initdata: + self.run(self.initdata) + except BaseException: + self.finalize() + raise # re-raise + + def finalize(self): + interpid = self.interpid + resultsid = self.resultsid + self.resultsid = None + self.interpid = None + if resultsid is not None: + try: + _interpqueues.destroy(resultsid) + except _interpqueues.QueueNotFoundError: + pass + if interpid is not None: + try: + _interpreters.decref(interpid) + except _interpreters.InterpreterNotFoundError: + pass + + def run(self, task): + data, kind = task + if kind == 'script': + raise NotImplementedError('script kind disabled') + script = f""" +with WorkerContext._capture_exc({self.resultsid}): +{textwrap.indent(data, ' ')} +WorkerContext._send_script_result({self.resultsid})""" + elif kind == 'function': + script = f'WorkerContext._call_pickled({data!r}, {self.resultsid})' + else: + raise NotImplementedError(kind) + + try: + self._exec(script) + except ExecutionFailed as exc: + exc_wrapper = exc + else: + exc_wrapper = None + + # Return the result, or raise the exception. + while True: + try: + obj = _interpqueues.get(self.resultsid) + except _interpqueues.QueueNotFoundError: + raise # re-raise + except _interpqueues.QueueError: + continue + except ModuleNotFoundError: + # interpreters.queues doesn't exist, which means + # QueueEmpty doesn't. Act as though it does. + continue + else: + break + (res, excdata), pickled, unboundop = obj + assert unboundop is None, unboundop + if excdata is not None: + assert res is None, res + assert pickled + assert exc_wrapper is not None + exc = pickle.loads(excdata) + raise exc from exc_wrapper + return pickle.loads(res) if pickled else res + + +class BrokenInterpreterPool(_thread.BrokenThreadPool): + """ + Raised when a worker thread in an InterpreterPoolExecutor failed initializing. + """ + + +class InterpreterPoolExecutor(_thread.ThreadPoolExecutor): + + BROKEN = BrokenInterpreterPool + + @classmethod + def prepare_context(cls, initializer, initargs, shared): + return WorkerContext.prepare(initializer, initargs, shared) + + def __init__(self, max_workers=None, thread_name_prefix='', + initializer=None, initargs=(), shared=None): + """Initializes a new InterpreterPoolExecutor instance. + + Args: + max_workers: The maximum number of interpreters that can be used to + execute the given calls. + thread_name_prefix: An optional name prefix to give our threads. + initializer: A callable or script used to initialize + each worker interpreter. + initargs: A tuple of arguments to pass to the initializer. + shared: A mapping of shareabled objects to be inserted into + each worker interpreter. + """ + super().__init__(max_workers, thread_name_prefix, + initializer, initargs, shared=shared) diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py index a024033f35fb54..16cc5533d429ef 100644 --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -43,19 +43,46 @@ def _python_exit(): after_in_parent=_global_shutdown_lock.release) +class WorkerContext: + + @classmethod + def prepare(cls, initializer, initargs): + if initializer is not None: + if not callable(initializer): + raise TypeError("initializer must be a callable") + def create_context(): + return cls(initializer, initargs) + def resolve_task(fn, args, kwargs): + return (fn, args, kwargs) + return create_context, resolve_task + + def __init__(self, initializer, initargs): + self.initializer = initializer + self.initargs = initargs + + def initialize(self): + if self.initializer is not None: + self.initializer(*self.initargs) + + def finalize(self): + pass + + def run(self, task): + fn, args, kwargs = task + return fn(*args, **kwargs) + + class _WorkItem: - def __init__(self, future, fn, args, kwargs): + def __init__(self, future, task): self.future = future - self.fn = fn - self.args = args - self.kwargs = kwargs + self.task = task - def run(self): + def run(self, ctx): if not self.future.set_running_or_notify_cancel(): return try: - result = self.fn(*self.args, **self.kwargs) + result = ctx.run(self.task) except BaseException as exc: self.future.set_exception(exc) # Break a reference cycle with the exception 'exc' @@ -66,16 +93,15 @@ def run(self): __class_getitem__ = classmethod(types.GenericAlias) -def _worker(executor_reference, work_queue, initializer, initargs): - if initializer is not None: - try: - initializer(*initargs) - except BaseException: - _base.LOGGER.critical('Exception in initializer:', exc_info=True) - executor = executor_reference() - if executor is not None: - executor._initializer_failed() - return +def _worker(executor_reference, ctx, work_queue): + try: + ctx.initialize() + except BaseException: + _base.LOGGER.critical('Exception in initializer:', exc_info=True) + executor = executor_reference() + if executor is not None: + executor._initializer_failed() + return try: while True: try: @@ -89,7 +115,7 @@ def _worker(executor_reference, work_queue, initializer, initargs): work_item = work_queue.get(block=True) if work_item is not None: - work_item.run() + work_item.run(ctx) # Delete references to object. See GH-60488 del work_item continue @@ -110,6 +136,8 @@ def _worker(executor_reference, work_queue, initializer, initargs): del executor except BaseException: _base.LOGGER.critical('Exception in worker', exc_info=True) + finally: + ctx.finalize() class BrokenThreadPool(_base.BrokenExecutor): @@ -120,11 +148,17 @@ class BrokenThreadPool(_base.BrokenExecutor): class ThreadPoolExecutor(_base.Executor): + BROKEN = BrokenThreadPool + # Used to assign unique thread names when thread_name_prefix is not supplied. _counter = itertools.count().__next__ + @classmethod + def prepare_context(cls, initializer, initargs): + return WorkerContext.prepare(initializer, initargs) + def __init__(self, max_workers=None, thread_name_prefix='', - initializer=None, initargs=()): + initializer=None, initargs=(), **ctxkwargs): """Initializes a new ThreadPoolExecutor instance. Args: @@ -133,6 +167,7 @@ def __init__(self, max_workers=None, thread_name_prefix='', thread_name_prefix: An optional name prefix to give our threads. initializer: A callable used to initialize worker threads. initargs: A tuple of arguments to pass to the initializer. + ctxkwargs: Additional arguments to cls.prepare_context(). """ if max_workers is None: # ThreadPoolExecutor is often used to: @@ -146,8 +181,9 @@ def __init__(self, max_workers=None, thread_name_prefix='', if max_workers <= 0: raise ValueError("max_workers must be greater than 0") - if initializer is not None and not callable(initializer): - raise TypeError("initializer must be a callable") + (self._create_worker_context, + self._resolve_work_item_task, + ) = type(self).prepare_context(initializer, initargs, **ctxkwargs) self._max_workers = max_workers self._work_queue = queue.SimpleQueue() @@ -158,13 +194,11 @@ def __init__(self, max_workers=None, thread_name_prefix='', self._shutdown_lock = threading.Lock() self._thread_name_prefix = (thread_name_prefix or ("ThreadPoolExecutor-%d" % self._counter())) - self._initializer = initializer - self._initargs = initargs def submit(self, fn, /, *args, **kwargs): with self._shutdown_lock, _global_shutdown_lock: if self._broken: - raise BrokenThreadPool(self._broken) + raise self.BROKEN(self._broken) if self._shutdown: raise RuntimeError('cannot schedule new futures after shutdown') @@ -173,7 +207,8 @@ def submit(self, fn, /, *args, **kwargs): 'interpreter shutdown') f = _base.Future() - w = _WorkItem(f, fn, args, kwargs) + task = self._resolve_work_item_task(fn, args, kwargs) + w = _WorkItem(f, task) self._work_queue.put(w) self._adjust_thread_count() @@ -196,9 +231,8 @@ def weakref_cb(_, q=self._work_queue): num_threads) t = threading.Thread(name=thread_name, target=_worker, args=(weakref.ref(self, weakref_cb), - self._work_queue, - self._initializer, - self._initargs)) + self._create_worker_context(), + self._work_queue)) t.start() self._threads.add(t) _threads_queues[t] = self._work_queue @@ -214,7 +248,7 @@ def _initializer_failed(self): except queue.Empty: break if work_item is not None: - work_item.future.set_exception(BrokenThreadPool(self._broken)) + work_item.future.set_exception(self.BROKEN(self._broken)) def shutdown(self, wait=True, *, cancel_futures=False): with self._shutdown_lock: diff --git a/Lib/test/test_concurrent_futures/executor.py b/Lib/test/test_concurrent_futures/executor.py index 4160656cb133ab..b97d9ffd94b1f8 100644 --- a/Lib/test/test_concurrent_futures/executor.py +++ b/Lib/test/test_concurrent_futures/executor.py @@ -23,6 +23,7 @@ def make_dummy_object(_): class ExecutorTest: + # Executor.shutdown() and context manager usage is tested by # ExecutorShutdownTest. def test_submit(self): @@ -52,7 +53,8 @@ def test_map_exception(self): i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5]) self.assertEqual(i.__next__(), (0, 1)) self.assertEqual(i.__next__(), (0, 1)) - self.assertRaises(ZeroDivisionError, i.__next__) + with self.assertRaises(ZeroDivisionError): + i.__next__() @support.requires_resource('walltime') def test_map_timeout(self): diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py new file mode 100644 index 00000000000000..0de03c0d669399 --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -0,0 +1,346 @@ +import asyncio +import contextlib +import io +import os +import pickle +import sys +import time +import unittest +from concurrent.futures.interpreter import ( + ExecutionFailed, BrokenInterpreterPool, +) +import _interpreters +from test import support +import test.test_asyncio.utils as testasyncio_utils +from test.support.interpreters import queues + +from .executor import ExecutorTest, mul +from .util import BaseTestCase, InterpreterPoolMixin, setup_module + + +def noop(): + pass + + +def write_msg(fd, msg): + os.write(fd, msg + b'\0') + + +def read_msg(fd): + msg = b'' + while ch := os.read(fd, 1): + if ch == b'\0': + return msg + msg += ch + + +def get_current_name(): + return __name__ + + +def fail(exctype, msg=None): + raise exctype(msg) + + +def get_current_interpid(*extra): + interpid, _ = _interpreters.get_current() + return (interpid, *extra) + + +class InterpretersMixin(InterpreterPoolMixin): + + def pipe(self): + r, w = os.pipe() + self.addCleanup(lambda: os.close(r)) + self.addCleanup(lambda: os.close(w)) + return r, w + + +class InterpreterPoolExecutorTest( + InterpretersMixin, ExecutorTest, BaseTestCase): + + @unittest.expectedFailure + def test_init_script(self): + msg1 = b'step: init' + msg2 = b'step: run' + r, w = self.pipe() + initscript = f""" + import os + msg = {msg2!r} + os.write({w}, {msg1!r} + b'\\0') + """ + script = f""" + os.write({w}, msg + b'\\0') + """ + os.write(w, b'\0') + + executor = self.executor_type(initializer=initscript) + before_init = os.read(r, 100) + fut = executor.submit(script) + after_init = read_msg(r) + fut.result() + after_run = read_msg(r) + + self.assertEqual(before_init, b'\0') + self.assertEqual(after_init, msg1) + self.assertEqual(after_run, msg2) + + @unittest.expectedFailure + def test_init_script_args(self): + with self.assertRaises(ValueError): + self.executor_type(initializer='pass', initargs=('spam',)) + + def test_init_func(self): + msg = b'step: init' + r, w = self.pipe() + os.write(w, b'\0') + + executor = self.executor_type( + initializer=write_msg, initargs=(w, msg)) + before = os.read(r, 100) + executor.submit(mul, 10, 10) + after = read_msg(r) + + self.assertEqual(before, b'\0') + self.assertEqual(after, msg) + + def test_init_closure(self): + count = 0 + def init1(): + assert count == 0, count + def init2(): + nonlocal count + count += 1 + + with self.assertRaises(pickle.PicklingError): + self.executor_type(initializer=init1) + with self.assertRaises(pickle.PicklingError): + self.executor_type(initializer=init2) + + def test_init_instance_method(self): + class Spam: + def initializer(self): + raise NotImplementedError + spam = Spam() + + with self.assertRaises(pickle.PicklingError): + self.executor_type(initializer=spam.initializer) + + def test_init_shared(self): + msg = b'eggs' + r, w = self.pipe() + script = f"""if True: + import os + if __name__ != '__main__': + import __main__ + spam = __main__.spam + os.write({w}, spam + b'\\0') + """ + + executor = self.executor_type(shared={'spam': msg}) + fut = executor.submit(exec, script) + fut.result() + after = read_msg(r) + + self.assertEqual(after, msg) + + @unittest.expectedFailure + def test_init_exception_in_script(self): + executor = self.executor_type(initializer='raise Exception("spam")') + with executor: + with contextlib.redirect_stderr(io.StringIO()) as stderr: + fut = executor.submit('pass') + with self.assertRaises(BrokenInterpreterPool): + fut.result() + stderr = stderr.getvalue() + self.assertIn('ExecutionFailed: Exception: spam', stderr) + self.assertIn('Uncaught in the interpreter:', stderr) + self.assertIn('The above exception was the direct cause of the following exception:', + stderr) + + def test_init_exception_in_func(self): + executor = self.executor_type(initializer=fail, + initargs=(Exception, 'spam')) + with executor: + with contextlib.redirect_stderr(io.StringIO()) as stderr: + fut = executor.submit(noop) + with self.assertRaises(BrokenInterpreterPool): + fut.result() + stderr = stderr.getvalue() + self.assertIn('ExecutionFailed: Exception: spam', stderr) + self.assertIn('Uncaught in the interpreter:', stderr) + self.assertIn('The above exception was the direct cause of the following exception:', + stderr) + + @unittest.expectedFailure + def test_submit_script(self): + msg = b'spam' + r, w = self.pipe() + script = f""" + import os + os.write({w}, __name__.encode('utf-8') + b'\\0') + """ + executor = self.executor_type() + + fut = executor.submit(script) + res = fut.result() + after = read_msg(r) + + self.assertEqual(after, b'__main__') + self.assertIs(res, None) + + def test_submit_closure(self): + spam = True + def task1(): + return spam + def task2(): + nonlocal spam + spam += 1 + return spam + + executor = self.executor_type() + with self.assertRaises(pickle.PicklingError): + executor.submit(task1) + with self.assertRaises(pickle.PicklingError): + executor.submit(task2) + + def test_submit_local_instance(self): + class Spam: + def __init__(self): + self.value = True + + executor = self.executor_type() + with self.assertRaises(pickle.PicklingError): + executor.submit(Spam) + + def test_submit_instance_method(self): + class Spam: + def run(self): + return True + spam = Spam() + + executor = self.executor_type() + with self.assertRaises(pickle.PicklingError): + executor.submit(spam.run) + + def test_submit_func_globals(self): + executor = self.executor_type() + fut = executor.submit(get_current_name) + name = fut.result() + + self.assertEqual(name, __name__) + self.assertNotEqual(name, '__main__') + + @unittest.expectedFailure + def test_submit_exception_in_script(self): + fut = self.executor.submit('raise Exception("spam")') + with self.assertRaises(Exception) as captured: + fut.result() + self.assertIs(type(captured.exception), Exception) + self.assertEqual(str(captured.exception), 'spam') + cause = captured.exception.__cause__ + self.assertIs(type(cause), ExecutionFailed) + for attr in ('__name__', '__qualname__', '__module__'): + self.assertEqual(getattr(cause.excinfo.type, attr), + getattr(Exception, attr)) + self.assertEqual(cause.excinfo.msg, 'spam') + + def test_submit_exception_in_func(self): + fut = self.executor.submit(fail, Exception, 'spam') + with self.assertRaises(Exception) as captured: + fut.result() + self.assertIs(type(captured.exception), Exception) + self.assertEqual(str(captured.exception), 'spam') + cause = captured.exception.__cause__ + self.assertIs(type(cause), ExecutionFailed) + for attr in ('__name__', '__qualname__', '__module__'): + self.assertEqual(getattr(cause.excinfo.type, attr), + getattr(Exception, attr)) + self.assertEqual(cause.excinfo.msg, 'spam') + + def test_saturation(self): + blocker = queues.create() + executor = self.executor_type(4, shared=dict(blocker=blocker)) + + for i in range(15 * executor._max_workers): + executor.submit(exec, 'import __main__; __main__.blocker.get()') + #executor.submit('blocker.get()') + self.assertEqual(len(executor._threads), executor._max_workers) + for i in range(15 * executor._max_workers): + blocker.put_nowait(None) + executor.shutdown(wait=True) + + @support.requires_gil_enabled("gh-117344: test is flaky without the GIL") + def test_idle_thread_reuse(self): + executor = self.executor_type() + executor.submit(mul, 21, 2).result() + executor.submit(mul, 6, 7).result() + executor.submit(mul, 3, 14).result() + self.assertEqual(len(executor._threads), 1) + executor.shutdown(wait=True) + + +class AsyncioTest(InterpretersMixin, testasyncio_utils.TestCase): + + def setUp(self): + super().setUp() + self.loop = asyncio.new_event_loop() + self.set_event_loop(self.loop) + + self.executor = self.executor_type() + self.addCleanup(lambda: self.executor.shutdown()) + + def tearDown(self): + if not self.loop.is_closed(): + testasyncio_utils.run_briefly(self.loop) + + self.doCleanups() + support.gc_collect() + super().tearDown() + + def test_run_in_executor(self): + unexpected, _ = _interpreters.get_current() + + func = get_current_interpid + fut = self.loop.run_in_executor(self.executor, func, 'yo') + interpid, res = self.loop.run_until_complete(fut) + + self.assertEqual(res, 'yo') + self.assertNotEqual(interpid, unexpected) + + def test_run_in_executor_cancel(self): + executor = self.executor_type() + + called = False + + def patched_call_soon(*args): + nonlocal called + called = True + + func = time.sleep + fut = self.loop.run_in_executor(self.executor, func, 0.05) + fut.cancel() + self.loop.run_until_complete( + self.loop.shutdown_default_executor()) + self.loop.close() + self.loop.call_soon = patched_call_soon + self.loop.call_soon_threadsafe = patched_call_soon + time.sleep(0.4) + self.assertFalse(called) + + def test_default_executor(self): + unexpected, _ = _interpreters.get_current() + + self.loop.set_default_executor(self.executor) + fut = self.loop.run_in_executor(None, get_current_interpid) + interpid, = self.loop.run_until_complete(fut) + + self.assertNotEqual(interpid, unexpected) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/util.py b/Lib/test/test_concurrent_futures/util.py index 3b8ec3e205d5aa..52baab51340fc9 100644 --- a/Lib/test/test_concurrent_futures/util.py +++ b/Lib/test/test_concurrent_futures/util.py @@ -74,6 +74,10 @@ class ThreadPoolMixin(ExecutorMixin): executor_type = futures.ThreadPoolExecutor +class InterpreterPoolMixin(ExecutorMixin): + executor_type = futures.InterpreterPoolExecutor + + class ProcessPoolForkMixin(ExecutorMixin): executor_type = futures.ProcessPoolExecutor ctx = "fork" @@ -120,6 +124,7 @@ def get_context(self): def create_executor_tests(remote_globals, mixin, bases=(BaseTestCase,), executor_mixins=(ThreadPoolMixin, + InterpreterPoolMixin, ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin)): diff --git a/Misc/NEWS.d/next/Library/2024-09-27-15-42-55.gh-issue-124694.uUy32y.rst b/Misc/NEWS.d/next/Library/2024-09-27-15-42-55.gh-issue-124694.uUy32y.rst new file mode 100644 index 00000000000000..1aa1a463b0c63a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-27-15-42-55.gh-issue-124694.uUy32y.rst @@ -0,0 +1,6 @@ +We've added :class:`concurrent.futures.InterpreterPoolExecutor`, which +allows you to run code in multiple isolated interpreters. This allows you +to circumvent the limitations of CPU-bound threads (due to the GIL). Patch +by Eric Snow. + +This addition is unrelated to :pep:`734`. From 624be8699aec22bef137041478078c6fafaf032e Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 17 Oct 2024 00:07:37 -0700 Subject: [PATCH 212/247] GH-99749: Add optional feature to suggest correct names (ArgumentParser) (GH-124456) --- Doc/library/argparse.rst | 28 ++++- Lib/argparse.py | 35 ++++-- Lib/test/test_argparse.py | 103 +++++++++++++++--- ...4-09-24-18-49-16.gh-issue-99749.gBDJX7.rst | 1 + 4 files changed, 144 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-09-24-18-49-16.gh-issue-99749.gBDJX7.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 51ab8e29ff96d5..ee8562b81770b6 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -61,7 +61,8 @@ ArgumentParser objects formatter_class=argparse.HelpFormatter, \ prefix_chars='-', fromfile_prefix_chars=None, \ argument_default=None, conflict_handler='error', \ - add_help=True, allow_abbrev=True, exit_on_error=True) + add_help=True, allow_abbrev=True, exit_on_error=True, \ + suggest_on_error=False) Create a new :class:`ArgumentParser` object. All parameters should be passed as keyword arguments. Each parameter has its own more detailed description @@ -103,6 +104,10 @@ ArgumentParser objects * exit_on_error_ - Determines whether or not ArgumentParser exits with error info when an error occurs. (default: ``True``) + * suggest_on_error_ - Enables suggestions for mistyped argument choices + and subparser names (default: ``False``) + + .. versionchanged:: 3.5 *allow_abbrev* parameter was added. @@ -559,6 +564,27 @@ If the user would like to catch errors manually, the feature can be enabled by s .. versionadded:: 3.9 +suggest_on_error +^^^^^^^^^^^^^^^^ + +By default, when a user passes an invalid argument choice or subparser name, +:class:`ArgumentParser` will exit with error info and list the permissible +argument choices (if specified) or subparser names as part of the error message. + +If the user would like to enable suggestions for mistyped argument choices and +subparser names, the feature can be enabled by setting ``suggest_on_error`` to +``True``. Note that this only applies for arguments when the choices specified +are strings:: + + >>> parser = argparse.ArgumentParser(description='Process some integers.', suggest_on_error=True) + >>> parser.add_argument('--action', choices=['sum', 'max']) + >>> parser.add_argument('integers', metavar='N', type=int, nargs='+', + ... help='an integer for the accumulator') + >>> parser.parse_args(['--action', 'sumn', 1, 2, 3]) + tester.py: error: argument --action: invalid choice: 'sumn', maybe you meant 'sum'? (choose from 'sum', 'max') + +.. versionadded:: 3.14 + The add_argument() method ------------------------- diff --git a/Lib/argparse.py b/Lib/argparse.py index fa9f5211257e96..ece6f2e880d5cb 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1773,6 +1773,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): - allow_abbrev -- Allow long options to be abbreviated unambiguously - exit_on_error -- Determines whether or not ArgumentParser exits with error info when an error occurs + - suggest_on_error - Enables suggestions for mistyped argument choices + and subparser names. (default: ``False``) """ def __init__(self, @@ -1788,7 +1790,8 @@ def __init__(self, conflict_handler='error', add_help=True, allow_abbrev=True, - exit_on_error=True): + exit_on_error=True, + suggest_on_error=False): superinit = super(ArgumentParser, self).__init__ superinit(description=description, @@ -1804,6 +1807,7 @@ def __init__(self, self.add_help = add_help self.allow_abbrev = allow_abbrev self.exit_on_error = exit_on_error + self.suggest_on_error = suggest_on_error add_group = self.add_argument_group self._positionals = add_group(_('positional arguments')) @@ -2601,14 +2605,27 @@ def _get_value(self, action, arg_string): def _check_value(self, action, value): # converted value must be one of the choices (if specified) choices = action.choices - if choices is not None: - if isinstance(choices, str): - choices = iter(choices) - if value not in choices: - args = {'value': str(value), - 'choices': ', '.join(map(str, action.choices))} - msg = _('invalid choice: %(value)r (choose from %(choices)s)') - raise ArgumentError(action, msg % args) + if choices is None: + return + + if isinstance(choices, str): + choices = iter(choices) + + if value not in choices: + args = {'value': str(value), + 'choices': ', '.join(map(str, action.choices))} + msg = _('invalid choice: %(value)r (choose from %(choices)s)') + + if self.suggest_on_error and isinstance(value, str): + if all(isinstance(choice, str) for choice in action.choices): + import difflib + suggestions = difflib.get_close_matches(value, action.choices, 1) + if suggestions: + args['closest'] = suggestions[0] + msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' + '(choose from %(choices)s)') + + raise ArgumentError(action, msg % args) # ======================= # Help-formatting methods diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 78692fd3474782..a3c096ef3199c8 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2253,6 +2253,95 @@ class TestNegativeNumber(ParserTestCase): ('--complex -1e-3j', NS(int=None, float=None, complex=-0.001j)), ] +class TestArgumentAndSubparserSuggestions(TestCase): + """Test error handling and suggestion when a user makes a typo""" + + def test_wrong_argument_error_with_suggestions(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser.add_argument('foo', choices=['bar', 'baz']) + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('bazz',)) + self.assertIn( + "error: argument foo: invalid choice: 'bazz', maybe you meant 'baz'? (choose from bar, baz)", + excinfo.exception.stderr + ) + + def test_wrong_argument_error_no_suggestions(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=False) + parser.add_argument('foo', choices=['bar', 'baz']) + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('bazz',)) + self.assertIn( + "error: argument foo: invalid choice: 'bazz' (choose from bar, baz)", + excinfo.exception.stderr, + ) + + def test_wrong_argument_subparsers_with_suggestions(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=True) + subparsers = parser.add_subparsers(required=True) + subparsers.add_parser('foo') + subparsers.add_parser('bar') + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('baz',)) + self.assertIn( + "error: argument {foo,bar}: invalid choice: 'baz', maybe you meant" + " 'bar'? (choose from foo, bar)", + excinfo.exception.stderr, + ) + + def test_wrong_argument_subparsers_no_suggestions(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=False) + subparsers = parser.add_subparsers(required=True) + subparsers.add_parser('foo') + subparsers.add_parser('bar') + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('baz',)) + self.assertIn( + "error: argument {foo,bar}: invalid choice: 'baz' (choose from foo, bar)", + excinfo.exception.stderr, + ) + + def test_wrong_argument_no_suggestion_implicit(self): + parser = ErrorRaisingArgumentParser() + parser.add_argument('foo', choices=['bar', 'baz']) + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('bazz',)) + self.assertIn( + "error: argument foo: invalid choice: 'bazz' (choose from bar, baz)", + excinfo.exception.stderr, + ) + + def test_suggestions_choices_empty(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser.add_argument('foo', choices=[]) + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('bazz',)) + self.assertIn( + "error: argument foo: invalid choice: 'bazz' (choose from )", + excinfo.exception.stderr, + ) + + def test_suggestions_choices_int(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser.add_argument('foo', choices=[1, 2]) + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('3',)) + self.assertIn( + "error: argument foo: invalid choice: '3' (choose from 1, 2)", + excinfo.exception.stderr, + ) + + def test_suggestions_choices_mixed_types(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser.add_argument('foo', choices=[1, '2']) + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('3',)) + self.assertIn( + "error: argument foo: invalid choice: '3' (choose from 1, 2)", + excinfo.exception.stderr, + ) + + class TestInvalidAction(TestCase): """Test invalid user defined Action""" @@ -2505,18 +2594,6 @@ def test_required_subparsers_no_destination_error(self): 'error: the following arguments are required: {foo,bar}\n$' ) - def test_wrong_argument_subparsers_no_destination_error(self): - parser = ErrorRaisingArgumentParser() - subparsers = parser.add_subparsers(required=True) - subparsers.add_parser('foo') - subparsers.add_parser('bar') - with self.assertRaises(ArgumentParserError) as excinfo: - parser.parse_args(('baz',)) - self.assertRegex( - excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from foo, bar\)\n$" - ) - def test_optional_subparsers(self): parser = ErrorRaisingArgumentParser() subparsers = parser.add_subparsers(dest='command', required=False) @@ -2862,7 +2939,7 @@ def test_single_parent_mutex(self): parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent]) self._test_mutex_ab(parser.parse_args) - def test_single_granparent_mutex(self): + def test_single_grandparent_mutex(self): parents = [self.ab_mutex_parent] parser = ErrorRaisingArgumentParser(add_help=False, parents=parents) parser = ErrorRaisingArgumentParser(parents=[parser]) diff --git a/Misc/NEWS.d/next/Library/2024-09-24-18-49-16.gh-issue-99749.gBDJX7.rst b/Misc/NEWS.d/next/Library/2024-09-24-18-49-16.gh-issue-99749.gBDJX7.rst new file mode 100644 index 00000000000000..3ecd75c5b551b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-24-18-49-16.gh-issue-99749.gBDJX7.rst @@ -0,0 +1 @@ +Adds a feature to optionally enable suggestions for argument choices and subparser names if mistyped by the user. From 7b04496e5c7ed47e9653f4591674fc9ffef34587 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 17 Oct 2024 02:11:47 -0700 Subject: [PATCH 213/247] gh-125542: Deprecate prefix_chars in ArgumentParser.add_argument_group() (GH-125563) --- .../pending-removal-in-future.rst | 9 +++++-- Doc/library/argparse.rst | 4 +++ Doc/whatsnew/3.14.rst | 6 +++++ Lib/argparse.py | 8 ++++++ Lib/test/test_argparse.py | 25 +++++++++++++++++++ ...-10-16-04-50-53.gh-issue-125542.vZJ-Ns.rst | 2 ++ 6 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-16-04-50-53.gh-issue-125542.vZJ-Ns.rst diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst index f916797c07a068..d77fc86eab0ed6 100644 --- a/Doc/deprecations/pending-removal-in-future.rst +++ b/Doc/deprecations/pending-removal-in-future.rst @@ -4,8 +4,13 @@ Pending removal in future versions The following APIs will be removed in the future, although there is currently no date scheduled for their removal. -* :mod:`argparse`: Nesting argument groups and nesting mutually exclusive - groups are deprecated. +* :mod:`argparse`: + + * Nesting argument groups and nesting mutually exclusive + groups are deprecated. + * Passing the undocumented keyword argument *prefix_chars* to + :meth:`~argparse.ArgumentParser.add_argument_group` is now + deprecated. * :mod:`array`'s ``'u'`` format code (:gh:`57281`) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index ee8562b81770b6..ef0db3e9789c98 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1894,6 +1894,10 @@ Argument groups The function exists on the API by accident through inheritance and will be removed in the future. + .. deprecated:: 3.14 + Passing prefix_chars_ to :meth:`add_argument_group` + is now deprecated. + Mutual exclusion ^^^^^^^^^^^^^^^^ diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 9543af3c7ca225..feb65f244827ad 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -428,6 +428,12 @@ asyncio Deprecated ========== +* :mod:`argparse`: + Passing the undocumented keyword argument *prefix_chars* to + :meth:`~argparse.ArgumentParser.add_argument_group` is now + deprecated. + (Contributed by Savannah Ostrowski in :gh:`125563`.) + * :mod:`asyncio`: :func:`!asyncio.iscoroutinefunction` is deprecated and will be removed in Python 3.16, diff --git a/Lib/argparse.py b/Lib/argparse.py index ece6f2e880d5cb..49271a146c7282 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1662,6 +1662,14 @@ def _check_help(self, action): class _ArgumentGroup(_ActionsContainer): def __init__(self, container, title=None, description=None, **kwargs): + if 'prefix_chars' in kwargs: + import warnings + depr_msg = ( + "The use of the undocumented 'prefix_chars' parameter in " + "ArgumentParser.add_argument_group() is deprecated." + ) + warnings.warn(depr_msg, DeprecationWarning, stacklevel=3) + # add any missing keyword arguments by checking the container update = kwargs.setdefault update('conflict_handler', container.conflict_handler) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index a3c096ef3199c8..4fa669718abc50 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2893,6 +2893,31 @@ def test_interleaved_groups(self): result = parser.parse_args('1 2 3 4'.split()) self.assertEqual(expected, result) +class TestGroupConstructor(TestCase): + def test_group_prefix_chars(self): + parser = ErrorRaisingArgumentParser() + msg = ( + "The use of the undocumented 'prefix_chars' parameter in " + "ArgumentParser.add_argument_group() is deprecated." + ) + with self.assertWarns(DeprecationWarning) as cm: + parser.add_argument_group(prefix_chars='-+') + self.assertEqual(msg, str(cm.warning)) + self.assertEqual(cm.filename, __file__) + + def test_group_prefix_chars_default(self): + # "default" isn't quite the right word here, but it's the same as + # the parser's default prefix so it's a good test + parser = ErrorRaisingArgumentParser() + msg = ( + "The use of the undocumented 'prefix_chars' parameter in " + "ArgumentParser.add_argument_group() is deprecated." + ) + with self.assertWarns(DeprecationWarning) as cm: + parser.add_argument_group(prefix_chars='-') + self.assertEqual(msg, str(cm.warning)) + self.assertEqual(cm.filename, __file__) + # =================== # Parent parser tests # =================== diff --git a/Misc/NEWS.d/next/Library/2024-10-16-04-50-53.gh-issue-125542.vZJ-Ns.rst b/Misc/NEWS.d/next/Library/2024-10-16-04-50-53.gh-issue-125542.vZJ-Ns.rst new file mode 100644 index 00000000000000..777920cc54ff9b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-16-04-50-53.gh-issue-125542.vZJ-Ns.rst @@ -0,0 +1,2 @@ +Deprecate passing keyword-only *prefix_chars* argument to +:meth:`argparse.ArgumentParser.add_argument_group`. From dbcc5ac4709dfd8dfaf323d51f135f2218d14068 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 17 Oct 2024 04:41:22 -0700 Subject: [PATCH 214/247] gh-95836: Add custom type converter examples to argparse tutorial (GH-125376) --- Doc/howto/argparse.rst | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst index 30d9ac700376e6..1efbee64d60bb3 100644 --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -841,6 +841,53 @@ translated messages. To translate your own strings in the :mod:`argparse` output, use :mod:`gettext`. +Custom type converters +====================== + +The :mod:`argparse` module allows you to specify custom type converters for +your command-line arguments. This allows you to modify user input before it's +stored in the :class:`argparse.Namespace`. This can be useful when you need to +pre-process the input before it is used in your program. + +When using a custom type converter, you can use any callable that takes a +single string argument (the argument value) and returns the converted value. +However, if you need to handle more complex scenarios, you can use a custom +action class with the **action** parameter instead. + +For example, let's say you want to handle arguments with different prefixes and +process them accordingly:: + + import argparse + + parser = argparse.ArgumentParser(prefix_chars='-+') + + parser.add_argument('-a', metavar='', action='append', + type=lambda x: ('-', x)) + parser.add_argument('+a', metavar='', action='append', + type=lambda x: ('+', x)) + + args = parser.parse_args() + print(args) + +Output: + +.. code-block:: shell-session + + $ python prog.py -a value1 +a value2 + Namespace(a=[('-', 'value1'), ('+', 'value2')]) + +In this example, we: + +* Created a parser with custom prefix characters using the ``prefix_chars`` + parameter. + +* Defined two arguments, ``-a`` and ``+a``, which used the ``type`` parameter to + create custom type converters to store the value in a tuple with the prefix. + +Without the custom type converters, the arguments would have treated the ``-a`` +and ``+a`` as the same argument, which would have been undesirable. By using custom +type converters, we were able to differentiate between the two arguments. + Conclusion ========== From 37986e830ba25d2c382988b06bbe27410596346c Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 17 Oct 2024 08:20:30 -0400 Subject: [PATCH 215/247] gh-123153: Fix PGO builds with free-threading on Windows (#125607) * gh-123153: Fix PGO builds with free-threading * Redo how the #define works --- Python/ceval.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 43776e773e0deb..98d95b28488fd0 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -761,12 +761,20 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch) * so consume 3 units of C stack */ #define PY_EVAL_C_STACK_UNITS 2 -#if defined(_MSC_VER) && defined(_Py_USING_PGO) && defined(_Py_JIT) -/* _PyEval_EvalFrameDefault is too large to optimize for speed with - PGO on MSVC when the JIT is enabled. Disable that optimization - around this function only. If this is fixed upstream, we should - gate this on the version of MSVC. + +/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC + when the JIT is enabled or GIL is disabled. Disable that optimization around + this function only. If this is fixed upstream, we should gate this on the + version of MSVC. */ +#if (defined(_MSC_VER) && \ + defined(_Py_USING_PGO) && \ + (defined(_Py_JIT) || \ + defined(Py_GIL_DISABLED))) +#define DO_NOT_OPTIMIZE_INTERP_LOOP +#endif + +#ifdef DO_NOT_OPTIMIZE_INTERP_LOOP # pragma optimize("t", off) /* This setting is reversed below following _PyEval_EvalFrameDefault */ #endif @@ -1146,7 +1154,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } -#if defined(_MSC_VER) && defined(_Py_USING_PGO) && defined(_Py_JIT) +#ifdef DO_NOT_OPTIMIZE_INTERP_LOOP # pragma optimize("", on) #endif From 0d88b995a641315306d56fba7d07479b2c5f57ef Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Thu, 17 Oct 2024 17:33:37 +0300 Subject: [PATCH 216/247] gh-125644: Update `locations.md` reference (#125645) Signed-off-by: Emmanuel Ferdman --- InternalDocs/compiler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InternalDocs/compiler.md b/InternalDocs/compiler.md index acef6def563154..e9608977b0cbb3 100644 --- a/InternalDocs/compiler.md +++ b/InternalDocs/compiler.md @@ -447,7 +447,7 @@ bytecode. This includes transforming pseudo instructions into actual instruction converting jump targets from logical labels to relative offsets, and construction of the [exception table](exception_handling.md) and -[locations table](https://github.com/python/cpython/blob/main/Objects/locations.md). +[locations table](https://github.com/python/cpython/blob/main/InternalDocs/locations.md). The bytecode and tables are then wrapped into a ``PyCodeObject`` along with additional metadata, including the ``consts`` and ``names`` arrays, information about function reference to the source code (filename, etc). All of this is implemented by From 528bbab96feadbfabb798547e5bb2ad52070fb73 Mon Sep 17 00:00:00 2001 From: Jonathan Protzenko Date: Thu, 17 Oct 2024 08:08:43 -0700 Subject: [PATCH 217/247] GH-99108: Make vectorized versions of Blake2 available on x86, too (#125244) Accomplished by updating HACL* vendored code from hacl-star/hacl-star@a6a09496d9cff652b567d26f2c3ab012321b632a to hacl-star/hacl-star@315a9e491d2bc347b9dae99e0ea506995ea84d9d Co-authored-by: Victor Stinner Co-authored-by: Zachary Ware --- Misc/sbom.spdx.json | 48 ++-- Modules/_hacl/Hacl_Hash_Blake2b.c | 260 +++++++++++------- Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c | 225 +++++++++------ Modules/_hacl/Hacl_Hash_Blake2s.c | 231 ++++++++++------ Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c | 196 ++++++++----- .../include/krml/FStar_UInt128_Verified.h | 2 +- .../include/krml/FStar_UInt_8_16_32_64.h | 2 +- .../krml/fstar_uint128_struct_endianness.h | 2 +- Modules/_hacl/include/krml/internal/target.h | 6 +- .../_hacl/include/krml/lowstar_endianness.h | 2 +- Modules/_hacl/libintvector.h | 2 +- Modules/_hacl/refresh.sh | 2 +- 12 files changed, 619 insertions(+), 359 deletions(-) diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json index f07ad9423d9039..cc73e93009b43f 100644 --- a/Misc/sbom.spdx.json +++ b/Misc/sbom.spdx.json @@ -300,11 +300,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "c96cba53034348537ac423a220803b06cd9f0a43" + "checksumValue": "a34e821b68ef5334eccf4f729b28bb7bb65b965e" }, { "algorithm": "SHA256", - "checksumValue": "9f4fb5c70678638cfd163cc990be1def356cf7b65b75faa4666db8c5f8593530" + "checksumValue": "4582db9143c0810b98838a5357c577e0b32ae77f3018486159df4e0dfd3fce3c" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2b.c" @@ -328,11 +328,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "e11e2d1771e56c0afbdb0673906898b3a67e0cc3" + "checksumValue": "0ffe60c6d5eed5dd222515e820d461d319d16b1f" }, { "algorithm": "SHA256", - "checksumValue": "d5bf29d995f7cb9861841b813aa01206664895a1c5aa166a4796785c02117bf4" + "checksumValue": "4804cb3ce68bfdcf98853d6f1d77b4a844a3c2796f776b39770ba327e400d402" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c" @@ -370,11 +370,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "5422517af799cf74b194821fb2a1f39e3b02c54d" + "checksumValue": "cf035ffeff875bc74345a47373ce25dc408ea9dc" }, { "algorithm": "SHA256", - "checksumValue": "c66adab0259f2c2229e010cd635a982e8c2b8836e59e43e7867992d4148e4d9a" + "checksumValue": "579059b002c45fab0fed6381e85c3f5eaf1d959400ca64b103542ac6c35bade3" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2s.c" @@ -398,11 +398,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "7822db8e7c2f60dd64a18e112a1bc369e7f7a0ff" + "checksumValue": "9bb53022d158a9c349edb52a8def8aac7d098a4e" }, { "algorithm": "SHA256", - "checksumValue": "94b0cd3cf1f7385325ee878d2ef06affc8d6412af9302ca47d1aa6d858182050" + "checksumValue": "2abde0c6b5da0402e91b4bedfe786c24b908fbdc04e08e74651c7624729254d9" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c" @@ -580,11 +580,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "12c0c680c93b8112b97cc575faacbb3cbbd315b1" + "checksumValue": "7665829b9396f72e7f8098080d6d6773565468e9" }, { "algorithm": "SHA256", - "checksumValue": "455e94f24a0900deda7e6e36f4714e4253d32cea077f97e23f90c569a717bc48" + "checksumValue": "ca7357ee70365c690664a44f6522e526636151d9ed2da8d0d29da15bb8556530" } ], "fileName": "Modules/_hacl/include/krml/FStar_UInt128_Verified.h" @@ -594,11 +594,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "62b44acbbdc77b749c36c242cda027bacf7679f8" + "checksumValue": "a2db924d0e8f7df3139e9a20355ffa520aded479" }, { "algorithm": "SHA256", - "checksumValue": "65decdb74c24049aa19430462a51219250cfc65d8c162778e42df88b3142fa42" + "checksumValue": "f1de79fb4c763b215c823f44471bbae6b65e6bb533eb52a5863d551d5e2e6748" } ], "fileName": "Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h" @@ -608,11 +608,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "1987119a563a8fdc5966286e274f716dbcea77ee" + "checksumValue": "7f23693151d5409623cbe886e5b45a0e4f0d3c72" }, { "algorithm": "SHA256", - "checksumValue": "fe57e1bc5ce3224d106e36cb8829b5399c63a68a70b0ccd0c91d82a4565c8869" + "checksumValue": "1c9bee7ac4b987c73cc3aba6b7ceed8ec7e75c9a741810e4411f35602490e0d8" } ], "fileName": "Modules/_hacl/include/krml/fstar_uint128_struct_endianness.h" @@ -622,11 +622,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "81872ecdbd39b09cd813dee6e1dbed113a81aa4a" + "checksumValue": "9881567f43deb32bae77a84b2d349858a24b6685" }, { "algorithm": "SHA256", - "checksumValue": "1eef18295d412129007816fe65b7f15c0be8ad32840ef5e3dfaa5b67317e1b51" + "checksumValue": "3382156e32fcb376009177d3d2dc9712ff7c8c02afb97b3e16d98b41a2114f84" } ], "fileName": "Modules/_hacl/include/krml/internal/target.h" @@ -636,11 +636,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "964e09bd99ff2366afd6193b59863fc925e7fb05" + "checksumValue": "e18efc9239a5df0f222b5f7b0a65f72509d7e304" }, { "algorithm": "SHA256", - "checksumValue": "3734c7942bec9a434e16df069fa45bdcb84b130f14417bc5f7bfe8546272d9f5" + "checksumValue": "47dd5a7d21b5302255f9fff28884f65d3056fc3f54471ed62ec85fa1904f8aa5" } ], "fileName": "Modules/_hacl/include/krml/lowstar_endianness.h" @@ -804,11 +804,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "d5d85ee8f0bd52781fe470d0bf73ec388ddb3999" + "checksumValue": "f4a33ad535768b860362ab0bd033a70da0b524b7" }, { "algorithm": "SHA256", - "checksumValue": "9a421b998add98fe366374641c4edb27617ff539a59f0963879f345065d3d39d" + "checksumValue": "433cdf4ba80bc72e0cea5d4b420ff18676baeafdb5ba19adf5b7fb33e90b424b" } ], "fileName": "Modules/_hacl/libintvector.h" @@ -1640,14 +1640,14 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "988a74f5fbb59baca2d54e41447997ada92f4ebc59888dfb717438013f859117" + "checksumValue": "935ae51d0ff0bf1403f0ecc1ff02b8f685d09053618558c07fbe4bd2abbc5dd1" } ], - "downloadLocation": "https://github.com/hacl-star/hacl-star/archive/a6a09496d9cff652b567d26f2c3ab012321b632a.zip", + "downloadLocation": "https://github.com/hacl-star/hacl-star/archive/315a9e491d2bc347b9dae99e0ea506995ea84d9d.zip", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:hacl-star:hacl-star:a6a09496d9cff652b567d26f2c3ab012321b632a:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:hacl-star:hacl-star:315a9e491d2bc347b9dae99e0ea506995ea84d9d:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1655,7 +1655,7 @@ "name": "hacl-star", "originator": "Organization: HACL* Developers", "primaryPackagePurpose": "SOURCE", - "versionInfo": "a6a09496d9cff652b567d26f2c3ab012321b632a" + "versionInfo": "315a9e491d2bc347b9dae99e0ea506995ea84d9d" }, { "SPDXID": "SPDXRef-PACKAGE-macholib", diff --git a/Modules/_hacl/Hacl_Hash_Blake2b.c b/Modules/_hacl/Hacl_Hash_Blake2b.c index e13f16fd971c56..cd3b9777e09f6c 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2b.c +++ b/Modules/_hacl/Hacl_Hash_Blake2b.c @@ -575,86 +575,6 @@ void Hacl_Hash_Blake2b_init(uint64_t *hash, uint32_t kk, uint32_t nn) r1[3U] = iv7_; } -static void init_with_params(uint64_t *hash, Hacl_Hash_Blake2b_blake2_params p) -{ - uint64_t tmp[8U] = { 0U }; - uint64_t *r0 = hash; - uint64_t *r1 = hash + 4U; - uint64_t *r2 = hash + 8U; - uint64_t *r3 = hash + 12U; - uint64_t iv0 = Hacl_Hash_Blake2b_ivTable_B[0U]; - uint64_t iv1 = Hacl_Hash_Blake2b_ivTable_B[1U]; - uint64_t iv2 = Hacl_Hash_Blake2b_ivTable_B[2U]; - uint64_t iv3 = Hacl_Hash_Blake2b_ivTable_B[3U]; - uint64_t iv4 = Hacl_Hash_Blake2b_ivTable_B[4U]; - uint64_t iv5 = Hacl_Hash_Blake2b_ivTable_B[5U]; - uint64_t iv6 = Hacl_Hash_Blake2b_ivTable_B[6U]; - uint64_t iv7 = Hacl_Hash_Blake2b_ivTable_B[7U]; - r2[0U] = iv0; - r2[1U] = iv1; - r2[2U] = iv2; - r2[3U] = iv3; - r3[0U] = iv4; - r3[1U] = iv5; - r3[2U] = iv6; - r3[3U] = iv7; - uint8_t kk = p.key_length; - uint8_t nn = p.digest_length; - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint64_t *os = tmp + 4U; - uint8_t *bj = p.salt + i * 8U; - uint64_t u = load64_le(bj); - uint64_t r = u; - uint64_t x = r; - os[i] = x;); - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint64_t *os = tmp + 6U; - uint8_t *bj = p.personal + i * 8U; - uint64_t u = load64_le(bj); - uint64_t r = u; - uint64_t x = r; - os[i] = x;); - tmp[0U] = - (uint64_t)nn - ^ - ((uint64_t)kk - << 8U - ^ ((uint64_t)p.fanout << 16U ^ ((uint64_t)p.depth << 24U ^ (uint64_t)p.leaf_length << 32U))); - tmp[1U] = p.node_offset; - tmp[2U] = (uint64_t)p.node_depth ^ (uint64_t)p.inner_length << 8U; - tmp[3U] = 0ULL; - uint64_t tmp0 = tmp[0U]; - uint64_t tmp1 = tmp[1U]; - uint64_t tmp2 = tmp[2U]; - uint64_t tmp3 = tmp[3U]; - uint64_t tmp4 = tmp[4U]; - uint64_t tmp5 = tmp[5U]; - uint64_t tmp6 = tmp[6U]; - uint64_t tmp7 = tmp[7U]; - uint64_t iv0_ = iv0 ^ tmp0; - uint64_t iv1_ = iv1 ^ tmp1; - uint64_t iv2_ = iv2 ^ tmp2; - uint64_t iv3_ = iv3 ^ tmp3; - uint64_t iv4_ = iv4 ^ tmp4; - uint64_t iv5_ = iv5 ^ tmp5; - uint64_t iv6_ = iv6 ^ tmp6; - uint64_t iv7_ = iv7 ^ tmp7; - r0[0U] = iv0_; - r0[1U] = iv1_; - r0[2U] = iv2_; - r0[3U] = iv3_; - r1[0U] = iv4_; - r1[1U] = iv5_; - r1[2U] = iv6_; - r1[3U] = iv7_; -} - static void update_key(uint64_t *wv, uint64_t *hash, uint32_t kk, uint8_t *k, uint32_t ll) { FStar_UInt128_uint128 lb = FStar_UInt128_uint64_to_uint128((uint64_t)128U); @@ -811,16 +731,92 @@ static Hacl_Hash_Blake2b_state_t uint8_t nn = p1->digest_length; bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; - uint32_t kk2 = (uint32_t)i.key_length; + uint64_t *h = block_state.f3.snd; + uint32_t kk20 = (uint32_t)i.key_length; uint8_t *k_1 = key.snd; - if (!(kk2 == 0U)) + if (!(kk20 == 0U)) { - uint8_t *sub_b = buf + kk2; - memset(sub_b, 0U, (128U - kk2) * sizeof (uint8_t)); - memcpy(buf, k_1, kk2 * sizeof (uint8_t)); + uint8_t *sub_b = buf + kk20; + memset(sub_b, 0U, (128U - kk20) * sizeof (uint8_t)); + memcpy(buf, k_1, kk20 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p1[0U]; - init_with_params(block_state.f3.snd, pv); + uint64_t tmp[8U] = { 0U }; + uint64_t *r0 = h; + uint64_t *r1 = h + 4U; + uint64_t *r2 = h + 8U; + uint64_t *r3 = h + 12U; + uint64_t iv0 = Hacl_Hash_Blake2b_ivTable_B[0U]; + uint64_t iv1 = Hacl_Hash_Blake2b_ivTable_B[1U]; + uint64_t iv2 = Hacl_Hash_Blake2b_ivTable_B[2U]; + uint64_t iv3 = Hacl_Hash_Blake2b_ivTable_B[3U]; + uint64_t iv4 = Hacl_Hash_Blake2b_ivTable_B[4U]; + uint64_t iv5 = Hacl_Hash_Blake2b_ivTable_B[5U]; + uint64_t iv6 = Hacl_Hash_Blake2b_ivTable_B[6U]; + uint64_t iv7 = Hacl_Hash_Blake2b_ivTable_B[7U]; + r2[0U] = iv0; + r2[1U] = iv1; + r2[2U] = iv2; + r2[3U] = iv3; + r3[0U] = iv4; + r3[1U] = iv5; + r3[2U] = iv6; + r3[3U] = iv7; + uint8_t kk2 = pv.key_length; + uint8_t nn1 = pv.digest_length; + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r4 = u; + uint64_t x = r4; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r4 = u; + uint64_t x = r4; + os[i0] = x;); + tmp[0U] = + (uint64_t)nn1 + ^ + ((uint64_t)kk2 + << 8U + ^ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U))); + tmp[1U] = pv.node_offset; + tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U; + tmp[3U] = 0ULL; + uint64_t tmp0 = tmp[0U]; + uint64_t tmp1 = tmp[1U]; + uint64_t tmp2 = tmp[2U]; + uint64_t tmp3 = tmp[3U]; + uint64_t tmp4 = tmp[4U]; + uint64_t tmp5 = tmp[5U]; + uint64_t tmp6 = tmp[6U]; + uint64_t tmp7 = tmp[7U]; + uint64_t iv0_ = iv0 ^ tmp0; + uint64_t iv1_ = iv1 ^ tmp1; + uint64_t iv2_ = iv2 ^ tmp2; + uint64_t iv3_ = iv3 ^ tmp3; + uint64_t iv4_ = iv4 ^ tmp4; + uint64_t iv5_ = iv5 ^ tmp5; + uint64_t iv6_ = iv6 ^ tmp6; + uint64_t iv7_ = iv7 ^ tmp7; + r0[0U] = iv0_; + r0[1U] = iv1_; + r0[2U] = iv2_; + r0[3U] = iv3_; + r1[0U] = iv4_; + r1[1U] = iv5_; + r1[2U] = iv6_; + r1[3U] = iv7_; return p; } @@ -918,16 +914,92 @@ static void reset_raw(Hacl_Hash_Blake2b_state_t *state, Hacl_Hash_Blake2b_params bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i1 = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; - uint32_t kk2 = (uint32_t)i1.key_length; + uint64_t *h = block_state.f3.snd; + uint32_t kk20 = (uint32_t)i1.key_length; uint8_t *k_1 = key.snd; - if (!(kk2 == 0U)) + if (!(kk20 == 0U)) { - uint8_t *sub_b = buf + kk2; - memset(sub_b, 0U, (128U - kk2) * sizeof (uint8_t)); - memcpy(buf, k_1, kk2 * sizeof (uint8_t)); + uint8_t *sub_b = buf + kk20; + memset(sub_b, 0U, (128U - kk20) * sizeof (uint8_t)); + memcpy(buf, k_1, kk20 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p[0U]; - init_with_params(block_state.f3.snd, pv); + uint64_t tmp[8U] = { 0U }; + uint64_t *r0 = h; + uint64_t *r1 = h + 4U; + uint64_t *r2 = h + 8U; + uint64_t *r3 = h + 12U; + uint64_t iv0 = Hacl_Hash_Blake2b_ivTable_B[0U]; + uint64_t iv1 = Hacl_Hash_Blake2b_ivTable_B[1U]; + uint64_t iv2 = Hacl_Hash_Blake2b_ivTable_B[2U]; + uint64_t iv3 = Hacl_Hash_Blake2b_ivTable_B[3U]; + uint64_t iv4 = Hacl_Hash_Blake2b_ivTable_B[4U]; + uint64_t iv5 = Hacl_Hash_Blake2b_ivTable_B[5U]; + uint64_t iv6 = Hacl_Hash_Blake2b_ivTable_B[6U]; + uint64_t iv7 = Hacl_Hash_Blake2b_ivTable_B[7U]; + r2[0U] = iv0; + r2[1U] = iv1; + r2[2U] = iv2; + r2[3U] = iv3; + r3[0U] = iv4; + r3[1U] = iv5; + r3[2U] = iv6; + r3[3U] = iv7; + uint8_t kk2 = pv.key_length; + uint8_t nn1 = pv.digest_length; + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r = u; + uint64_t x = r; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r = u; + uint64_t x = r; + os[i0] = x;); + tmp[0U] = + (uint64_t)nn1 + ^ + ((uint64_t)kk2 + << 8U + ^ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U))); + tmp[1U] = pv.node_offset; + tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U; + tmp[3U] = 0ULL; + uint64_t tmp0 = tmp[0U]; + uint64_t tmp1 = tmp[1U]; + uint64_t tmp2 = tmp[2U]; + uint64_t tmp3 = tmp[3U]; + uint64_t tmp4 = tmp[4U]; + uint64_t tmp5 = tmp[5U]; + uint64_t tmp6 = tmp[6U]; + uint64_t tmp7 = tmp[7U]; + uint64_t iv0_ = iv0 ^ tmp0; + uint64_t iv1_ = iv1 ^ tmp1; + uint64_t iv2_ = iv2 ^ tmp2; + uint64_t iv3_ = iv3 ^ tmp3; + uint64_t iv4_ = iv4 ^ tmp4; + uint64_t iv5_ = iv5 ^ tmp5; + uint64_t iv6_ = iv6 ^ tmp6; + uint64_t iv7_ = iv7 ^ tmp7; + r0[0U] = iv0_; + r0[1U] = iv1_; + r0[2U] = iv2_; + r0[3U] = iv3_; + r1[0U] = iv4_; + r1[1U] = iv5_; + r1[2U] = iv6_; + r1[3U] = iv7_; uint8_t kk11 = i.key_length; uint32_t ite; if (kk11 != 0U) @@ -939,8 +1011,8 @@ static void reset_raw(Hacl_Hash_Blake2b_state_t *state, Hacl_Hash_Blake2b_params ite = 0U; } Hacl_Hash_Blake2b_state_t - tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; - state[0U] = tmp; + tmp8 = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; + state[0U] = tmp8; } /** diff --git a/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c b/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c index 35608aea71a293..92b2e8f539041b 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c +++ b/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.c @@ -298,75 +298,6 @@ Hacl_Hash_Blake2b_Simd256_init(Lib_IntVector_Intrinsics_vec256 *hash, uint32_t k r1[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv4_, iv5_, iv6_, iv7_); } -static void -init_with_params(Lib_IntVector_Intrinsics_vec256 *hash, Hacl_Hash_Blake2b_blake2_params p) -{ - uint64_t tmp[8U] = { 0U }; - Lib_IntVector_Intrinsics_vec256 *r0 = hash; - Lib_IntVector_Intrinsics_vec256 *r1 = hash + 1U; - Lib_IntVector_Intrinsics_vec256 *r2 = hash + 2U; - Lib_IntVector_Intrinsics_vec256 *r3 = hash + 3U; - uint64_t iv0 = Hacl_Hash_Blake2b_ivTable_B[0U]; - uint64_t iv1 = Hacl_Hash_Blake2b_ivTable_B[1U]; - uint64_t iv2 = Hacl_Hash_Blake2b_ivTable_B[2U]; - uint64_t iv3 = Hacl_Hash_Blake2b_ivTable_B[3U]; - uint64_t iv4 = Hacl_Hash_Blake2b_ivTable_B[4U]; - uint64_t iv5 = Hacl_Hash_Blake2b_ivTable_B[5U]; - uint64_t iv6 = Hacl_Hash_Blake2b_ivTable_B[6U]; - uint64_t iv7 = Hacl_Hash_Blake2b_ivTable_B[7U]; - r2[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv0, iv1, iv2, iv3); - r3[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv4, iv5, iv6, iv7); - uint8_t kk = p.key_length; - uint8_t nn = p.digest_length; - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint64_t *os = tmp + 4U; - uint8_t *bj = p.salt + i * 8U; - uint64_t u = load64_le(bj); - uint64_t r = u; - uint64_t x = r; - os[i] = x;); - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint64_t *os = tmp + 6U; - uint8_t *bj = p.personal + i * 8U; - uint64_t u = load64_le(bj); - uint64_t r = u; - uint64_t x = r; - os[i] = x;); - tmp[0U] = - (uint64_t)nn - ^ - ((uint64_t)kk - << 8U - ^ ((uint64_t)p.fanout << 16U ^ ((uint64_t)p.depth << 24U ^ (uint64_t)p.leaf_length << 32U))); - tmp[1U] = p.node_offset; - tmp[2U] = (uint64_t)p.node_depth ^ (uint64_t)p.inner_length << 8U; - tmp[3U] = 0ULL; - uint64_t tmp0 = tmp[0U]; - uint64_t tmp1 = tmp[1U]; - uint64_t tmp2 = tmp[2U]; - uint64_t tmp3 = tmp[3U]; - uint64_t tmp4 = tmp[4U]; - uint64_t tmp5 = tmp[5U]; - uint64_t tmp6 = tmp[6U]; - uint64_t tmp7 = tmp[7U]; - uint64_t iv0_ = iv0 ^ tmp0; - uint64_t iv1_ = iv1 ^ tmp1; - uint64_t iv2_ = iv2 ^ tmp2; - uint64_t iv3_ = iv3 ^ tmp3; - uint64_t iv4_ = iv4 ^ tmp4; - uint64_t iv5_ = iv5 ^ tmp5; - uint64_t iv6_ = iv6 ^ tmp6; - uint64_t iv7_ = iv7 ^ tmp7; - r0[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv0_, iv1_, iv2_, iv3_); - r1[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv4_, iv5_, iv6_, iv7_); -} - static void update_key( Lib_IntVector_Intrinsics_vec256 *wv, @@ -647,16 +578,80 @@ static Hacl_Hash_Blake2b_Simd256_state_t uint8_t nn = p1->digest_length; bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; - uint32_t kk2 = (uint32_t)i.key_length; + Lib_IntVector_Intrinsics_vec256 *h = block_state.f3.snd; + uint32_t kk20 = (uint32_t)i.key_length; uint8_t *k_1 = key.snd; - if (!(kk2 == 0U)) + if (!(kk20 == 0U)) { - uint8_t *sub_b = buf + kk2; - memset(sub_b, 0U, (128U - kk2) * sizeof (uint8_t)); - memcpy(buf, k_1, kk2 * sizeof (uint8_t)); + uint8_t *sub_b = buf + kk20; + memset(sub_b, 0U, (128U - kk20) * sizeof (uint8_t)); + memcpy(buf, k_1, kk20 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p1[0U]; - init_with_params(block_state.f3.snd, pv); + uint64_t tmp[8U] = { 0U }; + Lib_IntVector_Intrinsics_vec256 *r0 = h; + Lib_IntVector_Intrinsics_vec256 *r1 = h + 1U; + Lib_IntVector_Intrinsics_vec256 *r2 = h + 2U; + Lib_IntVector_Intrinsics_vec256 *r3 = h + 3U; + uint64_t iv0 = Hacl_Hash_Blake2b_ivTable_B[0U]; + uint64_t iv1 = Hacl_Hash_Blake2b_ivTable_B[1U]; + uint64_t iv2 = Hacl_Hash_Blake2b_ivTable_B[2U]; + uint64_t iv3 = Hacl_Hash_Blake2b_ivTable_B[3U]; + uint64_t iv4 = Hacl_Hash_Blake2b_ivTable_B[4U]; + uint64_t iv5 = Hacl_Hash_Blake2b_ivTable_B[5U]; + uint64_t iv6 = Hacl_Hash_Blake2b_ivTable_B[6U]; + uint64_t iv7 = Hacl_Hash_Blake2b_ivTable_B[7U]; + r2[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv0, iv1, iv2, iv3); + r3[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv4, iv5, iv6, iv7); + uint8_t kk2 = pv.key_length; + uint8_t nn1 = pv.digest_length; + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r4 = u; + uint64_t x = r4; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r4 = u; + uint64_t x = r4; + os[i0] = x;); + tmp[0U] = + (uint64_t)nn1 + ^ + ((uint64_t)kk2 + << 8U + ^ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U))); + tmp[1U] = pv.node_offset; + tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U; + tmp[3U] = 0ULL; + uint64_t tmp0 = tmp[0U]; + uint64_t tmp1 = tmp[1U]; + uint64_t tmp2 = tmp[2U]; + uint64_t tmp3 = tmp[3U]; + uint64_t tmp4 = tmp[4U]; + uint64_t tmp5 = tmp[5U]; + uint64_t tmp6 = tmp[6U]; + uint64_t tmp7 = tmp[7U]; + uint64_t iv0_ = iv0 ^ tmp0; + uint64_t iv1_ = iv1 ^ tmp1; + uint64_t iv2_ = iv2 ^ tmp2; + uint64_t iv3_ = iv3 ^ tmp3; + uint64_t iv4_ = iv4 ^ tmp4; + uint64_t iv5_ = iv5 ^ tmp5; + uint64_t iv6_ = iv6 ^ tmp6; + uint64_t iv7_ = iv7 ^ tmp7; + r0[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv0_, iv1_, iv2_, iv3_); + r1[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv4_, iv5_, iv6_, iv7_); return p; } @@ -757,16 +752,80 @@ reset_raw(Hacl_Hash_Blake2b_Simd256_state_t *state, Hacl_Hash_Blake2b_params_and bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i1 = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; - uint32_t kk2 = (uint32_t)i1.key_length; + Lib_IntVector_Intrinsics_vec256 *h = block_state.f3.snd; + uint32_t kk20 = (uint32_t)i1.key_length; uint8_t *k_1 = key.snd; - if (!(kk2 == 0U)) + if (!(kk20 == 0U)) { - uint8_t *sub_b = buf + kk2; - memset(sub_b, 0U, (128U - kk2) * sizeof (uint8_t)); - memcpy(buf, k_1, kk2 * sizeof (uint8_t)); + uint8_t *sub_b = buf + kk20; + memset(sub_b, 0U, (128U - kk20) * sizeof (uint8_t)); + memcpy(buf, k_1, kk20 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p[0U]; - init_with_params(block_state.f3.snd, pv); + uint64_t tmp[8U] = { 0U }; + Lib_IntVector_Intrinsics_vec256 *r0 = h; + Lib_IntVector_Intrinsics_vec256 *r1 = h + 1U; + Lib_IntVector_Intrinsics_vec256 *r2 = h + 2U; + Lib_IntVector_Intrinsics_vec256 *r3 = h + 3U; + uint64_t iv0 = Hacl_Hash_Blake2b_ivTable_B[0U]; + uint64_t iv1 = Hacl_Hash_Blake2b_ivTable_B[1U]; + uint64_t iv2 = Hacl_Hash_Blake2b_ivTable_B[2U]; + uint64_t iv3 = Hacl_Hash_Blake2b_ivTable_B[3U]; + uint64_t iv4 = Hacl_Hash_Blake2b_ivTable_B[4U]; + uint64_t iv5 = Hacl_Hash_Blake2b_ivTable_B[5U]; + uint64_t iv6 = Hacl_Hash_Blake2b_ivTable_B[6U]; + uint64_t iv7 = Hacl_Hash_Blake2b_ivTable_B[7U]; + r2[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv0, iv1, iv2, iv3); + r3[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv4, iv5, iv6, iv7); + uint8_t kk2 = pv.key_length; + uint8_t nn1 = pv.digest_length; + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r = u; + uint64_t x = r; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint64_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 8U; + uint64_t u = load64_le(bj); + uint64_t r = u; + uint64_t x = r; + os[i0] = x;); + tmp[0U] = + (uint64_t)nn1 + ^ + ((uint64_t)kk2 + << 8U + ^ ((uint64_t)pv.fanout << 16U ^ ((uint64_t)pv.depth << 24U ^ (uint64_t)pv.leaf_length << 32U))); + tmp[1U] = pv.node_offset; + tmp[2U] = (uint64_t)pv.node_depth ^ (uint64_t)pv.inner_length << 8U; + tmp[3U] = 0ULL; + uint64_t tmp0 = tmp[0U]; + uint64_t tmp1 = tmp[1U]; + uint64_t tmp2 = tmp[2U]; + uint64_t tmp3 = tmp[3U]; + uint64_t tmp4 = tmp[4U]; + uint64_t tmp5 = tmp[5U]; + uint64_t tmp6 = tmp[6U]; + uint64_t tmp7 = tmp[7U]; + uint64_t iv0_ = iv0 ^ tmp0; + uint64_t iv1_ = iv1 ^ tmp1; + uint64_t iv2_ = iv2 ^ tmp2; + uint64_t iv3_ = iv3 ^ tmp3; + uint64_t iv4_ = iv4 ^ tmp4; + uint64_t iv5_ = iv5 ^ tmp5; + uint64_t iv6_ = iv6 ^ tmp6; + uint64_t iv7_ = iv7 ^ tmp7; + r0[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv0_, iv1_, iv2_, iv3_); + r1[0U] = Lib_IntVector_Intrinsics_vec256_load64s(iv4_, iv5_, iv6_, iv7_); uint8_t kk11 = i.key_length; uint32_t ite; if (kk11 != 0U) @@ -778,8 +837,8 @@ reset_raw(Hacl_Hash_Blake2b_Simd256_state_t *state, Hacl_Hash_Blake2b_params_and ite = 0U; } Hacl_Hash_Blake2b_Simd256_state_t - tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; - state[0U] = tmp; + tmp8 = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; + state[0U] = tmp8; } /** diff --git a/Modules/_hacl/Hacl_Hash_Blake2s.c b/Modules/_hacl/Hacl_Hash_Blake2s.c index 167f38fbd1c603..e5e0ecd0bfde7e 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2s.c +++ b/Modules/_hacl/Hacl_Hash_Blake2s.c @@ -573,83 +573,6 @@ void Hacl_Hash_Blake2s_init(uint32_t *hash, uint32_t kk, uint32_t nn) r1[3U] = iv7_; } -static void init_with_params(uint32_t *hash, Hacl_Hash_Blake2b_blake2_params p) -{ - uint32_t tmp[8U] = { 0U }; - uint32_t *r0 = hash; - uint32_t *r1 = hash + 4U; - uint32_t *r2 = hash + 8U; - uint32_t *r3 = hash + 12U; - uint32_t iv0 = Hacl_Hash_Blake2b_ivTable_S[0U]; - uint32_t iv1 = Hacl_Hash_Blake2b_ivTable_S[1U]; - uint32_t iv2 = Hacl_Hash_Blake2b_ivTable_S[2U]; - uint32_t iv3 = Hacl_Hash_Blake2b_ivTable_S[3U]; - uint32_t iv4 = Hacl_Hash_Blake2b_ivTable_S[4U]; - uint32_t iv5 = Hacl_Hash_Blake2b_ivTable_S[5U]; - uint32_t iv6 = Hacl_Hash_Blake2b_ivTable_S[6U]; - uint32_t iv7 = Hacl_Hash_Blake2b_ivTable_S[7U]; - r2[0U] = iv0; - r2[1U] = iv1; - r2[2U] = iv2; - r2[3U] = iv3; - r3[0U] = iv4; - r3[1U] = iv5; - r3[2U] = iv6; - r3[3U] = iv7; - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint32_t *os = tmp + 4U; - uint8_t *bj = p.salt + i * 4U; - uint32_t u = load32_le(bj); - uint32_t r = u; - uint32_t x = r; - os[i] = x;); - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint32_t *os = tmp + 6U; - uint8_t *bj = p.personal + i * 4U; - uint32_t u = load32_le(bj); - uint32_t r = u; - uint32_t x = r; - os[i] = x;); - tmp[0U] = - (uint32_t)p.digest_length - ^ ((uint32_t)p.key_length << 8U ^ ((uint32_t)p.fanout << 16U ^ (uint32_t)p.depth << 24U)); - tmp[1U] = p.leaf_length; - tmp[2U] = (uint32_t)p.node_offset; - tmp[3U] = - (uint32_t)(p.node_offset >> 32U) - ^ ((uint32_t)p.node_depth << 16U ^ (uint32_t)p.inner_length << 24U); - uint32_t tmp0 = tmp[0U]; - uint32_t tmp1 = tmp[1U]; - uint32_t tmp2 = tmp[2U]; - uint32_t tmp3 = tmp[3U]; - uint32_t tmp4 = tmp[4U]; - uint32_t tmp5 = tmp[5U]; - uint32_t tmp6 = tmp[6U]; - uint32_t tmp7 = tmp[7U]; - uint32_t iv0_ = iv0 ^ tmp0; - uint32_t iv1_ = iv1 ^ tmp1; - uint32_t iv2_ = iv2 ^ tmp2; - uint32_t iv3_ = iv3 ^ tmp3; - uint32_t iv4_ = iv4 ^ tmp4; - uint32_t iv5_ = iv5 ^ tmp5; - uint32_t iv6_ = iv6 ^ tmp6; - uint32_t iv7_ = iv7 ^ tmp7; - r0[0U] = iv0_; - r0[1U] = iv1_; - r0[2U] = iv2_; - r0[3U] = iv3_; - r1[0U] = iv4_; - r1[1U] = iv5_; - r1[2U] = iv6_; - r1[3U] = iv7_; -} - static void update_key(uint32_t *wv, uint32_t *hash, uint32_t kk, uint8_t *k, uint32_t ll) { uint64_t lb = (uint64_t)64U; @@ -796,6 +719,7 @@ static Hacl_Hash_Blake2s_state_t uint8_t nn = p1->digest_length; bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; + uint32_t *h = block_state.f3.snd; uint32_t kk2 = (uint32_t)i.key_length; uint8_t *k_1 = key.snd; if (!(kk2 == 0U)) @@ -805,7 +729,79 @@ static Hacl_Hash_Blake2s_state_t memcpy(buf, k_1, kk2 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p1[0U]; - init_with_params(block_state.f3.snd, pv); + uint32_t tmp[8U] = { 0U }; + uint32_t *r0 = h; + uint32_t *r1 = h + 4U; + uint32_t *r2 = h + 8U; + uint32_t *r3 = h + 12U; + uint32_t iv0 = Hacl_Hash_Blake2b_ivTable_S[0U]; + uint32_t iv1 = Hacl_Hash_Blake2b_ivTable_S[1U]; + uint32_t iv2 = Hacl_Hash_Blake2b_ivTable_S[2U]; + uint32_t iv3 = Hacl_Hash_Blake2b_ivTable_S[3U]; + uint32_t iv4 = Hacl_Hash_Blake2b_ivTable_S[4U]; + uint32_t iv5 = Hacl_Hash_Blake2b_ivTable_S[5U]; + uint32_t iv6 = Hacl_Hash_Blake2b_ivTable_S[6U]; + uint32_t iv7 = Hacl_Hash_Blake2b_ivTable_S[7U]; + r2[0U] = iv0; + r2[1U] = iv1; + r2[2U] = iv2; + r2[3U] = iv3; + r3[0U] = iv4; + r3[1U] = iv5; + r3[2U] = iv6; + r3[3U] = iv7; + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r4 = u; + uint32_t x = r4; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r4 = u; + uint32_t x = r4; + os[i0] = x;); + tmp[0U] = + (uint32_t)pv.digest_length + ^ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U)); + tmp[1U] = pv.leaf_length; + tmp[2U] = (uint32_t)pv.node_offset; + tmp[3U] = + (uint32_t)(pv.node_offset >> 32U) + ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U); + uint32_t tmp0 = tmp[0U]; + uint32_t tmp1 = tmp[1U]; + uint32_t tmp2 = tmp[2U]; + uint32_t tmp3 = tmp[3U]; + uint32_t tmp4 = tmp[4U]; + uint32_t tmp5 = tmp[5U]; + uint32_t tmp6 = tmp[6U]; + uint32_t tmp7 = tmp[7U]; + uint32_t iv0_ = iv0 ^ tmp0; + uint32_t iv1_ = iv1 ^ tmp1; + uint32_t iv2_ = iv2 ^ tmp2; + uint32_t iv3_ = iv3 ^ tmp3; + uint32_t iv4_ = iv4 ^ tmp4; + uint32_t iv5_ = iv5 ^ tmp5; + uint32_t iv6_ = iv6 ^ tmp6; + uint32_t iv7_ = iv7 ^ tmp7; + r0[0U] = iv0_; + r0[1U] = iv1_; + r0[2U] = iv2_; + r0[3U] = iv3_; + r1[0U] = iv4_; + r1[1U] = iv5_; + r1[2U] = iv6_; + r1[3U] = iv7_; return p; } @@ -903,6 +899,7 @@ static void reset_raw(Hacl_Hash_Blake2s_state_t *state, Hacl_Hash_Blake2b_params bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i1 = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; + uint32_t *h = block_state.f3.snd; uint32_t kk2 = (uint32_t)i1.key_length; uint8_t *k_1 = key.snd; if (!(kk2 == 0U)) @@ -912,7 +909,79 @@ static void reset_raw(Hacl_Hash_Blake2s_state_t *state, Hacl_Hash_Blake2b_params memcpy(buf, k_1, kk2 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p[0U]; - init_with_params(block_state.f3.snd, pv); + uint32_t tmp[8U] = { 0U }; + uint32_t *r0 = h; + uint32_t *r1 = h + 4U; + uint32_t *r2 = h + 8U; + uint32_t *r3 = h + 12U; + uint32_t iv0 = Hacl_Hash_Blake2b_ivTable_S[0U]; + uint32_t iv1 = Hacl_Hash_Blake2b_ivTable_S[1U]; + uint32_t iv2 = Hacl_Hash_Blake2b_ivTable_S[2U]; + uint32_t iv3 = Hacl_Hash_Blake2b_ivTable_S[3U]; + uint32_t iv4 = Hacl_Hash_Blake2b_ivTable_S[4U]; + uint32_t iv5 = Hacl_Hash_Blake2b_ivTable_S[5U]; + uint32_t iv6 = Hacl_Hash_Blake2b_ivTable_S[6U]; + uint32_t iv7 = Hacl_Hash_Blake2b_ivTable_S[7U]; + r2[0U] = iv0; + r2[1U] = iv1; + r2[2U] = iv2; + r2[3U] = iv3; + r3[0U] = iv4; + r3[1U] = iv5; + r3[2U] = iv6; + r3[3U] = iv7; + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r = u; + uint32_t x = r; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r = u; + uint32_t x = r; + os[i0] = x;); + tmp[0U] = + (uint32_t)pv.digest_length + ^ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U)); + tmp[1U] = pv.leaf_length; + tmp[2U] = (uint32_t)pv.node_offset; + tmp[3U] = + (uint32_t)(pv.node_offset >> 32U) + ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U); + uint32_t tmp0 = tmp[0U]; + uint32_t tmp1 = tmp[1U]; + uint32_t tmp2 = tmp[2U]; + uint32_t tmp3 = tmp[3U]; + uint32_t tmp4 = tmp[4U]; + uint32_t tmp5 = tmp[5U]; + uint32_t tmp6 = tmp[6U]; + uint32_t tmp7 = tmp[7U]; + uint32_t iv0_ = iv0 ^ tmp0; + uint32_t iv1_ = iv1 ^ tmp1; + uint32_t iv2_ = iv2 ^ tmp2; + uint32_t iv3_ = iv3 ^ tmp3; + uint32_t iv4_ = iv4 ^ tmp4; + uint32_t iv5_ = iv5 ^ tmp5; + uint32_t iv6_ = iv6 ^ tmp6; + uint32_t iv7_ = iv7 ^ tmp7; + r0[0U] = iv0_; + r0[1U] = iv1_; + r0[2U] = iv2_; + r0[3U] = iv3_; + r1[0U] = iv4_; + r1[1U] = iv5_; + r1[2U] = iv6_; + r1[3U] = iv7_; uint8_t kk11 = i.key_length; uint32_t ite; if (kk11 != 0U) @@ -924,8 +993,8 @@ static void reset_raw(Hacl_Hash_Blake2s_state_t *state, Hacl_Hash_Blake2b_params ite = 0U; } Hacl_Hash_Blake2s_state_t - tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; - state[0U] = tmp; + tmp8 = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; + state[0U] = tmp8; } /** diff --git a/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c b/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c index a85b18a4d296ec..f675a7f14f192f 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c +++ b/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.c @@ -295,72 +295,6 @@ Hacl_Hash_Blake2s_Simd128_init(Lib_IntVector_Intrinsics_vec128 *hash, uint32_t k r1[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv4_, iv5_, iv6_, iv7_); } -static void -init_with_params(Lib_IntVector_Intrinsics_vec128 *hash, Hacl_Hash_Blake2b_blake2_params p) -{ - uint32_t tmp[8U] = { 0U }; - Lib_IntVector_Intrinsics_vec128 *r0 = hash; - Lib_IntVector_Intrinsics_vec128 *r1 = hash + 1U; - Lib_IntVector_Intrinsics_vec128 *r2 = hash + 2U; - Lib_IntVector_Intrinsics_vec128 *r3 = hash + 3U; - uint32_t iv0 = Hacl_Hash_Blake2b_ivTable_S[0U]; - uint32_t iv1 = Hacl_Hash_Blake2b_ivTable_S[1U]; - uint32_t iv2 = Hacl_Hash_Blake2b_ivTable_S[2U]; - uint32_t iv3 = Hacl_Hash_Blake2b_ivTable_S[3U]; - uint32_t iv4 = Hacl_Hash_Blake2b_ivTable_S[4U]; - uint32_t iv5 = Hacl_Hash_Blake2b_ivTable_S[5U]; - uint32_t iv6 = Hacl_Hash_Blake2b_ivTable_S[6U]; - uint32_t iv7 = Hacl_Hash_Blake2b_ivTable_S[7U]; - r2[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv0, iv1, iv2, iv3); - r3[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv4, iv5, iv6, iv7); - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint32_t *os = tmp + 4U; - uint8_t *bj = p.salt + i * 4U; - uint32_t u = load32_le(bj); - uint32_t r = u; - uint32_t x = r; - os[i] = x;); - KRML_MAYBE_FOR2(i, - 0U, - 2U, - 1U, - uint32_t *os = tmp + 6U; - uint8_t *bj = p.personal + i * 4U; - uint32_t u = load32_le(bj); - uint32_t r = u; - uint32_t x = r; - os[i] = x;); - tmp[0U] = - (uint32_t)p.digest_length - ^ ((uint32_t)p.key_length << 8U ^ ((uint32_t)p.fanout << 16U ^ (uint32_t)p.depth << 24U)); - tmp[1U] = p.leaf_length; - tmp[2U] = (uint32_t)p.node_offset; - tmp[3U] = - (uint32_t)(p.node_offset >> 32U) - ^ ((uint32_t)p.node_depth << 16U ^ (uint32_t)p.inner_length << 24U); - uint32_t tmp0 = tmp[0U]; - uint32_t tmp1 = tmp[1U]; - uint32_t tmp2 = tmp[2U]; - uint32_t tmp3 = tmp[3U]; - uint32_t tmp4 = tmp[4U]; - uint32_t tmp5 = tmp[5U]; - uint32_t tmp6 = tmp[6U]; - uint32_t tmp7 = tmp[7U]; - uint32_t iv0_ = iv0 ^ tmp0; - uint32_t iv1_ = iv1 ^ tmp1; - uint32_t iv2_ = iv2 ^ tmp2; - uint32_t iv3_ = iv3 ^ tmp3; - uint32_t iv4_ = iv4 ^ tmp4; - uint32_t iv5_ = iv5 ^ tmp5; - uint32_t iv6_ = iv6 ^ tmp6; - uint32_t iv7_ = iv7 ^ tmp7; - r0[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv0_, iv1_, iv2_, iv3_); - r1[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv4_, iv5_, iv6_, iv7_); -} - static void update_key( Lib_IntVector_Intrinsics_vec128 *wv, @@ -637,6 +571,7 @@ static Hacl_Hash_Blake2s_Simd128_state_t uint8_t nn = p1->digest_length; bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; + Lib_IntVector_Intrinsics_vec128 *h = block_state.f3.snd; uint32_t kk2 = (uint32_t)i.key_length; uint8_t *k_1 = key.snd; if (!(kk2 == 0U)) @@ -646,7 +581,67 @@ static Hacl_Hash_Blake2s_Simd128_state_t memcpy(buf, k_1, kk2 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p1[0U]; - init_with_params(block_state.f3.snd, pv); + uint32_t tmp[8U] = { 0U }; + Lib_IntVector_Intrinsics_vec128 *r0 = h; + Lib_IntVector_Intrinsics_vec128 *r1 = h + 1U; + Lib_IntVector_Intrinsics_vec128 *r2 = h + 2U; + Lib_IntVector_Intrinsics_vec128 *r3 = h + 3U; + uint32_t iv0 = Hacl_Hash_Blake2b_ivTable_S[0U]; + uint32_t iv1 = Hacl_Hash_Blake2b_ivTable_S[1U]; + uint32_t iv2 = Hacl_Hash_Blake2b_ivTable_S[2U]; + uint32_t iv3 = Hacl_Hash_Blake2b_ivTable_S[3U]; + uint32_t iv4 = Hacl_Hash_Blake2b_ivTable_S[4U]; + uint32_t iv5 = Hacl_Hash_Blake2b_ivTable_S[5U]; + uint32_t iv6 = Hacl_Hash_Blake2b_ivTable_S[6U]; + uint32_t iv7 = Hacl_Hash_Blake2b_ivTable_S[7U]; + r2[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv0, iv1, iv2, iv3); + r3[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv4, iv5, iv6, iv7); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r4 = u; + uint32_t x = r4; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r4 = u; + uint32_t x = r4; + os[i0] = x;); + tmp[0U] = + (uint32_t)pv.digest_length + ^ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U)); + tmp[1U] = pv.leaf_length; + tmp[2U] = (uint32_t)pv.node_offset; + tmp[3U] = + (uint32_t)(pv.node_offset >> 32U) + ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U); + uint32_t tmp0 = tmp[0U]; + uint32_t tmp1 = tmp[1U]; + uint32_t tmp2 = tmp[2U]; + uint32_t tmp3 = tmp[3U]; + uint32_t tmp4 = tmp[4U]; + uint32_t tmp5 = tmp[5U]; + uint32_t tmp6 = tmp[6U]; + uint32_t tmp7 = tmp[7U]; + uint32_t iv0_ = iv0 ^ tmp0; + uint32_t iv1_ = iv1 ^ tmp1; + uint32_t iv2_ = iv2 ^ tmp2; + uint32_t iv3_ = iv3 ^ tmp3; + uint32_t iv4_ = iv4 ^ tmp4; + uint32_t iv5_ = iv5 ^ tmp5; + uint32_t iv6_ = iv6 ^ tmp6; + uint32_t iv7_ = iv7 ^ tmp7; + r0[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv0_, iv1_, iv2_, iv3_); + r1[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv4_, iv5_, iv6_, iv7_); return p; } @@ -747,6 +742,7 @@ reset_raw(Hacl_Hash_Blake2s_Simd128_state_t *state, Hacl_Hash_Blake2b_params_and bool last_node = block_state.thd; Hacl_Hash_Blake2b_index i1 = { .key_length = kk1, .digest_length = nn, .last_node = last_node }; + Lib_IntVector_Intrinsics_vec128 *h = block_state.f3.snd; uint32_t kk2 = (uint32_t)i1.key_length; uint8_t *k_1 = key.snd; if (!(kk2 == 0U)) @@ -756,7 +752,67 @@ reset_raw(Hacl_Hash_Blake2s_Simd128_state_t *state, Hacl_Hash_Blake2b_params_and memcpy(buf, k_1, kk2 * sizeof (uint8_t)); } Hacl_Hash_Blake2b_blake2_params pv = p[0U]; - init_with_params(block_state.f3.snd, pv); + uint32_t tmp[8U] = { 0U }; + Lib_IntVector_Intrinsics_vec128 *r0 = h; + Lib_IntVector_Intrinsics_vec128 *r1 = h + 1U; + Lib_IntVector_Intrinsics_vec128 *r2 = h + 2U; + Lib_IntVector_Intrinsics_vec128 *r3 = h + 3U; + uint32_t iv0 = Hacl_Hash_Blake2b_ivTable_S[0U]; + uint32_t iv1 = Hacl_Hash_Blake2b_ivTable_S[1U]; + uint32_t iv2 = Hacl_Hash_Blake2b_ivTable_S[2U]; + uint32_t iv3 = Hacl_Hash_Blake2b_ivTable_S[3U]; + uint32_t iv4 = Hacl_Hash_Blake2b_ivTable_S[4U]; + uint32_t iv5 = Hacl_Hash_Blake2b_ivTable_S[5U]; + uint32_t iv6 = Hacl_Hash_Blake2b_ivTable_S[6U]; + uint32_t iv7 = Hacl_Hash_Blake2b_ivTable_S[7U]; + r2[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv0, iv1, iv2, iv3); + r3[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv4, iv5, iv6, iv7); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 4U; + uint8_t *bj = pv.salt + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r = u; + uint32_t x = r; + os[i0] = x;); + KRML_MAYBE_FOR2(i0, + 0U, + 2U, + 1U, + uint32_t *os = tmp + 6U; + uint8_t *bj = pv.personal + i0 * 4U; + uint32_t u = load32_le(bj); + uint32_t r = u; + uint32_t x = r; + os[i0] = x;); + tmp[0U] = + (uint32_t)pv.digest_length + ^ ((uint32_t)pv.key_length << 8U ^ ((uint32_t)pv.fanout << 16U ^ (uint32_t)pv.depth << 24U)); + tmp[1U] = pv.leaf_length; + tmp[2U] = (uint32_t)pv.node_offset; + tmp[3U] = + (uint32_t)(pv.node_offset >> 32U) + ^ ((uint32_t)pv.node_depth << 16U ^ (uint32_t)pv.inner_length << 24U); + uint32_t tmp0 = tmp[0U]; + uint32_t tmp1 = tmp[1U]; + uint32_t tmp2 = tmp[2U]; + uint32_t tmp3 = tmp[3U]; + uint32_t tmp4 = tmp[4U]; + uint32_t tmp5 = tmp[5U]; + uint32_t tmp6 = tmp[6U]; + uint32_t tmp7 = tmp[7U]; + uint32_t iv0_ = iv0 ^ tmp0; + uint32_t iv1_ = iv1 ^ tmp1; + uint32_t iv2_ = iv2 ^ tmp2; + uint32_t iv3_ = iv3 ^ tmp3; + uint32_t iv4_ = iv4 ^ tmp4; + uint32_t iv5_ = iv5 ^ tmp5; + uint32_t iv6_ = iv6 ^ tmp6; + uint32_t iv7_ = iv7 ^ tmp7; + r0[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv0_, iv1_, iv2_, iv3_); + r1[0U] = Lib_IntVector_Intrinsics_vec128_load32s(iv4_, iv5_, iv6_, iv7_); uint8_t kk11 = i.key_length; uint32_t ite; if (kk11 != 0U) @@ -768,8 +824,8 @@ reset_raw(Hacl_Hash_Blake2s_Simd128_state_t *state, Hacl_Hash_Blake2b_params_and ite = 0U; } Hacl_Hash_Blake2s_Simd128_state_t - tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; - state[0U] = tmp; + tmp8 = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)ite }; + state[0U] = tmp8; } /** diff --git a/Modules/_hacl/include/krml/FStar_UInt128_Verified.h b/Modules/_hacl/include/krml/FStar_UInt128_Verified.h index bdf25898f2bc25..659745b24265cb 100644 --- a/Modules/_hacl/include/krml/FStar_UInt128_Verified.h +++ b/Modules/_hacl/include/krml/FStar_UInt128_Verified.h @@ -1,6 +1,6 @@ /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. - Licensed under the Apache 2.0 License. + Licensed under the Apache 2.0 and MIT Licenses. */ diff --git a/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h b/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h index 1bdec972a2f249..68bac0b3f0aab1 100644 --- a/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h +++ b/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h @@ -1,6 +1,6 @@ /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. - Licensed under the Apache 2.0 License. + Licensed under the Apache 2.0 and MIT Licenses. */ diff --git a/Modules/_hacl/include/krml/fstar_uint128_struct_endianness.h b/Modules/_hacl/include/krml/fstar_uint128_struct_endianness.h index e2b6d62859a5f1..bb736add318aa8 100644 --- a/Modules/_hacl/include/krml/fstar_uint128_struct_endianness.h +++ b/Modules/_hacl/include/krml/fstar_uint128_struct_endianness.h @@ -1,5 +1,5 @@ /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. - Licensed under the Apache 2.0 License. */ + Licensed under the Apache 2.0 and MIT Licenses. */ #ifndef FSTAR_UINT128_STRUCT_ENDIANNESS_H #define FSTAR_UINT128_STRUCT_ENDIANNESS_H diff --git a/Modules/_hacl/include/krml/internal/target.h b/Modules/_hacl/include/krml/internal/target.h index 292adc1423553f..fd74d3da684567 100644 --- a/Modules/_hacl/include/krml/internal/target.h +++ b/Modules/_hacl/include/krml/internal/target.h @@ -1,5 +1,5 @@ /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. - Licensed under the Apache 2.0 License. */ + Licensed under the Apache 2.0 and MIT Licenses. */ #ifndef __KRML_TARGET_H #define __KRML_TARGET_H @@ -82,6 +82,8 @@ # define KRML_NOINLINE __declspec(noinline) # elif defined (__GNUC__) # define KRML_NOINLINE __attribute__((noinline,unused)) +# elif defined (__SUNPRO_C) +# define KRML_NOINLINE __attribute__((noinline)) # else # define KRML_NOINLINE # warning "The KRML_NOINLINE macro is not defined for this toolchain!" @@ -95,6 +97,8 @@ # define KRML_MUSTINLINE inline __forceinline # elif defined (__GNUC__) # define KRML_MUSTINLINE inline __attribute__((always_inline)) +# elif defined (__SUNPRO_C) +# define KRML_MUSTINLINE inline __attribute__((always_inline)) # else # define KRML_MUSTINLINE inline # warning "The KRML_MUSTINLINE macro defaults to plain inline for this toolchain!" diff --git a/Modules/_hacl/include/krml/lowstar_endianness.h b/Modules/_hacl/include/krml/lowstar_endianness.h index 1aa2ccd644c06f..af6b882cf259cc 100644 --- a/Modules/_hacl/include/krml/lowstar_endianness.h +++ b/Modules/_hacl/include/krml/lowstar_endianness.h @@ -1,5 +1,5 @@ /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. - Licensed under the Apache 2.0 License. */ + Licensed under the Apache 2.0 and MIT Licenses. */ #ifndef __LOWSTAR_ENDIANNESS_H #define __LOWSTAR_ENDIANNESS_H diff --git a/Modules/_hacl/libintvector.h b/Modules/_hacl/libintvector.h index 99d11336942064..11e914f7e1650a 100644 --- a/Modules/_hacl/libintvector.h +++ b/Modules/_hacl/libintvector.h @@ -19,7 +19,7 @@ #define Lib_IntVector_Intrinsics_bit_mask64(x) -((x) & 1) -#if defined(__x86_64__) || defined(_M_X64) +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) #if defined(HACL_CAN_COMPILE_VEC128) diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh index 44e18a15f9652a..6234fea9f17bc7 100755 --- a/Modules/_hacl/refresh.sh +++ b/Modules/_hacl/refresh.sh @@ -22,7 +22,7 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. -expected_hacl_star_rev=a6a09496d9cff652b567d26f2c3ab012321b632a +expected_hacl_star_rev=315a9e491d2bc347b9dae99e0ea506995ea84d9d hacl_dir="$(realpath "$1")" cd "$(dirname "$0")" From c124577ebe915a00de4033c0f7fa7c47621d79e0 Mon Sep 17 00:00:00 2001 From: Wulian Date: Thu, 17 Oct 2024 23:23:37 +0800 Subject: [PATCH 218/247] gh-123370: Fix the canvas not clearing after running turtledemo.clock (#123457) Rewriting the day and date every tick somehow prevented them from being removed either by clicking STOP or loading another example. The solution is to rewrite them only when they change. --- Lib/turtledemo/clock.py | 33 +++++++++++-------- ...-08-28-19-27-35.gh-issue-123370.SPZ9Ux.rst | 1 + 2 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-08-28-19-27-35.gh-issue-123370.SPZ9Ux.rst diff --git a/Lib/turtledemo/clock.py b/Lib/turtledemo/clock.py index fd3b3992d466bf..8a630e29b8da50 100644 --- a/Lib/turtledemo/clock.py +++ b/Lib/turtledemo/clock.py @@ -1,7 +1,6 @@ -# -*- coding: cp1252 -*- """ turtle-example-suite: - tdemo_clock.py + turtledemo/clock.py Enhanced clock-program, showing date and time @@ -12,6 +11,9 @@ from turtle import * from datetime import datetime +dtfont = "TkFixedFont", 14, "bold" +current_day = None + def jump(distanz, winkel=0): penup() right(winkel) @@ -52,11 +54,23 @@ def clockface(radius): jump(-radius) rt(6) +def display_date_time(): + global current_day + writer.clear() + now = datetime.now() + current_day = now.day + writer.home() + writer.forward(distance=65) + writer.write(wochentag(now), align="center", font=dtfont) + writer.back(distance=150) + writer.write(datum(now), align="center", font=dtfont) + writer.forward(distance=85) + def setup(): global second_hand, minute_hand, hour_hand, writer mode("logo") make_hand_shape("second_hand", 125, 25) - make_hand_shape("minute_hand", 130, 25) + make_hand_shape("minute_hand", 115, 25) make_hand_shape("hour_hand", 90, 25) clockface(160) second_hand = Turtle() @@ -74,10 +88,10 @@ def setup(): hand.speed(0) ht() writer = Turtle() - #writer.mode("logo") writer.ht() writer.pu() writer.bk(85) + display_date_time() def wochentag(t): wochentag = ["Monday", "Tuesday", "Wednesday", @@ -99,18 +113,11 @@ def tick(): stunde = t.hour + minute/60.0 try: tracer(False) # Terminator can occur here - writer.clear() - writer.home() - writer.forward(65) - writer.write(wochentag(t), - align="center", font=("Courier", 14, "bold")) - writer.back(150) - writer.write(datum(t), - align="center", font=("Courier", 14, "bold")) - writer.forward(85) second_hand.setheading(6*sekunde) # or here minute_hand.setheading(6*minute) hour_hand.setheading(30*stunde) + if t.day != current_day: + display_date_time() tracer(True) ontimer(tick, 100) except Terminator: diff --git a/Misc/NEWS.d/next/Library/2024-08-28-19-27-35.gh-issue-123370.SPZ9Ux.rst b/Misc/NEWS.d/next/Library/2024-08-28-19-27-35.gh-issue-123370.SPZ9Ux.rst new file mode 100644 index 00000000000000..1fd5cc54eaf3e7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-28-19-27-35.gh-issue-123370.SPZ9Ux.rst @@ -0,0 +1 @@ +Fix the canvas not clearing after running turtledemo clock. From 0cb20f2e7e867d5c34fc17dd5b8e51e8b0020bb3 Mon Sep 17 00:00:00 2001 From: Wulian Date: Thu, 17 Oct 2024 23:40:30 +0800 Subject: [PATCH 219/247] gh-125625: Check for `py -3.13` in PCbuild/find_python.bat (GH-125626) --- PCbuild/find_python.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat index 6db579fa8de08a..d65d080ca71a90 100644 --- a/PCbuild/find_python.bat +++ b/PCbuild/find_python.bat @@ -47,7 +47,7 @@ @rem If py.exe finds a recent enough version, use that one @rem It is fine to add new versions to this list when they have released, @rem but we do not use prerelease builds here. -@for %%p in (3.12 3.11 3.10) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found +@for %%p in (3.13 3.12 3.11 3.10) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found @if NOT exist "%_Py_EXTERNALS_DIR%" mkdir "%_Py_EXTERNALS_DIR%" @set _Py_NUGET=%NUGET% From ad3eac1963a5f195ef9b2c1dbb5e44fa3cce4c72 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 17 Oct 2024 18:46:59 +0300 Subject: [PATCH 220/247] gh-52551: Fix encoding issues in strftime() (GH-125193) Fix time.strftime(), the strftime() method and formatting of the datetime classes datetime, date and time. * Characters not encodable in the current locale are now acceptable in the format string. * Surrogate pairs and sequence of surrogatescape-encoded bytes are no longer recombinated. * Embedded null character no longer terminates the format string. This fixes also gh-78662 and gh-124531. --- Lib/test/datetimetester.py | 63 ++++- Lib/test/test_time.py | 29 ++- ...4-10-09-17-07-33.gh-issue-52551.PBakSY.rst | 8 + Modules/_datetimemodule.c | 206 +++++++--------- Modules/timemodule.c | 233 ++++++++++-------- 5 files changed, 307 insertions(+), 232 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-09-17-07-33.gh-issue-52551.PBakSY.rst diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index c81408b344968d..dbe25ef57dea83 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -2949,11 +2949,32 @@ def test_more_strftime(self): self.assertEqual(t.strftime("%z"), "-0200" + z) self.assertEqual(t.strftime("%:z"), "-02:00:" + z) - # bpo-34482: Check that surrogates don't cause a crash. - try: - t.strftime('%y\ud800%m %H\ud800%M') - except UnicodeEncodeError: - pass + def test_strftime_special(self): + t = self.theclass(2004, 12, 31, 6, 22, 33, 47) + s1 = t.strftime('%c') + s2 = t.strftime('%B') + # gh-52551, gh-78662: Unicode strings should pass through strftime, + # independently from locale. + self.assertEqual(t.strftime('\U0001f40d'), '\U0001f40d') + self.assertEqual(t.strftime('\U0001f4bb%c\U0001f40d%B'), f'\U0001f4bb{s1}\U0001f40d{s2}') + self.assertEqual(t.strftime('%c\U0001f4bb%B\U0001f40d'), f'{s1}\U0001f4bb{s2}\U0001f40d') + # Lone surrogates should pass through. + self.assertEqual(t.strftime('\ud83d'), '\ud83d') + self.assertEqual(t.strftime('\udc0d'), '\udc0d') + self.assertEqual(t.strftime('\ud83d%c\udc0d%B'), f'\ud83d{s1}\udc0d{s2}') + self.assertEqual(t.strftime('%c\ud83d%B\udc0d'), f'{s1}\ud83d{s2}\udc0d') + self.assertEqual(t.strftime('%c\udc0d%B\ud83d'), f'{s1}\udc0d{s2}\ud83d') + # Surrogate pairs should not recombine. + self.assertEqual(t.strftime('\ud83d\udc0d'), '\ud83d\udc0d') + self.assertEqual(t.strftime('%c\ud83d\udc0d%B'), f'{s1}\ud83d\udc0d{s2}') + # Surrogate-escaped bytes should not recombine. + self.assertEqual(t.strftime('\udcf0\udc9f\udc90\udc8d'), '\udcf0\udc9f\udc90\udc8d') + self.assertEqual(t.strftime('%c\udcf0\udc9f\udc90\udc8d%B'), f'{s1}\udcf0\udc9f\udc90\udc8d{s2}') + # gh-124531: The null character should not terminate the format string. + self.assertEqual(t.strftime('\0'), '\0') + self.assertEqual(t.strftime('\0'*1000), '\0'*1000) + self.assertEqual(t.strftime('\0%c\0%B'), f'\0{s1}\0{s2}') + self.assertEqual(t.strftime('%c\0%B\0'), f'{s1}\0{s2}\0') def test_extract(self): dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234) @@ -3736,6 +3757,33 @@ def test_strftime(self): # gh-85432: The parameter was named "fmt" in the pure-Python impl. t.strftime(format="%f") + def test_strftime_special(self): + t = self.theclass(1, 2, 3, 4) + s1 = t.strftime('%I%p%Z') + s2 = t.strftime('%X') + # gh-52551, gh-78662: Unicode strings should pass through strftime, + # independently from locale. + self.assertEqual(t.strftime('\U0001f40d'), '\U0001f40d') + self.assertEqual(t.strftime('\U0001f4bb%I%p%Z\U0001f40d%X'), f'\U0001f4bb{s1}\U0001f40d{s2}') + self.assertEqual(t.strftime('%I%p%Z\U0001f4bb%X\U0001f40d'), f'{s1}\U0001f4bb{s2}\U0001f40d') + # Lone surrogates should pass through. + self.assertEqual(t.strftime('\ud83d'), '\ud83d') + self.assertEqual(t.strftime('\udc0d'), '\udc0d') + self.assertEqual(t.strftime('\ud83d%I%p%Z\udc0d%X'), f'\ud83d{s1}\udc0d{s2}') + self.assertEqual(t.strftime('%I%p%Z\ud83d%X\udc0d'), f'{s1}\ud83d{s2}\udc0d') + self.assertEqual(t.strftime('%I%p%Z\udc0d%X\ud83d'), f'{s1}\udc0d{s2}\ud83d') + # Surrogate pairs should not recombine. + self.assertEqual(t.strftime('\ud83d\udc0d'), '\ud83d\udc0d') + self.assertEqual(t.strftime('%I%p%Z\ud83d\udc0d%X'), f'{s1}\ud83d\udc0d{s2}') + # Surrogate-escaped bytes should not recombine. + self.assertEqual(t.strftime('\udcf0\udc9f\udc90\udc8d'), '\udcf0\udc9f\udc90\udc8d') + self.assertEqual(t.strftime('%I%p%Z\udcf0\udc9f\udc90\udc8d%X'), f'{s1}\udcf0\udc9f\udc90\udc8d{s2}') + # gh-124531: The null character should not terminate the format string. + self.assertEqual(t.strftime('\0'), '\0') + self.assertEqual(t.strftime('\0'*1000), '\0'*1000) + self.assertEqual(t.strftime('\0%I%p%Z\0%X'), f'\0{s1}\0{s2}') + self.assertEqual(t.strftime('%I%p%Z\0%X\0'), f'{s1}\0{s2}\0') + def test_format(self): t = self.theclass(1, 2, 3, 4) self.assertEqual(t.__format__(''), str(t)) @@ -4259,9 +4307,8 @@ def tzname(self, dt): return self.tz self.assertRaises(TypeError, t.strftime, "%Z") # Issue #6697: - if '_Fast' in self.__class__.__name__: - Badtzname.tz = '\ud800' - self.assertRaises(ValueError, t.strftime, "%Z") + Badtzname.tz = '\ud800' + self.assertEqual(t.strftime("%Z"), '\ud800') def test_hash_edge_cases(self): # Offsets that overflow a basic time. diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 27c0f51acc58ab..f8b99a9b6a63f5 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -181,8 +181,33 @@ def test_strftime(self): self.fail('conversion specifier: %r failed.' % format) self.assertRaises(TypeError, time.strftime, b'%S', tt) - # embedded null character - self.assertRaises(ValueError, time.strftime, '%S\0', tt) + + def test_strftime_special(self): + tt = time.gmtime(self.t) + s1 = time.strftime('%c', tt) + s2 = time.strftime('%B', tt) + # gh-52551, gh-78662: Unicode strings should pass through strftime, + # independently from locale. + self.assertEqual(time.strftime('\U0001f40d', tt), '\U0001f40d') + self.assertEqual(time.strftime('\U0001f4bb%c\U0001f40d%B', tt), f'\U0001f4bb{s1}\U0001f40d{s2}') + self.assertEqual(time.strftime('%c\U0001f4bb%B\U0001f40d', tt), f'{s1}\U0001f4bb{s2}\U0001f40d') + # Lone surrogates should pass through. + self.assertEqual(time.strftime('\ud83d', tt), '\ud83d') + self.assertEqual(time.strftime('\udc0d', tt), '\udc0d') + self.assertEqual(time.strftime('\ud83d%c\udc0d%B', tt), f'\ud83d{s1}\udc0d{s2}') + self.assertEqual(time.strftime('%c\ud83d%B\udc0d', tt), f'{s1}\ud83d{s2}\udc0d') + self.assertEqual(time.strftime('%c\udc0d%B\ud83d', tt), f'{s1}\udc0d{s2}\ud83d') + # Surrogate pairs should not recombine. + self.assertEqual(time.strftime('\ud83d\udc0d', tt), '\ud83d\udc0d') + self.assertEqual(time.strftime('%c\ud83d\udc0d%B', tt), f'{s1}\ud83d\udc0d{s2}') + # Surrogate-escaped bytes should not recombine. + self.assertEqual(time.strftime('\udcf0\udc9f\udc90\udc8d', tt), '\udcf0\udc9f\udc90\udc8d') + self.assertEqual(time.strftime('%c\udcf0\udc9f\udc90\udc8d%B', tt), f'{s1}\udcf0\udc9f\udc90\udc8d{s2}') + # gh-124531: The null character should not terminate the format string. + self.assertEqual(time.strftime('\0', tt), '\0') + self.assertEqual(time.strftime('\0'*1000, tt), '\0'*1000) + self.assertEqual(time.strftime('\0%c\0%B', tt), f'\0{s1}\0{s2}') + self.assertEqual(time.strftime('%c\0%B\0', tt), f'{s1}\0{s2}\0') def _bounds_checking(self, func): # Make sure that strftime() checks the bounds of the various parts diff --git a/Misc/NEWS.d/next/Library/2024-10-09-17-07-33.gh-issue-52551.PBakSY.rst b/Misc/NEWS.d/next/Library/2024-10-09-17-07-33.gh-issue-52551.PBakSY.rst new file mode 100644 index 00000000000000..edc9ac5bb23117 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-09-17-07-33.gh-issue-52551.PBakSY.rst @@ -0,0 +1,8 @@ +Fix encoding issues in :func:`time.strftime`, the +:meth:`~datetime.datetime.strftime` method of the :mod:`datetime` classes +:class:`~datetime.datetime`, :class:`~datetime.date` and +:class:`~datetime.time` and formatting of these classes. Characters not +encodable in the current locale are now acceptable in the format string. +Surrogate pairs and sequence of surrogatescape-encoded bytes are no longer +recombinated. Embedded null character no longer terminates the format +string. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 2ba46cddb4f558..e1bb98fcf05862 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1747,7 +1747,7 @@ make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) PyObject *tzinfo = get_tzinfo_member(object); if (tzinfo == Py_None || tzinfo == NULL) { - return PyBytes_FromStringAndSize(NULL, 0); + return PyUnicode_FromStringAndSize(NULL, 0); } assert(tzinfoarg != NULL); @@ -1758,7 +1758,7 @@ make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) tzinfoarg) < 0) return NULL; - return PyBytes_FromStringAndSize(buf, strlen(buf)); + return PyUnicode_FromString(buf); } static PyObject * @@ -1815,7 +1815,7 @@ make_freplacement(PyObject *object) else sprintf(freplacement, "%06d", 0); - return PyBytes_FromStringAndSize(freplacement, strlen(freplacement)); + return PyUnicode_FromString(freplacement); } /* I sure don't want to reproduce the strftime code from the time module, @@ -1836,94 +1836,60 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, PyObject *Zreplacement = NULL; /* py string, replacement for %Z */ PyObject *freplacement = NULL; /* py string, replacement for %f */ - const char *pin; /* pointer to next char in input format */ - Py_ssize_t flen; /* length of input format */ - char ch; /* next char in input format */ - - PyObject *newfmt = NULL; /* py string, the output format */ - char *pnew; /* pointer to available byte in output format */ - size_t totalnew; /* number bytes total in output format buffer, - exclusive of trailing \0 */ - size_t usednew; /* number bytes used so far in output format buffer */ - - const char *ptoappend; /* ptr to string to append to output buffer */ - Py_ssize_t ntoappend; /* # of bytes to append to output buffer */ - -#ifdef Py_NORMALIZE_CENTURY - /* Buffer of maximum size of formatted year permitted by long. */ - char buf[SIZEOF_LONG * 5 / 2 + 2 -#ifdef Py_STRFTIME_C99_SUPPORT - /* Need 6 more to accommodate dashes, 2-digit month and day for %F. */ - + 6 -#endif - ]; -#endif - assert(object && format && timetuple); assert(PyUnicode_Check(format)); - /* Convert the input format to a C string and size */ - pin = PyUnicode_AsUTF8AndSize(format, &flen); - if (!pin) - return NULL; PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime"); if (strftime == NULL) { - goto Done; + return NULL; } /* Scan the input format, looking for %z/%Z/%f escapes, building * a new format. Since computing the replacements for those codes * is expensive, don't unless they're actually used. */ - if (flen > INT_MAX - 1) { - PyErr_NoMemory(); - goto Done; - } - - totalnew = flen + 1; /* realistic if no %z/%Z */ - newfmt = PyBytes_FromStringAndSize(NULL, totalnew); - if (newfmt == NULL) goto Done; - pnew = PyBytes_AsString(newfmt); - usednew = 0; - while ((ch = *pin++) != '\0') { - if (ch != '%') { - ptoappend = pin - 1; - ntoappend = 1; + _PyUnicodeWriter writer; + _PyUnicodeWriter_Init(&writer); + writer.overallocate = 1; + + Py_ssize_t flen = PyUnicode_GET_LENGTH(format); + Py_ssize_t i = 0; + Py_ssize_t start = 0; + Py_ssize_t end = 0; + while (i != flen) { + i = PyUnicode_FindChar(format, '%', i, flen, 1); + if (i < 0) { + assert(!PyErr_Occurred()); + break; } - else if ((ch = *pin++) == '\0') { - /* Null byte follows %, copy only '%'. - * - * Back the pin up one char so that we catch the null check - * the next time through the loop.*/ - pin--; - ptoappend = pin - 1; - ntoappend = 1; + end = i; + i++; + if (i == flen) { + break; } + Py_UCS4 ch = PyUnicode_READ_CHAR(format, i); + i++; /* A % has been seen and ch is the character after it. */ - else if (ch == 'z') { + PyObject *replacement = NULL; + if (ch == 'z') { /* %z -> +HHMM */ if (zreplacement == NULL) { zreplacement = make_somezreplacement(object, "", tzinfoarg); if (zreplacement == NULL) - goto Done; + goto Error; } - assert(zreplacement != NULL); - assert(PyBytes_Check(zreplacement)); - ptoappend = PyBytes_AS_STRING(zreplacement); - ntoappend = PyBytes_GET_SIZE(zreplacement); + replacement = zreplacement; } - else if (ch == ':' && *pin == 'z' && pin++) { + else if (ch == ':' && i < flen && PyUnicode_READ_CHAR(format, i) == 'z') { /* %:z -> +HH:MM */ + i++; if (colonzreplacement == NULL) { colonzreplacement = make_somezreplacement(object, ":", tzinfoarg); if (colonzreplacement == NULL) - goto Done; + goto Error; } - assert(colonzreplacement != NULL); - assert(PyBytes_Check(colonzreplacement)); - ptoappend = PyBytes_AS_STRING(colonzreplacement); - ntoappend = PyBytes_GET_SIZE(colonzreplacement); + replacement = colonzreplacement; } else if (ch == 'Z') { /* format tzname */ @@ -1931,26 +1897,18 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, Zreplacement = make_Zreplacement(object, tzinfoarg); if (Zreplacement == NULL) - goto Done; + goto Error; } - assert(Zreplacement != NULL); - assert(PyUnicode_Check(Zreplacement)); - ptoappend = PyUnicode_AsUTF8AndSize(Zreplacement, - &ntoappend); - if (ptoappend == NULL) - goto Done; + replacement = Zreplacement; } else if (ch == 'f') { /* format microseconds */ if (freplacement == NULL) { freplacement = make_freplacement(object); if (freplacement == NULL) - goto Done; + goto Error; } - assert(freplacement != NULL); - assert(PyBytes_Check(freplacement)); - ptoappend = PyBytes_AS_STRING(freplacement); - ntoappend = PyBytes_GET_SIZE(freplacement); + replacement = freplacement; } #ifdef Py_NORMALIZE_CENTURY else if (ch == 'Y' || ch == 'G' @@ -1961,100 +1919,102 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, /* 0-pad year with century as necessary */ PyObject *item = PySequence_GetItem(timetuple, 0); if (item == NULL) { - goto Done; + goto Error; } long year_long = PyLong_AsLong(item); Py_DECREF(item); if (year_long == -1 && PyErr_Occurred()) { - goto Done; + goto Error; } /* Note that datetime(1000, 1, 1).strftime('%G') == '1000' so year 1000 for %G can go on the fast path. */ if (year_long >= 1000) { - goto PassThrough; + continue; } if (ch == 'G') { PyObject *year_str = PyObject_CallFunction(strftime, "sO", "%G", timetuple); if (year_str == NULL) { - goto Done; + goto Error; } PyObject *year = PyNumber_Long(year_str); Py_DECREF(year_str); if (year == NULL) { - goto Done; + goto Error; } year_long = PyLong_AsLong(year); Py_DECREF(year); if (year_long == -1 && PyErr_Occurred()) { - goto Done; + goto Error; } } - ntoappend = PyOS_snprintf(buf, sizeof(buf), + /* Buffer of maximum size of formatted year permitted by long. + * +6 to accommodate dashes, 2-digit month and day for %F. */ + char buf[SIZEOF_LONG * 5 / 2 + 2 + 6]; + Py_ssize_t n = PyOS_snprintf(buf, sizeof(buf), #ifdef Py_STRFTIME_C99_SUPPORT ch == 'F' ? "%04ld-%%m-%%d" : #endif "%04ld", year_long); #ifdef Py_STRFTIME_C99_SUPPORT if (ch == 'C') { - ntoappend -= 2; + n -= 2; } #endif - ptoappend = buf; + if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { + goto Error; + } + start = i; + if (_PyUnicodeWriter_WriteASCIIString(&writer, buf, n) < 0) { + goto Error; + } + continue; } #endif else { /* percent followed by something else */ -#ifdef Py_NORMALIZE_CENTURY - PassThrough: -#endif - ptoappend = pin - 2; - ntoappend = 2; - } - - /* Append the ntoappend chars starting at ptoappend to - * the new format. - */ - if (ntoappend == 0) continue; - assert(ptoappend != NULL); - assert(ntoappend > 0); - while (usednew + ntoappend > totalnew) { - if (totalnew > (PY_SSIZE_T_MAX >> 1)) { /* overflow */ - PyErr_NoMemory(); - goto Done; - } - totalnew <<= 1; - if (_PyBytes_Resize(&newfmt, totalnew) < 0) - goto Done; - pnew = PyBytes_AsString(newfmt) + usednew; } - memcpy(pnew, ptoappend, ntoappend); - pnew += ntoappend; - usednew += ntoappend; - assert(usednew <= totalnew); + assert(replacement != NULL); + assert(PyUnicode_Check(replacement)); + if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { + goto Error; + } + start = i; + if (_PyUnicodeWriter_WriteStr(&writer, replacement) < 0) { + goto Error; + } } /* end while() */ - if (_PyBytes_Resize(&newfmt, usednew) < 0) - goto Done; - { - PyObject *format; - - format = PyUnicode_FromString(PyBytes_AS_STRING(newfmt)); - if (format != NULL) { - result = PyObject_CallFunctionObjArgs(strftime, - format, timetuple, NULL); - Py_DECREF(format); + PyObject *newformat; + if (start == 0) { + _PyUnicodeWriter_Dealloc(&writer); + newformat = Py_NewRef(format); + } + else { + if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, flen) < 0) { + goto Error; + } + newformat = _PyUnicodeWriter_Finish(&writer); + if (newformat == NULL) { + goto Done; } } + result = PyObject_CallFunctionObjArgs(strftime, + newformat, timetuple, NULL); + Py_DECREF(newformat); + Done: Py_XDECREF(freplacement); Py_XDECREF(zreplacement); Py_XDECREF(colonzreplacement); Py_XDECREF(Zreplacement); - Py_XDECREF(newfmt); Py_XDECREF(strftime); return result; + + Error: + _PyUnicodeWriter_Dealloc(&writer); + goto Done; } /* --------------------------------------------------------------------------- diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 9720c201a184a8..b9d114ada0dfcd 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -776,27 +776,100 @@ the C library strftime function.\n" #endif static PyObject * -time_strftime(PyObject *module, PyObject *args) +time_strftime1(time_char **outbuf, size_t *bufsize, + time_char *format, size_t fmtlen, + struct tm *tm) { - PyObject *tup = NULL; - struct tm buf; - const time_char *fmt; + size_t buflen; +#if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME) + /* check that the format string contains only valid directives */ + for (const time_char *f = strchr(format, '%'); + f != NULL; + f = strchr(f + 2, '%')) + { + if (f[1] == '#') + ++f; /* not documented by python, */ + if (f[1] == '\0') + break; + if ((f[1] == 'y') && tm->tm_year < 0) { + PyErr_SetString(PyExc_ValueError, + "format %y requires year >= 1900 on Windows"); + return NULL; + } + } +#elif (defined(_AIX) || (defined(__sun) && defined(__SVR4))) && defined(HAVE_WCSFTIME) + for (const time_char *f = wcschr(format, '%'); + f != NULL; + f = wcschr(f + 2, '%')) + { + if (f[1] == L'\0') + break; + /* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0)) + returns "0/" instead of "99" */ + if (f[1] == L'y' && tm->tm_year < 0) { + PyErr_SetString(PyExc_ValueError, + "format %y requires year >= 1900 on AIX"); + return NULL; + } + } +#endif + + /* I hate these functions that presume you know how big the output + * will be ahead of time... + */ + while (1) { + if (*bufsize > PY_SSIZE_T_MAX/sizeof(time_char)) { + PyErr_NoMemory(); + return NULL; + } + *outbuf = (time_char *)PyMem_Realloc(*outbuf, + *bufsize*sizeof(time_char)); + if (*outbuf == NULL) { + PyErr_NoMemory(); + return NULL; + } +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) + errno = 0; +#endif + _Py_BEGIN_SUPPRESS_IPH + buflen = format_time(*outbuf, *bufsize, format, tm); + _Py_END_SUPPRESS_IPH +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) + /* VisualStudio .NET 2005 does this properly */ + if (buflen == 0 && errno == EINVAL) { + PyErr_SetString(PyExc_ValueError, "Invalid format string"); + return NULL; + } +#endif + if (buflen == 0 && *bufsize < 256 * fmtlen) { + *bufsize += *bufsize; + continue; + } + /* If the buffer is 256 times as long as the format, + it's probably not failing for lack of room! + More likely, the format yields an empty result, + e.g. an empty format, or %Z when the timezone + is unknown. */ #ifdef HAVE_WCSFTIME - wchar_t *format; + return PyUnicode_FromWideChar(*outbuf, buflen); #else - PyObject *format; + return PyUnicode_DecodeLocaleAndSize(*outbuf, buflen, "surrogateescape"); #endif + } +} + +static PyObject * +time_strftime(PyObject *module, PyObject *args) +{ + PyObject *tup = NULL; + struct tm buf; PyObject *format_arg; - size_t fmtlen, buflen; - time_char *outbuf = NULL; - size_t i; - PyObject *ret = NULL; + Py_ssize_t format_size; + time_char *format, *outbuf = NULL; + size_t fmtlen, bufsize = 1024; memset((void *) &buf, '\0', sizeof(buf)); - /* Will always expect a unicode string to be passed as format. - Given that there's no str type anymore in py3k this seems safe. - */ if (!PyArg_ParseTuple(args, "U|O:strftime", &format_arg, &tup)) return NULL; @@ -834,101 +907,63 @@ time_strftime(PyObject *module, PyObject *args) else if (buf.tm_isdst > 1) buf.tm_isdst = 1; -#ifdef HAVE_WCSFTIME - format = PyUnicode_AsWideCharString(format_arg, NULL); - if (format == NULL) + format_size = PyUnicode_GET_LENGTH(format_arg); + if ((size_t)format_size > PY_SSIZE_T_MAX/sizeof(time_char) - 1) { + PyErr_NoMemory(); return NULL; - fmt = format; -#else - /* Convert the unicode string to an ascii one */ - format = PyUnicode_EncodeLocale(format_arg, "surrogateescape"); - if (format == NULL) + } + format = PyMem_Malloc((format_size + 1)*sizeof(time_char)); + if (format == NULL) { + PyErr_NoMemory(); return NULL; - fmt = PyBytes_AS_STRING(format); -#endif - -#if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME) - /* check that the format string contains only valid directives */ - for (outbuf = strchr(fmt, '%'); - outbuf != NULL; - outbuf = strchr(outbuf+2, '%')) - { - if (outbuf[1] == '#') - ++outbuf; /* not documented by python, */ - if (outbuf[1] == '\0') - break; - if ((outbuf[1] == 'y') && buf.tm_year < 0) { - PyErr_SetString(PyExc_ValueError, - "format %y requires year >= 1900 on Windows"); - Py_DECREF(format); - return NULL; - } } -#elif (defined(_AIX) || (defined(__sun) && defined(__SVR4))) && defined(HAVE_WCSFTIME) - for (outbuf = wcschr(fmt, '%'); - outbuf != NULL; - outbuf = wcschr(outbuf+2, '%')) - { - if (outbuf[1] == L'\0') - break; - /* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0)) - returns "0/" instead of "99" */ - if (outbuf[1] == L'y' && buf.tm_year < 0) { - PyErr_SetString(PyExc_ValueError, - "format %y requires year >= 1900 on AIX"); - PyMem_Free(format); - return NULL; + _PyUnicodeWriter writer; + _PyUnicodeWriter_Init(&writer); + writer.overallocate = 1; + Py_ssize_t i = 0; + while (i < format_size) { + fmtlen = 0; + for (; i < format_size; i++) { + Py_UCS4 c = PyUnicode_READ_CHAR(format_arg, i); + if (!c || c > 127) { + break; + } + format[fmtlen++] = (char)c; } - } -#endif - - fmtlen = time_strlen(fmt); - - /* I hate these functions that presume you know how big the output - * will be ahead of time... - */ - for (i = 1024; ; i += i) { - outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char)); - if (outbuf == NULL) { - PyErr_NoMemory(); - break; + if (fmtlen) { + format[fmtlen] = 0; + PyObject *unicode = time_strftime1(&outbuf, &bufsize, + format, fmtlen, &buf); + if (unicode == NULL) { + goto error; + } + if (_PyUnicodeWriter_WriteStr(&writer, unicode) < 0) { + Py_DECREF(unicode); + goto error; + } + Py_DECREF(unicode); } -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - errno = 0; -#endif - _Py_BEGIN_SUPPRESS_IPH - buflen = format_time(outbuf, i, fmt, &buf); - _Py_END_SUPPRESS_IPH -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - /* VisualStudio .NET 2005 does this properly */ - if (buflen == 0 && errno == EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid format string"); - PyMem_Free(outbuf); - break; + + Py_ssize_t start = i; + for (; i < format_size; i++) { + Py_UCS4 c = PyUnicode_READ_CHAR(format_arg, i); + if (c == '%') { + break; + } } -#endif - if (buflen > 0 || i >= 256 * fmtlen) { - /* If the buffer is 256 times as long as the format, - it's probably not failing for lack of room! - More likely, the format yields an empty result, - e.g. an empty format, or %Z when the timezone - is unknown. */ -#ifdef HAVE_WCSFTIME - ret = PyUnicode_FromWideChar(outbuf, buflen); -#else - ret = PyUnicode_DecodeLocaleAndSize(outbuf, buflen, "surrogateescape"); -#endif - PyMem_Free(outbuf); - break; + if (_PyUnicodeWriter_WriteSubstring(&writer, format_arg, start, i) < 0) { + goto error; } - PyMem_Free(outbuf); } -#ifdef HAVE_WCSFTIME + + PyMem_Free(outbuf); PyMem_Free(format); -#else - Py_DECREF(format); -#endif - return ret; + return _PyUnicodeWriter_Finish(&writer); +error: + PyMem_Free(outbuf); + PyMem_Free(format); + _PyUnicodeWriter_Dealloc(&writer); + return NULL; } #undef time_char From 04d6dd23e2d8a3132772cf7ce928676e26313585 Mon Sep 17 00:00:00 2001 From: George Pittock <66332098+georgepittock@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:34:37 +0100 Subject: [PATCH 221/247] gh-113570: reprlib.repr does not use builtin __repr__ for reshadowed builtins (GH-113577) --- Lib/reprlib.py | 31 ++++++++++--- Lib/test/test_reprlib.py | 44 +++++++++++++++++++ ...-12-30-00-21-45.gh-issue-113570._XQgsW.rst | 1 + 3 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-30-00-21-45.gh-issue-113570._XQgsW.rst diff --git a/Lib/reprlib.py b/Lib/reprlib.py index 05bb1a0eb01795..19dbe3a07eb618 100644 --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -36,6 +36,17 @@ def wrapper(self): return decorating_function class Repr: + _lookup = { + 'tuple': 'builtins', + 'list': 'builtins', + 'array': 'array', + 'set': 'builtins', + 'frozenset': 'builtins', + 'deque': 'collections', + 'dict': 'builtins', + 'str': 'builtins', + 'int': 'builtins' + } def __init__( self, *, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4, @@ -60,14 +71,24 @@ def repr(self, x): return self.repr1(x, self.maxlevel) def repr1(self, x, level): - typename = type(x).__name__ + cls = type(x) + typename = cls.__name__ + if ' ' in typename: parts = typename.split() typename = '_'.join(parts) - if hasattr(self, 'repr_' + typename): - return getattr(self, 'repr_' + typename)(x, level) - else: - return self.repr_instance(x, level) + + method = getattr(self, 'repr_' + typename, None) + if method: + # not defined in this class + if typename not in self._lookup: + return method(x, level) + module = getattr(cls, '__module__', None) + # defined in this class and is the module intended + if module == self._lookup[typename]: + return method(x, level) + + return self.repr_instance(x, level) def _join(self, pieces, level): if self.indent is None: diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index 3e93b561c143d8..ffeb1fba7b80c6 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -580,6 +580,50 @@ def test_invalid_indent(self): with self.assertRaisesRegex(expected_error, expected_msg): r.repr(test_object) + def test_shadowed_stdlib_array(self): + # Issue #113570: repr() should not be fooled by an array + class array: + def __repr__(self): + return "not array.array" + + self.assertEqual(r(array()), "not array.array") + + def test_shadowed_builtin(self): + # Issue #113570: repr() should not be fooled + # by a shadowed builtin function + class list: + def __repr__(self): + return "not builtins.list" + + self.assertEqual(r(list()), "not builtins.list") + + def test_custom_repr(self): + class MyRepr(Repr): + + def repr_TextIOWrapper(self, obj, level): + if obj.name in {'', '', ''}: + return obj.name + return repr(obj) + + aRepr = MyRepr() + self.assertEqual(aRepr.repr(sys.stdin), "") + + def test_custom_repr_class_with_spaces(self): + class TypeWithSpaces: + pass + + t = TypeWithSpaces() + type(t).__name__ = "type with spaces" + self.assertEqual(type(t).__name__, "type with spaces") + + class MyRepr(Repr): + def repr_type_with_spaces(self, obj, level): + return "Type With Spaces" + + + aRepr = MyRepr() + self.assertEqual(aRepr.repr(t), "Type With Spaces") + def write_file(path, text): with open(path, 'w', encoding='ASCII') as fp: fp.write(text) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-30-00-21-45.gh-issue-113570._XQgsW.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-30-00-21-45.gh-issue-113570._XQgsW.rst new file mode 100644 index 00000000000000..6e0f0afe05369b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-30-00-21-45.gh-issue-113570._XQgsW.rst @@ -0,0 +1 @@ +Fixed a bug in ``reprlib.repr`` where it incorrectly called the repr method on shadowed Python built-in types. From f203d1cb52f7697140337a73841c8412282e2ee0 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 17 Oct 2024 09:45:25 -0700 Subject: [PATCH 222/247] gh-125017: Fix crash on premature access to classmethod/staticmethod annotations (#125636) --- Lib/test/test_descr.py | 14 +++++++ ...-10-16-23-06-06.gh-issue-125017.fcltj0.rst | 2 + Objects/funcobject.c | 41 ++++++++++++------- 3 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-23-06-06.gh-issue-125017.fcltj0.rst diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 9d15ab3a96bad6..b7e0f4d6d64018 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1618,6 +1618,9 @@ def annotated(cls) -> int: pass for method in (annotated, unannotated): with self.subTest(deco=deco, method=method): + with self.assertRaises(AttributeError): + del unannotated.__annotations__ + original_annotations = dict(method.__wrapped__.__annotations__) self.assertNotIn('__annotations__', method.__dict__) self.assertEqual(method.__annotations__, original_annotations) @@ -1644,6 +1647,17 @@ def annotated(cls) -> int: pass del method.__annotate__ self.assertIs(method.__annotate__, original_annotate) + def test_staticmethod_annotations_without_dict_access(self): + # gh-125017: this used to crash + class Spam: + def __new__(cls, x, y): + pass + + self.assertEqual(Spam.__new__.__annotations__, {}) + obj = Spam.__dict__['__new__'] + self.assertIsInstance(obj, staticmethod) + self.assertEqual(obj.__annotations__, {}) + @support.refcount_test def test_refleaks_in_classmethod___init__(self): gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-23-06-06.gh-issue-125017.fcltj0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-23-06-06.gh-issue-125017.fcltj0.rst new file mode 100644 index 00000000000000..11c526643c3122 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-16-23-06-06.gh-issue-125017.fcltj0.rst @@ -0,0 +1,2 @@ +Fix crash on certain accesses to the ``__annotations__`` of +:class:`staticmethod` and :class:`classmethod` objects. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 6119a96b4aae76..f86ef32f1827bf 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1220,30 +1220,43 @@ functools_wraps(PyObject *wrapper, PyObject *wrapped) // Used for wrapping __annotations__ and __annotate__ on classmethod // and staticmethod objects. static PyObject * -descriptor_get_wrapped_attribute(PyObject *wrapped, PyObject *dict, PyObject *name) +descriptor_get_wrapped_attribute(PyObject *wrapped, PyObject *obj, PyObject *name) { + PyObject *dict = PyObject_GenericGetDict(obj, NULL); + if (dict == NULL) { + return NULL; + } PyObject *res; if (PyDict_GetItemRef(dict, name, &res) < 0) { + Py_DECREF(dict); return NULL; } if (res != NULL) { + Py_DECREF(dict); return res; } res = PyObject_GetAttr(wrapped, name); if (res == NULL) { + Py_DECREF(dict); return NULL; } if (PyDict_SetItem(dict, name, res) < 0) { + Py_DECREF(dict); Py_DECREF(res); return NULL; } + Py_DECREF(dict); return res; } static int -descriptor_set_wrapped_attribute(PyObject *dict, PyObject *name, PyObject *value, +descriptor_set_wrapped_attribute(PyObject *oobj, PyObject *name, PyObject *value, char *type_name) { + PyObject *dict = PyObject_GenericGetDict(oobj, NULL); + if (dict == NULL) { + return -1; + } if (value == NULL) { if (PyDict_DelItem(dict, name) < 0) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { @@ -1251,14 +1264,18 @@ descriptor_set_wrapped_attribute(PyObject *dict, PyObject *name, PyObject *value PyErr_Format(PyExc_AttributeError, "'%.200s' object has no attribute '%U'", type_name, name); + return -1; } else { + Py_DECREF(dict); return -1; } } + Py_DECREF(dict); return 0; } else { + Py_DECREF(dict); return PyDict_SetItem(dict, name, value); } } @@ -1380,28 +1397,26 @@ static PyObject * cm_get___annotations__(PyObject *self, void *closure) { classmethod *cm = _PyClassMethod_CAST(self); - return descriptor_get_wrapped_attribute(cm->cm_callable, cm->cm_dict, &_Py_ID(__annotations__)); + return descriptor_get_wrapped_attribute(cm->cm_callable, self, &_Py_ID(__annotations__)); } static int cm_set___annotations__(PyObject *self, PyObject *value, void *closure) { - classmethod *cm = _PyClassMethod_CAST(self); - return descriptor_set_wrapped_attribute(cm->cm_dict, &_Py_ID(__annotations__), value, "classmethod"); + return descriptor_set_wrapped_attribute(self, &_Py_ID(__annotations__), value, "classmethod"); } static PyObject * cm_get___annotate__(PyObject *self, void *closure) { classmethod *cm = _PyClassMethod_CAST(self); - return descriptor_get_wrapped_attribute(cm->cm_callable, cm->cm_dict, &_Py_ID(__annotate__)); + return descriptor_get_wrapped_attribute(cm->cm_callable, self, &_Py_ID(__annotate__)); } static int cm_set___annotate__(PyObject *self, PyObject *value, void *closure) { - classmethod *cm = _PyClassMethod_CAST(self); - return descriptor_set_wrapped_attribute(cm->cm_dict, &_Py_ID(__annotate__), value, "classmethod"); + return descriptor_set_wrapped_attribute(self, &_Py_ID(__annotate__), value, "classmethod"); } @@ -1615,28 +1630,26 @@ static PyObject * sm_get___annotations__(PyObject *self, void *closure) { staticmethod *sm = _PyStaticMethod_CAST(self); - return descriptor_get_wrapped_attribute(sm->sm_callable, sm->sm_dict, &_Py_ID(__annotations__)); + return descriptor_get_wrapped_attribute(sm->sm_callable, self, &_Py_ID(__annotations__)); } static int sm_set___annotations__(PyObject *self, PyObject *value, void *closure) { - staticmethod *sm = _PyStaticMethod_CAST(self); - return descriptor_set_wrapped_attribute(sm->sm_dict, &_Py_ID(__annotations__), value, "staticmethod"); + return descriptor_set_wrapped_attribute(self, &_Py_ID(__annotations__), value, "staticmethod"); } static PyObject * sm_get___annotate__(PyObject *self, void *closure) { staticmethod *sm = _PyStaticMethod_CAST(self); - return descriptor_get_wrapped_attribute(sm->sm_callable, sm->sm_dict, &_Py_ID(__annotate__)); + return descriptor_get_wrapped_attribute(sm->sm_callable, self, &_Py_ID(__annotate__)); } static int sm_set___annotate__(PyObject *self, PyObject *value, void *closure) { - staticmethod *sm = _PyStaticMethod_CAST(self); - return descriptor_set_wrapped_attribute(sm->sm_dict, &_Py_ID(__annotate__), value, "staticmethod"); + return descriptor_set_wrapped_attribute(self, &_Py_ID(__annotate__), value, "staticmethod"); } static PyGetSetDef sm_getsetlist[] = { From b454662921fd3a1fc27169e91aca03aadea08817 Mon Sep 17 00:00:00 2001 From: chrysn Date: Thu, 17 Oct 2024 19:49:12 +0200 Subject: [PATCH 223/247] gh-118986: expose `socket.IPV6_RECVERR` (#118987) --- Doc/library/socket.rst | 4 ++-- .../Library/2024-05-13-10-09-41.gh-issue-118986.-r4W9h.rst | 1 + Modules/socketmodule.c | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-05-13-10-09-41.gh-issue-118986.-r4W9h.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 935d4a85342876..0c7b9328648f66 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -451,8 +451,8 @@ Constants network interface instead of its name. .. versionchanged:: 3.14 - Added missing ``IP_RECVERR``, ``IP_RECVTTL``, and ``IP_RECVORIGDSTADDR`` - on Linux. + Added missing ``IP_RECVERR``, ``IPV6_RECVERR``, ``IP_RECVTTL``, and + ``IP_RECVORIGDSTADDR`` on Linux. .. versionchanged:: 3.14 Added support for ``TCP_QUICKACK`` on Windows platforms when available. diff --git a/Misc/NEWS.d/next/Library/2024-05-13-10-09-41.gh-issue-118986.-r4W9h.rst b/Misc/NEWS.d/next/Library/2024-05-13-10-09-41.gh-issue-118986.-r4W9h.rst new file mode 100644 index 00000000000000..196da60a950bfb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-13-10-09-41.gh-issue-118986.-r4W9h.rst @@ -0,0 +1 @@ +Add :data:`!socket.IPV6_RECVERR` constant (available since Linux 2.2). diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 744e5e0c0b2b54..2764bd6e2b2a47 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -8578,6 +8578,9 @@ socket_exec(PyObject *m) #ifdef IPV6_RECVDSTOPTS ADD_INT_MACRO(m, IPV6_RECVDSTOPTS); #endif +#ifdef IPV6_RECVERR + ADD_INT_MACRO(m, IPV6_RECVERR); +#endif #ifdef IPV6_RECVHOPLIMIT ADD_INT_MACRO(m, IPV6_RECVHOPLIMIT); #endif From d8c864816121547338efa43c56e3f75ead98a924 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 17 Oct 2024 14:10:55 -0400 Subject: [PATCH 224/247] gh-125541: Make Ctrl-C interrupt `threading.Lock.acquire()` on Windows (#125546) --- Doc/library/_thread.rst | 9 +++------ Doc/library/threading.rst | 3 +++ ...24-10-15-16-50-03.gh-issue-125541.FfhmWo.rst | 4 ++++ Python/parking_lot.c | 17 +++++++++++++++-- 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 6a66fc4c64bc45..ed29ac70035597 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -187,6 +187,9 @@ Lock objects have the following methods: .. versionchanged:: 3.2 Lock acquires can now be interrupted by signals on POSIX. + .. versionchanged:: 3.14 + Lock acquires can now be interrupted by signals on Windows. + .. method:: lock.release() @@ -219,12 +222,6 @@ In addition to these methods, lock objects can also be used via the * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is equivalent to calling :func:`_thread.exit`. -* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method - on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception - will happen immediately, rather than only after the lock has been acquired or - the operation has timed out). It can be interrupted on POSIX, but not on - Windows. - * When the main thread exits, it is system defined whether the other threads survive. On most systems, they are killed without executing :keyword:`try` ... :keyword:`finally` clauses or executing object diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index cb82fea377697b..d4b343db36efb3 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -567,6 +567,9 @@ All methods are executed atomically. Lock acquisition can now be interrupted by signals on POSIX if the underlying threading implementation supports it. + .. versionchanged:: 3.14 + Lock acquisition can now be interrupted by signals on Windows. + .. method:: release() diff --git a/Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst b/Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst new file mode 100644 index 00000000000000..7a20bca1739869 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst @@ -0,0 +1,4 @@ +Pressing :kbd:`Ctrl-C` while blocked in :meth:`threading.Lock.acquire`, +:meth:`threading.RLock.acquire`, and :meth:`threading.Thread.join` now +interrupts the function call and raises a :exc:`KeyboardInterrupt` exception +on Windows, similar to how those functions behave on macOS and Linux. diff --git a/Python/parking_lot.c b/Python/parking_lot.c index a7e9760e35d87a..bffc959e5d0978 100644 --- a/Python/parking_lot.c +++ b/Python/parking_lot.c @@ -111,15 +111,28 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, PyTime_t timeout) millis = (DWORD) div; } } - wait = WaitForSingleObjectEx(sema->platform_sem, millis, FALSE); + + // NOTE: we wait on the sigint event even in non-main threads to match the + // behavior of the other platforms. Non-main threads will ignore the + // Py_PARK_INTR result. + HANDLE sigint_event = _PyOS_SigintEvent(); + HANDLE handles[2] = { sema->platform_sem, sigint_event }; + DWORD count = sigint_event != NULL ? 2 : 1; + wait = WaitForMultipleObjects(count, handles, FALSE, millis); if (wait == WAIT_OBJECT_0) { res = Py_PARK_OK; } + else if (wait == WAIT_OBJECT_0 + 1) { + ResetEvent(sigint_event); + res = Py_PARK_INTR; + } else if (wait == WAIT_TIMEOUT) { res = Py_PARK_TIMEOUT; } else { - res = Py_PARK_INTR; + _Py_FatalErrorFormat(__func__, + "unexpected error from semaphore: %u (error: %u)", + wait, GetLastError()); } #elif defined(_Py_USE_SEMAPHORES) int err; From c3164ae3cf4e8f9ccc4df8ea5f5664c5927ea839 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Thu, 17 Oct 2024 17:21:32 -0500 Subject: [PATCH 225/247] gh-125017: Fix refleak from GH-125636 (GH-125664) --- Objects/funcobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/funcobject.c b/Objects/funcobject.c index f86ef32f1827bf..3cb247691386bf 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1264,6 +1264,7 @@ descriptor_set_wrapped_attribute(PyObject *oobj, PyObject *name, PyObject *value PyErr_Format(PyExc_AttributeError, "'%.200s' object has no attribute '%U'", type_name, name); + Py_DECREF(dict); return -1; } else { From 7cf2dbc3cb3ef7be65a98bbfc87246d36d795c82 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 17 Oct 2024 17:49:15 -0600 Subject: [PATCH 226/247] gh-125667: Statically Initialize the Arg Converter Data Values in _interpqueuesmodule.c (gh-125668) --- Modules/_interpqueuesmodule.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c index 5dec240f02c4db..55c43199ee4d79 100644 --- a/Modules/_interpqueuesmodule.c +++ b/Modules/_interpqueuesmodule.c @@ -1518,7 +1518,7 @@ static PyObject * queuesmod_destroy(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:destroy", kwlist, qidarg_converter, &qidarg)) { return NULL; @@ -1579,7 +1579,7 @@ static PyObject * queuesmod_put(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", "obj", "fmt", "unboundop", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; PyObject *obj; int fmt; int unboundop; @@ -1615,7 +1615,7 @@ static PyObject * queuesmod_get(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get", kwlist, qidarg_converter, &qidarg)) { return NULL; @@ -1651,7 +1651,7 @@ static PyObject * queuesmod_bind(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:bind", kwlist, qidarg_converter, &qidarg)) { return NULL; @@ -1681,7 +1681,7 @@ queuesmod_release(PyObject *self, PyObject *args, PyObject *kwds) { // Note that only the current interpreter is affected. static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:release", kwlist, qidarg_converter, &qidarg)) { @@ -1710,7 +1710,7 @@ static PyObject * queuesmod_get_maxsize(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get_maxsize", kwlist, qidarg_converter, &qidarg)) { @@ -1735,7 +1735,7 @@ static PyObject * queuesmod_get_queue_defaults(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get_queue_defaults", kwlist, qidarg_converter, &qidarg)) { @@ -1765,7 +1765,7 @@ static PyObject * queuesmod_is_full(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:is_full", kwlist, qidarg_converter, &qidarg)) { @@ -1793,7 +1793,7 @@ static PyObject * queuesmod_get_count(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg; + qidarg_converter_data qidarg = {0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get_count", kwlist, qidarg_converter, &qidarg)) { From 77cebb1ce9baac9e01a45d34113c3bea74940d90 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 17 Oct 2024 17:29:11 -0700 Subject: [PATCH 227/247] gh-125600: Only show stale code warning on source code display commands (#125601) --- Lib/pdb.py | 24 +++++++++++++++---- Lib/test/test_pdb.py | 19 +++++++++++++++ ...-10-16-15-55-50.gh-issue-125600.yMsJx0.rst | 1 + 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-16-15-55-50.gh-issue-125600.yMsJx0.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 3e5e6088fdcc7e..cd7a7042fa6987 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -402,6 +402,8 @@ def setup(self, f, tb): self.curframe = self.stack[self.curindex][0] self.set_convenience_variable(self.curframe, '_frame', self.curframe) + self._save_initial_file_mtime(self.curframe) + if self._chained_exceptions: self.set_convenience_variable( self.curframe, @@ -494,9 +496,21 @@ def _cmdloop(self): except KeyboardInterrupt: self.message('--KeyboardInterrupt--') + def _save_initial_file_mtime(self, frame): + """save the mtime of the all the files in the frame stack in the file mtime table + if they haven't been saved yet.""" + while frame: + filename = frame.f_code.co_filename + if filename not in self._file_mtime_table: + try: + self._file_mtime_table[filename] = os.path.getmtime(filename) + except Exception: + pass + frame = frame.f_back + def _validate_file_mtime(self): - """Check if the source file of the current frame has been modified since - the last time we saw it. If so, give a warning.""" + """Check if the source file of the current frame has been modified. + If so, give a warning and reset the modify time to current.""" try: filename = self.curframe.f_code.co_filename mtime = os.path.getmtime(filename) @@ -506,7 +520,7 @@ def _validate_file_mtime(self): mtime != self._file_mtime_table[filename]): self.message(f"*** WARNING: file '{filename}' was edited, " "running stale code until the program is rerun") - self._file_mtime_table[filename] = mtime + self._file_mtime_table[filename] = mtime # Called before loop, handles display expressions # Set up convenience variable containers @@ -836,7 +850,6 @@ def onecmd(self, line): a breakpoint command list definition. """ if not self.commands_defining: - self._validate_file_mtime() if line.startswith('_pdbcmd'): command, arg, line = self.parseline(line) if hasattr(self, command): @@ -980,6 +993,7 @@ def completedefault(self, text, line, begidx, endidx): def _pdbcmd_print_frame_status(self, arg): self.print_stack_trace(0) + self._validate_file_mtime() self._show_display() def _pdbcmd_silence_frame_status(self, arg): @@ -1861,6 +1875,7 @@ def do_list(self, arg): self.message('[EOF]') except KeyboardInterrupt: pass + self._validate_file_mtime() do_l = do_list def do_longlist(self, arg): @@ -1879,6 +1894,7 @@ def do_longlist(self, arg): self.error(err) return self._print_lines(lines, lineno, breaklist, self.curframe) + self._validate_file_mtime() do_ll = do_longlist def do_source(self, arg): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 8136c591a33001..7e6f276d355a14 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3711,6 +3711,25 @@ def test_file_modified_after_execution(self): self.assertIn("WARNING:", stdout) self.assertIn("was edited", stdout) + def test_file_modified_and_immediately_restarted(self): + script = """ + print("hello") + """ + + # the time.sleep is needed for low-resolution filesystems like HFS+ + commands = """ + filename = $_frame.f_code.co_filename + f = open(filename, "w") + f.write("print('goodbye')") + import time; time.sleep(1) + f.close() + restart + """ + + stdout, stderr = self.run_pdb_script(script, commands) + self.assertNotIn("WARNING:", stdout) + self.assertNotIn("was edited", stdout) + def test_file_modified_after_execution_with_multiple_instances(self): # the time.sleep is needed for low-resolution filesystems like HFS+ script = """ diff --git a/Misc/NEWS.d/next/Library/2024-10-16-15-55-50.gh-issue-125600.yMsJx0.rst b/Misc/NEWS.d/next/Library/2024-10-16-15-55-50.gh-issue-125600.yMsJx0.rst new file mode 100644 index 00000000000000..19bf4fbefb601b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-16-15-55-50.gh-issue-125600.yMsJx0.rst @@ -0,0 +1 @@ +Only show stale code warning in :mod:`pdb` when we display source code. From a0f5c8e6272a1fd5422892d773923b138e77ae5f Mon Sep 17 00:00:00 2001 From: Furkan Onder Date: Fri, 18 Oct 2024 05:08:34 +0300 Subject: [PATCH 228/247] gh-125620: Skip check_resource_tracker_death on NetBSD due to long wait for SIGKILL process termination (GH-125621) * Skip test_resource_tracker_sigkill on NetBSD --- Lib/test/_test_multiprocessing.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index a059a6b8340448..065fc27b770438 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5761,6 +5761,8 @@ def test_resource_tracker_sigterm(self): # Catchable signal (ignored by semaphore tracker) self.check_resource_tracker_death(signal.SIGTERM, False) + @unittest.skipIf(sys.platform.startswith("netbsd"), + "gh-125620: Skip on NetBSD due to long wait for SIGKILL process termination.") def test_resource_tracker_sigkill(self): # Uncatchable signal. self.check_resource_tracker_death(signal.SIGKILL, True) From d358425e6968858e52908794d15f37e62abc74ec Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Fri, 18 Oct 2024 14:26:29 +0200 Subject: [PATCH 229/247] gh-125682: Reject non-ASCII digits in the Python implementation of JSON decoder (GH-125687) --- Lib/json/scanner.py | 2 +- Lib/test/test_json/test_decode.py | 6 ++++++ .../Library/2024-10-18-09-51-29.gh-issue-125682.vsj4cU.rst | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-18-09-51-29.gh-issue-125682.vsj4cU.rst diff --git a/Lib/json/scanner.py b/Lib/json/scanner.py index 7a61cfc2d24dce..090897515fe2f3 100644 --- a/Lib/json/scanner.py +++ b/Lib/json/scanner.py @@ -9,7 +9,7 @@ __all__ = ['make_scanner'] NUMBER_RE = re.compile( - r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', + r'(-?(?:0|[1-9][0-9]*))(\.[0-9]+)?([eE][-+]?[0-9]+)?', (re.VERBOSE | re.MULTILINE | re.DOTALL)) def py_make_scanner(context): diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py index 79fb239b35d3f2..2250af964c022b 100644 --- a/Lib/test/test_json/test_decode.py +++ b/Lib/test/test_json/test_decode.py @@ -16,6 +16,12 @@ def test_float(self): self.assertIsInstance(rval, float) self.assertEqual(rval, 1.0) + def test_nonascii_digits_rejected(self): + # JSON specifies only ascii digits, see gh-125687 + for num in ["1\uff10", "0.\uff10", "0e\uff10"]: + with self.assertRaises(self.JSONDecodeError): + self.loads(num) + def test_bytes(self): self.assertEqual(self.loads(b"1"), 1) diff --git a/Misc/NEWS.d/next/Library/2024-10-18-09-51-29.gh-issue-125682.vsj4cU.rst b/Misc/NEWS.d/next/Library/2024-10-18-09-51-29.gh-issue-125682.vsj4cU.rst new file mode 100644 index 00000000000000..3eb2905ad8d810 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-18-09-51-29.gh-issue-125682.vsj4cU.rst @@ -0,0 +1,2 @@ +Reject non-ASCII digits in the Python implementation of :func:`json.loads` +conforming to the JSON specification. From df751363e386d1f77c5ba9515a5539902457d386 Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Fri, 18 Oct 2024 14:29:47 +0200 Subject: [PATCH 230/247] gh-125660: Reject invalid unicode escapes for Python implementation of JSON decoder (GH-125683) --- Lib/json/decoder.py | 9 +++++---- Lib/test/test_json/test_scanstring.py | 10 ++++++++++ .../2024-10-18-08-58-10.gh-issue-125660.sDdDqO.rst | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-18-08-58-10.gh-issue-125660.sDdDqO.rst diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py index d69a45d6793069..ff4bfcdcc407b9 100644 --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -50,17 +50,18 @@ def __reduce__(self): } +HEXDIGITS = re.compile(r'[0-9A-Fa-f]{4}', FLAGS) STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) BACKSLASH = { '"': '"', '\\': '\\', '/': '/', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', } -def _decode_uXXXX(s, pos): - esc = s[pos + 1:pos + 5] - if len(esc) == 4 and esc[1] not in 'xX': +def _decode_uXXXX(s, pos, _m=HEXDIGITS.match): + esc = _m(s, pos + 1) + if esc is not None: try: - return int(esc, 16) + return int(esc.group(), 16) except ValueError: pass msg = "Invalid \\uXXXX escape" diff --git a/Lib/test/test_json/test_scanstring.py b/Lib/test/test_json/test_scanstring.py index 2d3ee8a8bf0f92..cca556a3b95bab 100644 --- a/Lib/test/test_json/test_scanstring.py +++ b/Lib/test/test_json/test_scanstring.py @@ -116,6 +116,11 @@ def test_bad_escapes(self): '"\\u012z"', '"\\u0x12"', '"\\u0X12"', + '"\\u{0}"'.format("\uff10" * 4), + '"\\u 123"', + '"\\u-123"', + '"\\u+123"', + '"\\u1_23"', '"\\ud834\\"', '"\\ud834\\u"', '"\\ud834\\ud"', @@ -127,6 +132,11 @@ def test_bad_escapes(self): '"\\ud834\\udd2z"', '"\\ud834\\u0x20"', '"\\ud834\\u0X20"', + '"\\ud834\\u{0}"'.format("\uff10" * 4), + '"\\ud834\\u 123"', + '"\\ud834\\u-123"', + '"\\ud834\\u+123"', + '"\\ud834\\u1_23"', ] for s in bad_escapes: with self.assertRaises(self.JSONDecodeError, msg=s): diff --git a/Misc/NEWS.d/next/Library/2024-10-18-08-58-10.gh-issue-125660.sDdDqO.rst b/Misc/NEWS.d/next/Library/2024-10-18-08-58-10.gh-issue-125660.sDdDqO.rst new file mode 100644 index 00000000000000..74d76c7bddae7d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-18-08-58-10.gh-issue-125660.sDdDqO.rst @@ -0,0 +1 @@ +Reject invalid unicode escapes for Python implementation of :func:`json.loads`. From 10c4c95395771fb37e93811aaace42f026c16de5 Mon Sep 17 00:00:00 2001 From: "RUANG (Roy James)" Date: Fri, 18 Oct 2024 20:45:17 +0800 Subject: [PATCH 231/247] gh-123610: Added additional types to ctypes/wintypes.py (GH-124086) --- Lib/ctypes/wintypes.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/ctypes/wintypes.py b/Lib/ctypes/wintypes.py index 9c4e721438aad5..4beba0d19513e2 100644 --- a/Lib/ctypes/wintypes.py +++ b/Lib/ctypes/wintypes.py @@ -63,10 +63,16 @@ def __repr__(self): HBITMAP = HANDLE HBRUSH = HANDLE HCOLORSPACE = HANDLE +HCONV = HANDLE +HCONVLIST = HANDLE +HCURSOR = HANDLE HDC = HANDLE +HDDEDATA = HANDLE HDESK = HANDLE +HDROP = HANDLE HDWP = HANDLE HENHMETAFILE = HANDLE +HFILE = INT HFONT = HANDLE HGDIOBJ = HANDLE HGLOBAL = HANDLE @@ -82,9 +88,11 @@ def __repr__(self): HMONITOR = HANDLE HPALETTE = HANDLE HPEN = HANDLE +HRESULT = LONG HRGN = HANDLE HRSRC = HANDLE HSTR = HANDLE +HSZ = HANDLE HTASK = HANDLE HWINSTA = HANDLE HWND = HANDLE From cda0ec8e7c4e9a010e5f73c5afaf18f86cb27b97 Mon Sep 17 00:00:00 2001 From: Wulian Date: Fri, 18 Oct 2024 20:48:18 +0800 Subject: [PATCH 232/247] gh-124102: Clean up unsupported VS and WiX detections (GH-124784) --- PCbuild/pyproject.props | 5 ----- Tools/msi/README.txt | 20 +++++++++++--------- Tools/msi/wix.props | 2 -- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index 9c85e5efa4af4a..c65341179376ea 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -217,11 +217,6 @@ public override bool Execute() { - - - $(VCInstallDir)\redist\ - - <_RedistFiles Include="$(VCInstallDir)\Redist\MSVC\*\*.*" /> diff --git a/Tools/msi/README.txt b/Tools/msi/README.txt index 98e5ba039d2bcd..8ae156450d5240 100644 --- a/Tools/msi/README.txt +++ b/Tools/msi/README.txt @@ -61,18 +61,20 @@ the initial download size by separating them into their own MSIs. Building the Installer ====================== -Before building the installer, download extra build dependencies using -Tools\msi\get_externals.bat. (Note that this is in addition to the +Before building the installer, download the extra build dependencies +using Tools\msi\get_externals.bat. (Note that this is in addition to the similarly named file in PCbuild.) -One of the dependencies used in builds is WiX, a toolset that lets developers -create installers for Windows Installer, the Windows installation engine. +One of the dependencies used in the build process is WiX, a toolset that +allows developers to create installers for Windows Installer, the +Windows installation engine. If you're not using the copy of WiX +installed by Tools\msi\get_externals.bat, you'll need to set the +"WixInstallPath" environment variable before building. -Additionally, make sure "MSVC v14x - VS 20xx C++ ARM64 build tools" are -selected under "Desktop Development with C++" in "Visual Studio installer", -even if you are not building on ARM64. This is required because we have -upgraded to WiX-3.14, which requires these tools for Python 3.11 and later -versions. +Additionally, ensure that "MSVC v14x - VS 20xx C++ ARM64/ARM64EC build tools" +is selected under "Desktop Development with C++" in the "Visual Studio Installer", +even if you're not building on ARM64. This is required because we've upgraded +to WiX 3.14, which requires these tools for Python 3.10 and later versions. For testing, the installer should be built with the Tools/msi/build.bat script: diff --git a/Tools/msi/wix.props b/Tools/msi/wix.props index d8ced317d0ce81..707c8aeacb648d 100644 --- a/Tools/msi/wix.props +++ b/Tools/msi/wix.props @@ -5,8 +5,6 @@ $(MSBuildThisFileDirectory)\Wix\ $(ExternalsDir)\windows-installer\wix-314\ - $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Installer XML\3.10@InstallRoot) - $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows Installer XML\3.10@InstallRoot) $(WixInstallPath)\Wix.targets \ No newline at end of file From 2e950e341930ea79549137d4d3771d5edb940e65 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 18 Oct 2024 16:51:29 +0300 Subject: [PATCH 233/247] Add tests for time.strftime() with invalid format string (GH-125696) --- Lib/test/test_time.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index f8b99a9b6a63f5..d368f08b610870 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -18,7 +18,7 @@ except ImportError: _testinternalcapi = None -from test.support import skip_if_buggy_ucrt_strfptime +from test.support import skip_if_buggy_ucrt_strfptime, SuppressCrashReport # Max year is only limited by the size of C int. SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4 @@ -182,6 +182,17 @@ def test_strftime(self): self.assertRaises(TypeError, time.strftime, b'%S', tt) + def test_strftime_invalid_format(self): + tt = time.gmtime(self.t) + with SuppressCrashReport(): + for i in range(1, 128): + format = ' %' + chr(i) + with self.subTest(format=format): + try: + time.strftime(format, tt) + except ValueError as exc: + self.assertEqual(str(exc), 'Invalid format string') + def test_strftime_special(self): tt = time.gmtime(self.t) s1 = time.strftime('%c', tt) From 6d93690954daae9e9a368084765a4005f957686d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 18 Oct 2024 09:26:08 -0600 Subject: [PATCH 234/247] gh-125604: Move _Py_AuditHookEntry, etc. Out of pycore_runtime.h (gh-125605) This is essentially a cleanup, moving a handful of API declarations to the header files where they fit best, creating new ones when needed. We do the following: * add pycore_debug_offsets.h and move _Py_DebugOffsets, etc. there * inline struct _getargs_runtime_state and struct _gilstate_runtime_state in _PyRuntimeState * move struct _reftracer_runtime_state to the existing pycore_object_state.h * add pycore_audit.h and move to it _Py_AuditHookEntry , _PySys_Audit(), and _PySys_ClearAuditHooks * add audit.h and cpython/audit.h and move the existing audit-related API there *move the perfmap/trampoline API from cpython/sysmodule.h to cpython/ceval.h, and remove the now-empty cpython/sysmodule.h --- Include/Python.h | 1 + Include/audit.h | 30 +++ Include/cpython/audit.h | 8 + Include/cpython/ceval.h | 18 ++ Include/cpython/sysmodule.h | 22 -- Include/internal/pycore_audit.h | 35 +++ Include/internal/pycore_debug_offsets.h | 269 ++++++++++++++++++++++++ Include/internal/pycore_object_state.h | 8 + Include/internal/pycore_runtime.h | 197 ++--------------- Include/internal/pycore_runtime_init.h | 107 +--------- Include/internal/pycore_sysmodule.h | 10 - Include/sysmodule.h | 17 -- Makefile.pre.in | 5 +- Modules/_testexternalinspection.c | 4 +- Objects/object.c | 1 + PCbuild/pythoncore.vcxproj | 5 +- PCbuild/pythoncore.vcxproj.filters | 15 +- Python/bytecodes.c | 2 +- Python/ceval.c | 2 +- Python/errors.c | 3 +- Python/import.c | 3 +- Python/legacy_tracing.c | 2 +- Python/pylifecycle.c | 5 +- Python/pystate.c | 2 +- Python/pythonrun.c | 3 +- Python/sysmodule.c | 1 + 26 files changed, 429 insertions(+), 346 deletions(-) create mode 100644 Include/audit.h create mode 100644 Include/cpython/audit.h delete mode 100644 Include/cpython/sysmodule.h create mode 100644 Include/internal/pycore_audit.h create mode 100644 Include/internal/pycore_debug_offsets.h diff --git a/Include/Python.h b/Include/Python.h index e1abdd16f031fb..717e27feab62db 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -124,6 +124,7 @@ #include "pylifecycle.h" #include "ceval.h" #include "sysmodule.h" +#include "audit.h" #include "osmodule.h" #include "intrcheck.h" #include "import.h" diff --git a/Include/audit.h b/Include/audit.h new file mode 100644 index 00000000000000..793b7077e1027b --- /dev/null +++ b/Include/audit.h @@ -0,0 +1,30 @@ +#ifndef Py_AUDIT_H +#define Py_AUDIT_H +#ifdef __cplusplus +extern "C" { +#endif + + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 +PyAPI_FUNC(int) PySys_Audit( + const char *event, + const char *argFormat, + ...); + +PyAPI_FUNC(int) PySys_AuditTuple( + const char *event, + PyObject *args); +#endif + + +#ifndef Py_LIMITED_API +# define Py_CPYTHON_AUDIT_H +# include "cpython/audit.h" +# undef Py_CPYTHON_AUDIT_H +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_AUDIT_H */ diff --git a/Include/cpython/audit.h b/Include/cpython/audit.h new file mode 100644 index 00000000000000..3c5c7a8c06091d --- /dev/null +++ b/Include/cpython/audit.h @@ -0,0 +1,8 @@ +#ifndef Py_CPYTHON_AUDIT_H +# error "this header file must not be included directly" +#endif + + +typedef int(*Py_AuditHookFunction)(const char *, PyObject *, void *); + +PyAPI_FUNC(int) PySys_AddAuditHook(Py_AuditHookFunction, void*); diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index 78f7405661662f..ca8109e3248a8d 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -23,3 +23,21 @@ _PyEval_RequestCodeExtraIndex(freefunc f) { PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *); + + +// Trampoline API + +typedef struct { + FILE* perf_map; + PyThread_type_lock map_lock; +} PerfMapState; + +PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void); +PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry( + const void *code_addr, + unsigned int code_size, + const char *entry_name); +PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void); +PyAPI_FUNC(int) PyUnstable_CopyPerfMapFile(const char* parent_filename); +PyAPI_FUNC(int) PyUnstable_PerfTrampoline_CompileCode(PyCodeObject *); +PyAPI_FUNC(int) PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable); diff --git a/Include/cpython/sysmodule.h b/Include/cpython/sysmodule.h deleted file mode 100644 index a3ac07f538a94f..00000000000000 --- a/Include/cpython/sysmodule.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef Py_CPYTHON_SYSMODULE_H -# error "this header file must not be included directly" -#endif - -typedef int(*Py_AuditHookFunction)(const char *, PyObject *, void *); - -PyAPI_FUNC(int) PySys_AddAuditHook(Py_AuditHookFunction, void*); - -typedef struct { - FILE* perf_map; - PyThread_type_lock map_lock; -} PerfMapState; - -PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void); -PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry( - const void *code_addr, - unsigned int code_size, - const char *entry_name); -PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void); -PyAPI_FUNC(int) PyUnstable_CopyPerfMapFile(const char* parent_filename); -PyAPI_FUNC(int) PyUnstable_PerfTrampoline_CompileCode(PyCodeObject *); -PyAPI_FUNC(int) PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable); diff --git a/Include/internal/pycore_audit.h b/Include/internal/pycore_audit.h new file mode 100644 index 00000000000000..2811aaa6236123 --- /dev/null +++ b/Include/internal/pycore_audit.h @@ -0,0 +1,35 @@ +#ifndef Py_INTERNAL_AUDIT_H +#define Py_INTERNAL_AUDIT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +/* Runtime audit hook state */ + +typedef struct _Py_AuditHookEntry { + struct _Py_AuditHookEntry *next; + Py_AuditHookFunction hookCFunction; + void *userData; +} _Py_AuditHookEntry; + + +extern int _PySys_Audit( + PyThreadState *tstate, + const char *event, + const char *argFormat, + ...); + +// _PySys_ClearAuditHooks() must not be exported: use extern rather than +// PyAPI_FUNC(). We want minimal exposure of this function. +extern void _PySys_ClearAuditHooks(PyThreadState *tstate); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_AUDIT_H */ diff --git a/Include/internal/pycore_debug_offsets.h b/Include/internal/pycore_debug_offsets.h new file mode 100644 index 00000000000000..184f4b9360b6d3 --- /dev/null +++ b/Include/internal/pycore_debug_offsets.h @@ -0,0 +1,269 @@ +#ifndef Py_INTERNAL_DEBUG_OFFSETS_H +#define Py_INTERNAL_DEBUG_OFFSETS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +#define _Py_Debug_Cookie "xdebugpy" + +#ifdef Py_GIL_DISABLED +# define _Py_Debug_gilruntimestate_enabled offsetof(struct _gil_runtime_state, enabled) +# define _Py_Debug_Free_Threaded 1 +#else +# define _Py_Debug_gilruntimestate_enabled 0 +# define _Py_Debug_Free_Threaded 0 +#endif + + +typedef struct _Py_DebugOffsets { + char cookie[8]; + uint64_t version; + uint64_t free_threaded; + // Runtime state offset; + struct _runtime_state { + uint64_t size; + uint64_t finalizing; + uint64_t interpreters_head; + } runtime_state; + + // Interpreter state offset; + struct _interpreter_state { + uint64_t size; + uint64_t id; + uint64_t next; + uint64_t threads_head; + uint64_t gc; + uint64_t imports_modules; + uint64_t sysdict; + uint64_t builtins; + uint64_t ceval_gil; + uint64_t gil_runtime_state; + uint64_t gil_runtime_state_enabled; + uint64_t gil_runtime_state_locked; + uint64_t gil_runtime_state_holder; + } interpreter_state; + + // Thread state offset; + struct _thread_state{ + uint64_t size; + uint64_t prev; + uint64_t next; + uint64_t interp; + uint64_t current_frame; + uint64_t thread_id; + uint64_t native_thread_id; + uint64_t datastack_chunk; + uint64_t status; + } thread_state; + + // InterpreterFrame offset; + struct _interpreter_frame { + uint64_t size; + uint64_t previous; + uint64_t executable; + uint64_t instr_ptr; + uint64_t localsplus; + uint64_t owner; + } interpreter_frame; + + // Code object offset; + struct _code_object { + uint64_t size; + uint64_t filename; + uint64_t name; + uint64_t qualname; + uint64_t linetable; + uint64_t firstlineno; + uint64_t argcount; + uint64_t localsplusnames; + uint64_t localspluskinds; + uint64_t co_code_adaptive; + } code_object; + + // PyObject offset; + struct _pyobject { + uint64_t size; + uint64_t ob_type; + } pyobject; + + // PyTypeObject object offset; + struct _type_object { + uint64_t size; + uint64_t tp_name; + uint64_t tp_repr; + uint64_t tp_flags; + } type_object; + + // PyTuple object offset; + struct _tuple_object { + uint64_t size; + uint64_t ob_item; + uint64_t ob_size; + } tuple_object; + + // PyList object offset; + struct _list_object { + uint64_t size; + uint64_t ob_item; + uint64_t ob_size; + } list_object; + + // PyDict object offset; + struct _dict_object { + uint64_t size; + uint64_t ma_keys; + uint64_t ma_values; + } dict_object; + + // PyFloat object offset; + struct _float_object { + uint64_t size; + uint64_t ob_fval; + } float_object; + + // PyLong object offset; + struct _long_object { + uint64_t size; + uint64_t lv_tag; + uint64_t ob_digit; + } long_object; + + // PyBytes object offset; + struct _bytes_object { + uint64_t size; + uint64_t ob_size; + uint64_t ob_sval; + } bytes_object; + + // Unicode object offset; + struct _unicode_object { + uint64_t size; + uint64_t state; + uint64_t length; + uint64_t asciiobject_size; + } unicode_object; + + // GC runtime state offset; + struct _gc { + uint64_t size; + uint64_t collecting; + } gc; +} _Py_DebugOffsets; + + +#define _Py_DebugOffsets_INIT(debug_cookie) { \ + .cookie = debug_cookie, \ + .version = PY_VERSION_HEX, \ + .free_threaded = _Py_Debug_Free_Threaded, \ + .runtime_state = { \ + .size = sizeof(_PyRuntimeState), \ + .finalizing = offsetof(_PyRuntimeState, _finalizing), \ + .interpreters_head = offsetof(_PyRuntimeState, interpreters.head), \ + }, \ + .interpreter_state = { \ + .size = sizeof(PyInterpreterState), \ + .id = offsetof(PyInterpreterState, id), \ + .next = offsetof(PyInterpreterState, next), \ + .threads_head = offsetof(PyInterpreterState, threads.head), \ + .gc = offsetof(PyInterpreterState, gc), \ + .imports_modules = offsetof(PyInterpreterState, imports.modules), \ + .sysdict = offsetof(PyInterpreterState, sysdict), \ + .builtins = offsetof(PyInterpreterState, builtins), \ + .ceval_gil = offsetof(PyInterpreterState, ceval.gil), \ + .gil_runtime_state = offsetof(PyInterpreterState, _gil), \ + .gil_runtime_state_enabled = _Py_Debug_gilruntimestate_enabled, \ + .gil_runtime_state_locked = offsetof(PyInterpreterState, _gil.locked), \ + .gil_runtime_state_holder = offsetof(PyInterpreterState, _gil.last_holder), \ + }, \ + .thread_state = { \ + .size = sizeof(PyThreadState), \ + .prev = offsetof(PyThreadState, prev), \ + .next = offsetof(PyThreadState, next), \ + .interp = offsetof(PyThreadState, interp), \ + .current_frame = offsetof(PyThreadState, current_frame), \ + .thread_id = offsetof(PyThreadState, thread_id), \ + .native_thread_id = offsetof(PyThreadState, native_thread_id), \ + .datastack_chunk = offsetof(PyThreadState, datastack_chunk), \ + .status = offsetof(PyThreadState, _status), \ + }, \ + .interpreter_frame = { \ + .size = sizeof(_PyInterpreterFrame), \ + .previous = offsetof(_PyInterpreterFrame, previous), \ + .executable = offsetof(_PyInterpreterFrame, f_executable), \ + .instr_ptr = offsetof(_PyInterpreterFrame, instr_ptr), \ + .localsplus = offsetof(_PyInterpreterFrame, localsplus), \ + .owner = offsetof(_PyInterpreterFrame, owner), \ + }, \ + .code_object = { \ + .size = sizeof(PyCodeObject), \ + .filename = offsetof(PyCodeObject, co_filename), \ + .name = offsetof(PyCodeObject, co_name), \ + .qualname = offsetof(PyCodeObject, co_qualname), \ + .linetable = offsetof(PyCodeObject, co_linetable), \ + .firstlineno = offsetof(PyCodeObject, co_firstlineno), \ + .argcount = offsetof(PyCodeObject, co_argcount), \ + .localsplusnames = offsetof(PyCodeObject, co_localsplusnames), \ + .localspluskinds = offsetof(PyCodeObject, co_localspluskinds), \ + .co_code_adaptive = offsetof(PyCodeObject, co_code_adaptive), \ + }, \ + .pyobject = { \ + .size = sizeof(PyObject), \ + .ob_type = offsetof(PyObject, ob_type), \ + }, \ + .type_object = { \ + .size = sizeof(PyTypeObject), \ + .tp_name = offsetof(PyTypeObject, tp_name), \ + .tp_repr = offsetof(PyTypeObject, tp_repr), \ + .tp_flags = offsetof(PyTypeObject, tp_flags), \ + }, \ + .tuple_object = { \ + .size = sizeof(PyTupleObject), \ + .ob_item = offsetof(PyTupleObject, ob_item), \ + .ob_size = offsetof(PyTupleObject, ob_base.ob_size), \ + }, \ + .list_object = { \ + .size = sizeof(PyListObject), \ + .ob_item = offsetof(PyListObject, ob_item), \ + .ob_size = offsetof(PyListObject, ob_base.ob_size), \ + }, \ + .dict_object = { \ + .size = sizeof(PyDictObject), \ + .ma_keys = offsetof(PyDictObject, ma_keys), \ + .ma_values = offsetof(PyDictObject, ma_values), \ + }, \ + .float_object = { \ + .size = sizeof(PyFloatObject), \ + .ob_fval = offsetof(PyFloatObject, ob_fval), \ + }, \ + .long_object = { \ + .size = sizeof(PyLongObject), \ + .lv_tag = offsetof(PyLongObject, long_value.lv_tag), \ + .ob_digit = offsetof(PyLongObject, long_value.ob_digit), \ + }, \ + .bytes_object = { \ + .size = sizeof(PyBytesObject), \ + .ob_size = offsetof(PyBytesObject, ob_base.ob_size), \ + .ob_sval = offsetof(PyBytesObject, ob_sval), \ + }, \ + .unicode_object = { \ + .size = sizeof(PyUnicodeObject), \ + .state = offsetof(PyUnicodeObject, _base._base.state), \ + .length = offsetof(PyUnicodeObject, _base._base.length), \ + .asciiobject_size = sizeof(PyASCIIObject), \ + }, \ + .gc = { \ + .size = sizeof(struct _gc_runtime_state), \ + .collecting = offsetof(struct _gc_runtime_state, collecting), \ + }, \ +} + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_DEBUG_OFFSETS_H */ diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h index e7fa7c1f10d6d1..8a47a6d9e6eb0d 100644 --- a/Include/internal/pycore_object_state.h +++ b/Include/internal/pycore_object_state.h @@ -11,6 +11,14 @@ extern "C" { #include "pycore_freelist_state.h" // _Py_freelists #include "pycore_hashtable.h" // _Py_hashtable_t + +/* Reference tracer state */ +struct _reftracer_runtime_state { + PyRefTracer tracer_func; + void* tracer_data; +}; + + struct _py_object_runtime_state { #ifdef Py_REF_DEBUG Py_ssize_t interpreter_leaks; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index d4291b87261ae0..7f592aa6cf9f05 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -9,8 +9,10 @@ extern "C" { #endif #include "pycore_atexit.h" // struct _atexit_runtime_state +#include "pycore_audit.h" // _Py_AuditHookEntry #include "pycore_ceval_state.h" // struct _ceval_runtime_state -#include "pycore_crossinterp.h" // struct _xidregistry +#include "pycore_crossinterp.h" // struct _xidregistry +#include "pycore_debug_offsets.h" // _Py_DebugOffsets #include "pycore_faulthandler.h" // struct _faulthandler_runtime_state #include "pycore_floatobject.h" // struct _Py_float_runtime_state #include "pycore_import.h" // struct _import_runtime_state @@ -25,185 +27,12 @@ extern "C" { #include "pycore_typeobject.h" // struct _types_runtime_state #include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_state -struct _getargs_runtime_state { - struct _PyArg_Parser *static_parsers; -}; - -/* GIL state */ - -struct _gilstate_runtime_state { - /* bpo-26558: Flag to disable PyGILState_Check(). - If set to non-zero, PyGILState_Check() always return 1. */ - int check_enabled; - /* The single PyInterpreterState used by this process' - GILState implementation - */ - /* TODO: Given interp_main, it may be possible to kill this ref */ - PyInterpreterState *autoInterpreterState; -}; - -/* Runtime audit hook state */ - -#define _Py_Debug_Cookie "xdebugpy" - -#ifdef Py_GIL_DISABLED -# define _Py_Debug_gilruntimestate_enabled offsetof(struct _gil_runtime_state, enabled) -# define _Py_Debug_Free_Threaded 1 -#else -# define _Py_Debug_gilruntimestate_enabled 0 -# define _Py_Debug_Free_Threaded 0 -#endif -typedef struct _Py_AuditHookEntry { - struct _Py_AuditHookEntry *next; - Py_AuditHookFunction hookCFunction; - void *userData; -} _Py_AuditHookEntry; - -typedef struct _Py_DebugOffsets { - char cookie[8]; - uint64_t version; - uint64_t free_threaded; - // Runtime state offset; - struct _runtime_state { - uint64_t size; - uint64_t finalizing; - uint64_t interpreters_head; - } runtime_state; - - // Interpreter state offset; - struct _interpreter_state { - uint64_t size; - uint64_t id; - uint64_t next; - uint64_t threads_head; - uint64_t gc; - uint64_t imports_modules; - uint64_t sysdict; - uint64_t builtins; - uint64_t ceval_gil; - uint64_t gil_runtime_state; - uint64_t gil_runtime_state_enabled; - uint64_t gil_runtime_state_locked; - uint64_t gil_runtime_state_holder; - } interpreter_state; - - // Thread state offset; - struct _thread_state{ - uint64_t size; - uint64_t prev; - uint64_t next; - uint64_t interp; - uint64_t current_frame; - uint64_t thread_id; - uint64_t native_thread_id; - uint64_t datastack_chunk; - uint64_t status; - } thread_state; - - // InterpreterFrame offset; - struct _interpreter_frame { - uint64_t size; - uint64_t previous; - uint64_t executable; - uint64_t instr_ptr; - uint64_t localsplus; - uint64_t owner; - } interpreter_frame; - - // Code object offset; - struct _code_object { - uint64_t size; - uint64_t filename; - uint64_t name; - uint64_t qualname; - uint64_t linetable; - uint64_t firstlineno; - uint64_t argcount; - uint64_t localsplusnames; - uint64_t localspluskinds; - uint64_t co_code_adaptive; - } code_object; - - // PyObject offset; - struct _pyobject { - uint64_t size; - uint64_t ob_type; - } pyobject; - - // PyTypeObject object offset; - struct _type_object { - uint64_t size; - uint64_t tp_name; - uint64_t tp_repr; - uint64_t tp_flags; - } type_object; - - // PyTuple object offset; - struct _tuple_object { - uint64_t size; - uint64_t ob_item; - uint64_t ob_size; - } tuple_object; - - // PyList object offset; - struct _list_object { - uint64_t size; - uint64_t ob_item; - uint64_t ob_size; - } list_object; - - // PyDict object offset; - struct _dict_object { - uint64_t size; - uint64_t ma_keys; - uint64_t ma_values; - } dict_object; - - // PyFloat object offset; - struct _float_object { - uint64_t size; - uint64_t ob_fval; - } float_object; - - // PyLong object offset; - struct _long_object { - uint64_t size; - uint64_t lv_tag; - uint64_t ob_digit; - } long_object; - - // PyBytes object offset; - struct _bytes_object { - uint64_t size; - uint64_t ob_size; - uint64_t ob_sval; - } bytes_object; - - // Unicode object offset; - struct _unicode_object { - uint64_t size; - uint64_t state; - uint64_t length; - uint64_t asciiobject_size; - } unicode_object; - - // GC runtime state offset; - struct _gc { - uint64_t size; - uint64_t collecting; - } gc; -} _Py_DebugOffsets; - -/* Reference tracer state */ -struct _reftracer_runtime_state { - PyRefTracer tracer_func; - void* tracer_data; -}; /* Full Python runtime state */ /* _PyRuntimeState holds the global state for the CPython runtime. - That data is exposed in the internal API as a static variable (_PyRuntime). + That data is exported by the internal API as a global variable + (_PyRuntime, defined near the top of pylifecycle.c). */ typedef struct pyruntimestate { /* This field must be first to facilitate locating it by out of process @@ -299,8 +128,19 @@ typedef struct pyruntimestate { struct _import_runtime_state imports; struct _ceval_runtime_state ceval; - struct _gilstate_runtime_state gilstate; - struct _getargs_runtime_state getargs; + struct _gilstate_runtime_state { + /* bpo-26558: Flag to disable PyGILState_Check(). + If set to non-zero, PyGILState_Check() always return 1. */ + int check_enabled; + /* The single PyInterpreterState used by this process' + GILState implementation + */ + /* TODO: Given interp_main, it may be possible to kill this ref */ + PyInterpreterState *autoInterpreterState; + } gilstate; + struct _getargs_runtime_state { + struct _PyArg_Parser *static_parsers; + } getargs; struct _fileutils_state fileutils; struct _faulthandler_runtime_state faulthandler; struct _tracemalloc_runtime_state tracemalloc; @@ -404,6 +244,7 @@ _PyRuntimeState_SetFinalizing(_PyRuntimeState *runtime, PyThreadState *tstate) { } } + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index a17ba46966daa1..e99febab2f3d57 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_ceval_state.h" // _PyEval_RUNTIME_PERF_INIT +#include "pycore_debug_offsets.h" // _Py_DebugOffsets_INIT() #include "pycore_faulthandler.h" // _faulthandler_runtime_state_INIT #include "pycore_floatobject.h" // _py_float_format_unknown #include "pycore_function.h" @@ -32,111 +33,7 @@ extern PyTypeObject _PyExc_MemoryError; #define _PyRuntimeState_INIT(runtime, debug_cookie) \ { \ - .debug_offsets = { \ - .cookie = debug_cookie, \ - .version = PY_VERSION_HEX, \ - .free_threaded = _Py_Debug_Free_Threaded, \ - .runtime_state = { \ - .size = sizeof(_PyRuntimeState), \ - .finalizing = offsetof(_PyRuntimeState, _finalizing), \ - .interpreters_head = offsetof(_PyRuntimeState, interpreters.head), \ - }, \ - .interpreter_state = { \ - .size = sizeof(PyInterpreterState), \ - .id = offsetof(PyInterpreterState, id), \ - .next = offsetof(PyInterpreterState, next), \ - .threads_head = offsetof(PyInterpreterState, threads.head), \ - .gc = offsetof(PyInterpreterState, gc), \ - .imports_modules = offsetof(PyInterpreterState, imports.modules), \ - .sysdict = offsetof(PyInterpreterState, sysdict), \ - .builtins = offsetof(PyInterpreterState, builtins), \ - .ceval_gil = offsetof(PyInterpreterState, ceval.gil), \ - .gil_runtime_state = offsetof(PyInterpreterState, _gil), \ - .gil_runtime_state_enabled = _Py_Debug_gilruntimestate_enabled, \ - .gil_runtime_state_locked = offsetof(PyInterpreterState, _gil.locked), \ - .gil_runtime_state_holder = offsetof(PyInterpreterState, _gil.last_holder), \ - }, \ - .thread_state = { \ - .size = sizeof(PyThreadState), \ - .prev = offsetof(PyThreadState, prev), \ - .next = offsetof(PyThreadState, next), \ - .interp = offsetof(PyThreadState, interp), \ - .current_frame = offsetof(PyThreadState, current_frame), \ - .thread_id = offsetof(PyThreadState, thread_id), \ - .native_thread_id = offsetof(PyThreadState, native_thread_id), \ - .datastack_chunk = offsetof(PyThreadState, datastack_chunk), \ - .status = offsetof(PyThreadState, _status), \ - }, \ - .interpreter_frame = { \ - .size = sizeof(_PyInterpreterFrame), \ - .previous = offsetof(_PyInterpreterFrame, previous), \ - .executable = offsetof(_PyInterpreterFrame, f_executable), \ - .instr_ptr = offsetof(_PyInterpreterFrame, instr_ptr), \ - .localsplus = offsetof(_PyInterpreterFrame, localsplus), \ - .owner = offsetof(_PyInterpreterFrame, owner), \ - }, \ - .code_object = { \ - .size = sizeof(PyCodeObject), \ - .filename = offsetof(PyCodeObject, co_filename), \ - .name = offsetof(PyCodeObject, co_name), \ - .qualname = offsetof(PyCodeObject, co_qualname), \ - .linetable = offsetof(PyCodeObject, co_linetable), \ - .firstlineno = offsetof(PyCodeObject, co_firstlineno), \ - .argcount = offsetof(PyCodeObject, co_argcount), \ - .localsplusnames = offsetof(PyCodeObject, co_localsplusnames), \ - .localspluskinds = offsetof(PyCodeObject, co_localspluskinds), \ - .co_code_adaptive = offsetof(PyCodeObject, co_code_adaptive), \ - }, \ - .pyobject = { \ - .size = sizeof(PyObject), \ - .ob_type = offsetof(PyObject, ob_type), \ - }, \ - .type_object = { \ - .size = sizeof(PyTypeObject), \ - .tp_name = offsetof(PyTypeObject, tp_name), \ - .tp_repr = offsetof(PyTypeObject, tp_repr), \ - .tp_flags = offsetof(PyTypeObject, tp_flags), \ - }, \ - .tuple_object = { \ - .size = sizeof(PyTupleObject), \ - .ob_item = offsetof(PyTupleObject, ob_item), \ - .ob_size = offsetof(PyTupleObject, ob_base.ob_size), \ - }, \ - .list_object = { \ - .size = sizeof(PyListObject), \ - .ob_item = offsetof(PyListObject, ob_item), \ - .ob_size = offsetof(PyListObject, ob_base.ob_size), \ - }, \ - .dict_object = { \ - .size = sizeof(PyDictObject), \ - .ma_keys = offsetof(PyDictObject, ma_keys), \ - .ma_values = offsetof(PyDictObject, ma_values), \ - }, \ - .float_object = { \ - .size = sizeof(PyFloatObject), \ - .ob_fval = offsetof(PyFloatObject, ob_fval), \ - }, \ - .long_object = { \ - .size = sizeof(PyLongObject), \ - .lv_tag = offsetof(PyLongObject, long_value.lv_tag), \ - .ob_digit = offsetof(PyLongObject, long_value.ob_digit), \ - }, \ - .bytes_object = { \ - .size = sizeof(PyBytesObject), \ - .ob_size = offsetof(PyBytesObject, ob_base.ob_size), \ - .ob_sval = offsetof(PyBytesObject, ob_sval), \ - }, \ - .unicode_object = { \ - .size = sizeof(PyUnicodeObject), \ - .state = offsetof(PyUnicodeObject, _base._base.state), \ - .length = offsetof(PyUnicodeObject, _base._base.length), \ - .asciiobject_size = sizeof(PyASCIIObject), \ - }, \ - .gc = { \ - .size = sizeof(struct _gc_runtime_state), \ - .collecting = offsetof(struct _gc_runtime_state, collecting), \ - }, \ - }, \ + .debug_offsets = _Py_DebugOffsets_INIT(debug_cookie), \ .allocators = { \ .standard = _pymem_allocators_standard_INIT(runtime), \ .debug = _pymem_allocators_debug_INIT, \ diff --git a/Include/internal/pycore_sysmodule.h b/Include/internal/pycore_sysmodule.h index a1d795e284f6ac..99968df54a45f6 100644 --- a/Include/internal/pycore_sysmodule.h +++ b/Include/internal/pycore_sysmodule.h @@ -14,16 +14,6 @@ PyAPI_FUNC(PyObject*) _PySys_GetAttr(PyThreadState *tstate, PyObject *name); // Export for '_pickle' shared extension PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *); -extern int _PySys_Audit( - PyThreadState *tstate, - const char *event, - const char *argFormat, - ...); - -// _PySys_ClearAuditHooks() must not be exported: use extern rather than -// PyAPI_FUNC(). We want minimal exposure of this function. -extern void _PySys_ClearAuditHooks(PyThreadState *tstate); - extern int _PySys_SetAttr(PyObject *, PyObject *); extern int _PySys_ClearAttrString(PyInterpreterState *interp, diff --git a/Include/sysmodule.h b/Include/sysmodule.h index 5a0af2e1578eb7..c1d5f610fe08a5 100644 --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -21,23 +21,6 @@ Py_DEPRECATED(3.13) PyAPI_FUNC(void) PySys_ResetWarnOptions(void); PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 -PyAPI_FUNC(int) PySys_Audit( - const char *event, - const char *argFormat, - ...); - -PyAPI_FUNC(int) PySys_AuditTuple( - const char *event, - PyObject *args); -#endif - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_SYSMODULE_H -# include "cpython/sysmodule.h" -# undef Py_CPYTHON_SYSMODULE_H -#endif - #ifdef __cplusplus } #endif diff --git a/Makefile.pre.in b/Makefile.pre.in index 07c8a4d20142db..fb6f22d57397db 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1032,6 +1032,7 @@ python.worker.js: $(srcdir)/Tools/wasm/python.worker.js PYTHON_HEADERS= \ $(srcdir)/Include/Python.h \ $(srcdir)/Include/abstract.h \ + $(srcdir)/Include/audit.h \ $(srcdir)/Include/bltinmodule.h \ $(srcdir)/Include/boolobject.h \ $(srcdir)/Include/bytearrayobject.h \ @@ -1110,6 +1111,7 @@ PYTHON_HEADERS= \ $(PARSER_HEADERS) \ \ $(srcdir)/Include/cpython/abstract.h \ + $(srcdir)/Include/cpython/audit.h \ $(srcdir)/Include/cpython/bytearrayobject.h \ $(srcdir)/Include/cpython/bytesobject.h \ $(srcdir)/Include/cpython/cellobject.h \ @@ -1159,7 +1161,6 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/pythonrun.h \ $(srcdir)/Include/cpython/pythread.h \ $(srcdir)/Include/cpython/setobject.h \ - $(srcdir)/Include/cpython/sysmodule.h \ $(srcdir)/Include/cpython/traceback.h \ $(srcdir)/Include/cpython/tracemalloc.h \ $(srcdir)/Include/cpython/tupleobject.h \ @@ -1174,6 +1175,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_ast.h \ $(srcdir)/Include/internal/pycore_ast_state.h \ $(srcdir)/Include/internal/pycore_atexit.h \ + $(srcdir)/Include/internal/pycore_audit.h \ $(srcdir)/Include/internal/pycore_backoff.h \ $(srcdir)/Include/internal/pycore_bitutils.h \ $(srcdir)/Include/internal/pycore_blocks_output_buffer.h \ @@ -1193,6 +1195,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_context.h \ $(srcdir)/Include/internal/pycore_critical_section.h \ $(srcdir)/Include/internal/pycore_crossinterp.h \ + $(srcdir)/Include/internal/pycore_debug_offsets.h \ $(srcdir)/Include/internal/pycore_descrobject.h \ $(srcdir)/Include/internal/pycore_dict.h \ $(srcdir)/Include/internal/pycore_dict_state.h \ diff --git a/Modules/_testexternalinspection.c b/Modules/_testexternalinspection.c index 2476346777c319..0807d1e47b6736 100644 --- a/Modules/_testexternalinspection.c +++ b/Modules/_testexternalinspection.c @@ -51,7 +51,9 @@ # define Py_BUILD_CORE_MODULE 1 #endif #include "Python.h" -#include +#include // _Py_DebugOffsets +#include // FRAME_OWNED_BY_CSTACK +#include // Py_TAG_BITS #ifndef HAVE_PROCESS_VM_READV # define HAVE_PROCESS_VM_READV 0 diff --git a/Objects/object.c b/Objects/object.c index 4a4c5bf7d7f08a..1a15b70d3dc63f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -17,6 +17,7 @@ #include "pycore_memoryobject.h" // _PyManagedBuffer_Type #include "pycore_namespace.h" // _PyNamespace_Type #include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition +#include "pycore_object_state.h" // struct _reftracer_runtime_state #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_optimizer.h" // _PyUOpExecutor_Type, _PyUOpOptimizer_Type, ... #include "pycore_pyerrors.h" // _PyErr_Occurred() diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 3b33c6bf6bb91d..a4881e9256e4dd 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -128,6 +128,7 @@ + @@ -137,6 +138,7 @@ + @@ -185,7 +187,6 @@ - @@ -208,6 +209,7 @@ + @@ -227,6 +229,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index ee2930b10439a9..6b294683320a73 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -48,6 +48,9 @@ Include + + Include + Include @@ -354,6 +357,9 @@ Include\cpython + + Include\cpython + Include\cpython @@ -513,9 +519,6 @@ Include\cpython - - Include\cpython - Include\cpython @@ -552,6 +555,9 @@ Include\internal + + Include\internal + Include\internal @@ -603,6 +609,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e6525657cabc2b..c59a35c3e828ca 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -8,6 +8,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_audit.h" // _PySys_Audit() #include "pycore_backoff.h" #include "pycore_cell.h" // PyCell_GetRef() #include "pycore_ceval.h" @@ -27,7 +28,6 @@ #include "pycore_range.h" // _PyRangeIterObject #include "pycore_setobject.h" // _PySet_NextEntry() #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs -#include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_typeobject.h" // _PySuper_Lookup() diff --git a/Python/ceval.c b/Python/ceval.c index 98d95b28488fd0..55e5eba25eaa21 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_audit.h" // _PySys_Audit() #include "pycore_backoff.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_cell.h" // PyCell_GetRef() @@ -26,7 +27,6 @@ #include "pycore_range.h" // _PyRangeIterObject #include "pycore_setobject.h" // _PySet_Update() #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs -#include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_typeobject.h" // _PySuper_Lookup() #include "pycore_uop_ids.h" // Uops diff --git a/Python/errors.c b/Python/errors.c index 9e2a3ce062a6fe..7f3b4aabc432d7 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -2,12 +2,13 @@ /* Error handling */ #include "Python.h" +#include "pycore_audit.h" // _PySys_Audit() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_initconfig.h" // _PyStatus_ERR() #include "pycore_pyerrors.h" // _PyErr_Format() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() -#include "pycore_sysmodule.h" // _PySys_Audit() +#include "pycore_sysmodule.h" // _PySys_GetAttr() #include "pycore_traceback.h" // _PyTraceBack_FromFrame() #ifdef MS_WINDOWS diff --git a/Python/import.c b/Python/import.c index acf849f14562b9..d8ad37b2422795 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1,6 +1,7 @@ /* Module definition and import implementation */ #include "Python.h" +#include "pycore_audit.h" // _PySys_Audit() #include "pycore_ceval.h" #include "pycore_hashtable.h" // _Py_hashtable_new_full() #include "pycore_import.h" // _PyImport_BootstrapImp() @@ -14,7 +15,7 @@ #include "pycore_pylifecycle.h" #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_sysmodule.h" // _PySys_Audit() +#include "pycore_sysmodule.h" // _PySys_ClearAttrString() #include "pycore_time.h" // _PyTime_AsMicroseconds() #include "pycore_weakref.h" // _PyWeakref_GET_REF() diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index 1436921a19b768..45af275f1f6dce 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -3,9 +3,9 @@ */ #include "Python.h" +#include "pycore_audit.h" // _PySys_Audit() #include "pycore_ceval.h" // export _PyEval_SetProfile() #include "pycore_object.h" -#include "pycore_sysmodule.h" // _PySys_Audit() #include "opcode.h" #include diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5fb9c4f7c719fe..b8f424854ecb86 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2,6 +2,7 @@ #include "Python.h" +#include "pycore_audit.h" // _PySys_ClearAuditHooks() #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_ceval.h" // _PyEval_FiniGIL() #include "pycore_codecs.h" // _PyCodec_Lookup() @@ -26,7 +27,7 @@ #include "pycore_runtime_init.h" // _PyRuntimeState_INIT #include "pycore_setobject.h" // _PySet_NextEntry() #include "pycore_sliceobject.h" // _PySlice_Fini() -#include "pycore_sysmodule.h" // _PySys_ClearAuditHooks() +#include "pycore_sysmodule.h" // _PySys_GetAttr() #include "pycore_traceback.h" // _Py_DumpTracebackThreads() #include "pycore_uniqueid.h" // _PyObject_FinalizeUniqueIdPool() #include "pycore_typeobject.h" // _PyTypes_InitTypes() @@ -78,6 +79,7 @@ static void wait_for_thread_shutdown(PyThreadState *tstate); static void finalize_subinterpreters(void); static void call_ll_exitfuncs(_PyRuntimeState *runtime); + /* The following places the `_PyRuntime` structure in a location that can be * found without any external information. This is meant to ease access to the * interpreter state for various runtime debugging tools, but is *not* an @@ -107,6 +109,7 @@ __attribute__ ((section (".PyRuntime"))) = _PyRuntimeState_INIT(_PyRuntime, _Py_Debug_Cookie); _Py_COMP_DIAG_POP + static int runtime_initialized = 0; PyStatus diff --git a/Python/pystate.c b/Python/pystate.c index e3812cba41d9c2..7df872cd6d7d8a 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_audit.h" // _Py_AuditHookEntry #include "pycore_ceval.h" #include "pycore_code.h" // stats #include "pycore_critical_section.h" // _PyCriticalSection_Resume() @@ -18,7 +19,6 @@ #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" #include "pycore_runtime_init.h" // _PyRuntimeState_INIT -#include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_obmalloc.h" // _PyMem_obmalloc_state_on_heap() #include "pycore_uniqueid.h" // _PyObject_FinalizePerThreadRefcounts() diff --git a/Python/pythonrun.c b/Python/pythonrun.c index b67597113ead45..fc0f11bc4e8af4 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -13,6 +13,7 @@ #include "Python.h" #include "pycore_ast.h" // PyAST_mod2obj() +#include "pycore_audit.h" // _PySys_Audit() #include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_compile.h" // _PyAST_Compile() #include "pycore_interp.h" // PyInterpreterState.importlib @@ -22,7 +23,7 @@ #include "pycore_pylifecycle.h" // _Py_FdIsInteractive() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_pythonrun.h" // export _PyRun_InteractiveLoopObject() -#include "pycore_sysmodule.h" // _PySys_Audit() +#include "pycore_sysmodule.h" // _PySys_GetAttr() #include "pycore_traceback.h" // _PyTraceBack_Print() #include "errcode.h" // E_EOF diff --git a/Python/sysmodule.c b/Python/sysmodule.c index ac343a8048e008..8b9209324002ce 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -15,6 +15,7 @@ Data members: */ #include "Python.h" +#include "pycore_audit.h" // _Py_AuditHookEntry #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_SetAsyncGenFinalizer() #include "pycore_dict.h" // _PyDict_GetItemWithError() From f8ba9fb2ce6690d2dd05b356583e8e4790badad7 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Fri, 18 Oct 2024 17:09:34 +0100 Subject: [PATCH 235/247] gh-125703: Correctly honour tracemalloc hooks on specialized DECREF paths (#125704) --- Include/internal/pycore_object.h | 5 +++++ .../2024-10-18-16-00-10.gh-issue-125703.QRoqMo.rst | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-18-16-00-10.gh-issue-125703.QRoqMo.rst diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index ad1a7d7e120519..96f6d61e1c620b 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -208,6 +208,11 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) #ifdef Py_TRACE_REFS _Py_ForgetReference(op); #endif + struct _reftracer_runtime_state *tracer = &_PyRuntime.ref_tracer; + if (tracer->tracer_func != NULL) { + void* data = tracer->tracer_data; + tracer->tracer_func(op, PyRefTracer_DESTROY, data); + } destruct(op); } } diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-18-16-00-10.gh-issue-125703.QRoqMo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-18-16-00-10.gh-issue-125703.QRoqMo.rst new file mode 100644 index 00000000000000..7cbfa725e78cef --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-18-16-00-10.gh-issue-125703.QRoqMo.rst @@ -0,0 +1,2 @@ +Correctly honour :mod:`tracemalloc` hooks in specialized ``Py_DECREF`` +paths. Patch by Pablo Galindo From c8fd4b12e3db49d795de55f74d9bac445c059f1b Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 18 Oct 2024 15:51:29 -0400 Subject: [PATCH 236/247] gh-125207: Fix MSVC 1935 build with JIT (#125209) * gh-125207: Use {0} array initializers * Simplify, as suggested in PR * Revert change to explicitly specify length --- Python/jit.c | 2 +- Tools/jit/_stencils.py | 2 +- Tools/jit/_writer.py | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Python/jit.c b/Python/jit.c index 234fc7dda83231..963bde2303dc2c 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -469,7 +469,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz // Loop once to find the total compiled size: size_t code_size = 0; size_t data_size = 0; - jit_state state = {}; + jit_state state = {0}; group = &trampoline; code_size += group->code_size; data_size += group->data_size; diff --git a/Tools/jit/_stencils.py b/Tools/jit/_stencils.py index bbb52f391f4b01..e4b2bf6e4702b3 100644 --- a/Tools/jit/_stencils.py +++ b/Tools/jit/_stencils.py @@ -339,7 +339,7 @@ def _get_trampoline_mask(self) -> str: word = bitmask & ((1 << 32) - 1) trampoline_mask.append(f"{word:#04x}") bitmask >>= 32 - return "{" + ", ".join(trampoline_mask) + "}" + return "{" + (", ".join(trampoline_mask) or "0") + "}" def as_c(self, opname: str) -> str: """Dump this hole as a StencilGroup initializer.""" diff --git a/Tools/jit/_writer.py b/Tools/jit/_writer.py index 7b99d10310a645..4e7f614b0e9d23 100644 --- a/Tools/jit/_writer.py +++ b/Tools/jit/_writer.py @@ -32,8 +32,11 @@ def _dump_footer( yield "};" yield "" yield f"static const void * const symbols_map[{max(len(symbols), 1)}] = {{" - for symbol, ordinal in symbols.items(): - yield f" [{ordinal}] = &{symbol}," + if symbols: + for symbol, ordinal in symbols.items(): + yield f" [{ordinal}] = &{symbol}," + else: + yield " 0" yield "};" From 322f14eeff9e3b5853eaac3233f7580ca0214cf8 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 18 Oct 2024 16:05:12 -0600 Subject: [PATCH 237/247] gh-124694: In test_interpreter_pool, Restore the Asyncio Event Loop Policy During Cleanup (gh-125708) This resolves a failure on the android buildbot. --- .../test_interpreter_pool.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 0de03c0d669399..5264b1bb6e9c75 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -282,6 +282,19 @@ def test_idle_thread_reuse(self): class AsyncioTest(InterpretersMixin, testasyncio_utils.TestCase): + @classmethod + def setUpClass(cls): + # Most uses of asyncio will implicitly call set_event_loop_policy() + # with the default policy if a policy hasn't been set already. + # If that happens in a test, like here, we'll end up with a failure + # when --fail-env-changed is used. That's why the other tests that + # use asyncio are careful to set the policy back to None and why + # we're careful to do so here. We also validate that no other + # tests left a policy in place, just in case. + policy = support.maybe_get_event_loop_policy() + assert policy is None, policy + cls.addClassCleanup(lambda: asyncio.set_event_loop_policy(None)) + def setUp(self): super().setUp() self.loop = asyncio.new_event_loop() From 2bb7ab7ad364ec804eab8ed6867df01ece887240 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 19 Oct 2024 04:59:22 +0100 Subject: [PATCH 238/247] GH-125277: Increase minimum supported Sphinx to 7.2.6 (#125368) --- .github/workflows/reusable-docs.yml | 2 +- Doc/conf.py | 2 +- Doc/requirements-oldest-sphinx.txt | 30 +++++++++---------- ...-10-10-23-46-54.gh-issue-125277.QAby09.rst | 2 ++ 4 files changed, 19 insertions(+), 17 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2024-10-10-23-46-54.gh-issue-125277.QAby09.rst diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 3809f24dcc977e..39a97392e898aa 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -84,7 +84,7 @@ jobs: - name: 'Set up Python' uses: actions/setup-python@v5 with: - python-version: '3.12' # known to work with Sphinx 6.2.1 + python-version: '3.13' # known to work with Sphinx 7.2.6 cache: 'pip' cache-dependency-path: 'Doc/requirements-oldest-sphinx.txt' - name: 'Install build dependencies' diff --git a/Doc/conf.py b/Doc/conf.py index 839beaad08bebd..db8fb9a9a68c6b 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -90,7 +90,7 @@ highlight_language = 'python3' # Minimum version of sphinx required -needs_sphinx = '6.2.1' +needs_sphinx = '7.2.6' # Create table of contents entries for domain objects (e.g. functions, classes, # attributes, etc.). Default is True. diff --git a/Doc/requirements-oldest-sphinx.txt b/Doc/requirements-oldest-sphinx.txt index 068fe0cb426ecd..3483faea6b56cb 100644 --- a/Doc/requirements-oldest-sphinx.txt +++ b/Doc/requirements-oldest-sphinx.txt @@ -7,29 +7,29 @@ blurb python-docs-theme>=2022.1 # Generated from: -# pip install "Sphinx~=6.2.1" +# pip install "Sphinx~=7.2.6" # pip freeze # -# Sphinx 6.2.1 comes from ``needs_sphinx = '6.2.1'`` in ``Doc/conf.py``. +# Sphinx 7.2.6 comes from ``needs_sphinx = '7.2.6'`` in ``Doc/conf.py``. alabaster==0.7.16 -Babel==2.15.0 -certifi==2024.7.4 -charset-normalizer==3.3.2 -docutils==0.19 -idna==3.7 +Babel==2.16.0 +certifi==2024.8.30 +charset-normalizer==3.4.0 +docutils==0.20.1 +idna==3.10 imagesize==1.4.1 Jinja2==3.1.4 -MarkupSafe==2.1.5 +MarkupSafe==3.0.1 packaging==24.1 Pygments==2.18.0 requests==2.32.3 snowballstemmer==2.2.0 -Sphinx==6.2.1 -sphinxcontrib-applehelp==1.0.8 -sphinxcontrib-devhelp==1.0.6 -sphinxcontrib-htmlhelp==2.0.5 +Sphinx==7.2.6 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.7 -sphinxcontrib-serializinghtml==1.1.10 -urllib3==2.2.2 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +urllib3==2.2.3 diff --git a/Misc/NEWS.d/next/Documentation/2024-10-10-23-46-54.gh-issue-125277.QAby09.rst b/Misc/NEWS.d/next/Documentation/2024-10-10-23-46-54.gh-issue-125277.QAby09.rst new file mode 100644 index 00000000000000..fcd6e22c27b5f4 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2024-10-10-23-46-54.gh-issue-125277.QAby09.rst @@ -0,0 +1,2 @@ +Require Sphinx 7.2.6 or later to build the Python documentation. +Patch by Adam Turner. From 84074a4fd810948350cec5500e77dc974cb5433d Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 19 Oct 2024 01:26:46 -0700 Subject: [PATCH 239/247] GH-99749: Add What's New entry for GH-124456 (GH-125671) --- Doc/whatsnew/3.14.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index feb65f244827ad..ad841538ccc547 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -210,6 +210,11 @@ argparse interpreter was instructed to find the ``__main__`` module code. (Contributed by Serhiy Storchaka and Alyssa Coghlan in :gh:`66436`.) +* Introduced the optional *suggest_on_error* parameter to + :class:`argparse.ArgumentParser`, enabling suggestions for argument choices + and subparser names if mistyped by the user. + (Contributed by Savannah Ostrowski in :gh:`124456`) + ast --- From a7443a1735c33d5758b47ac9b8a1c34bac4ef994 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 19 Oct 2024 11:29:51 +0300 Subject: [PATCH 240/247] gh-52551: Use wcsftime() to implement time.strftime() on Windows (GH-125658) --- Lib/test/test_strftime.py | 3 +-- .../Library/2024-10-17-20-36-06.gh-issue-52551.EIVNYY.rst | 1 + Modules/timemodule.c | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-17-20-36-06.gh-issue-52551.EIVNYY.rst diff --git a/Lib/test/test_strftime.py b/Lib/test/test_strftime.py index cebfc8927862a7..752e31359cf206 100644 --- a/Lib/test/test_strftime.py +++ b/Lib/test/test_strftime.py @@ -183,8 +183,7 @@ class Y1900Tests(unittest.TestCase): def test_y_before_1900(self): # Issue #13674, #19634 t = (1899, 1, 1, 0, 0, 0, 0, 0, 0) - if (sys.platform == "win32" - or sys.platform.startswith(("aix", "sunos", "solaris"))): + if sys.platform.startswith(("aix", "sunos", "solaris")): with self.assertRaises(ValueError): time.strftime("%y", t) else: diff --git a/Misc/NEWS.d/next/Library/2024-10-17-20-36-06.gh-issue-52551.EIVNYY.rst b/Misc/NEWS.d/next/Library/2024-10-17-20-36-06.gh-issue-52551.EIVNYY.rst new file mode 100644 index 00000000000000..48d3d93c3d72af --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-17-20-36-06.gh-issue-52551.EIVNYY.rst @@ -0,0 +1 @@ +Use :c:func:`!wcsftime` to implement :func:`time.strftime` on Windows. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index b9d114ada0dfcd..340011fc08b551 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -739,10 +739,6 @@ checktm(struct tm* buf) return 1; } -#ifdef MS_WINDOWS - /* wcsftime() doesn't format correctly time zones, see issue #10653 */ -# undef HAVE_WCSFTIME -#endif #define STRFTIME_FORMAT_CODES \ "Commonly used format codes:\n\ \n\ From 4b421e8aca7f2dccc5ac8604b78589941dd7974c Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 19 Oct 2024 12:49:14 +0100 Subject: [PATCH 241/247] gh-125522: Fix bare except in test_math.testTan (#125544) --- Lib/test/test_math.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index e2e2a419c7778c..fecafd53aa6e6f 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1902,7 +1902,7 @@ def testTan(self): try: self.assertTrue(math.isnan(math.tan(INF))) self.assertTrue(math.isnan(math.tan(NINF))) - except: + except ValueError: self.assertRaises(ValueError, math.tan, INF) self.assertRaises(ValueError, math.tan, NINF) self.assertTrue(math.isnan(math.tan(NAN))) From 2a378dba987e125521b678364f0cd44b92dd5d52 Mon Sep 17 00:00:00 2001 From: Julien Date: Sat, 19 Oct 2024 13:34:41 -0400 Subject: [PATCH 242/247] gh-125398: Convert paths in venv activate script when using Git Bash under Windows (GH-125399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Convert paths in venv activate script when using Git Bash under Windows With https://github.com/python/cpython/pull/112508 the check to converts paths when running on Windows was changed from using the non-posix environment variable `$OSTYPE` to using `uname` instead. However this missed the fact that when running under Git Bash on Windows, uname reports `MINGW*` (`$OSTYPE` is still `msys`). This results in `$PATH` being set to something like `D:\a\github-actions-shells\github-actions-shells\venv/Scripts:…`, instead of `/d/a/github-actions-shells/github-actions-shells/venv/Scripts`. Notably, the Git Bash is the bash shell that’s used for GitHub Actions Windows runners, and ships with VSCode. --- Lib/venv/scripts/common/activate | 4 ++-- .../Library/2024-10-13-15-04-58.gh-issue-125398.UW7Ndv.rst | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-13-15-04-58.gh-issue-125398.UW7Ndv.rst diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate index 4593799b7e9b0e..44f137672e9d2e 100644 --- a/Lib/venv/scripts/common/activate +++ b/Lib/venv/scripts/common/activate @@ -38,8 +38,8 @@ deactivate nondestructive # on Windows, a path can contain colons and backslashes and has to be converted: case "$(uname)" in - CYGWIN*|MSYS*) - # transform D:\path\to\venv to /d/path/to/venv on MSYS + CYGWIN*|MSYS*|MINGW*) + # transform D:\path\to\venv to /d/path/to/venv on MSYS and MINGW # and to /cygdrive/d/path/to/venv on Cygwin VIRTUAL_ENV=$(cygpath "__VENV_DIR__") export VIRTUAL_ENV diff --git a/Misc/NEWS.d/next/Library/2024-10-13-15-04-58.gh-issue-125398.UW7Ndv.rst b/Misc/NEWS.d/next/Library/2024-10-13-15-04-58.gh-issue-125398.UW7Ndv.rst new file mode 100644 index 00000000000000..a188b35e1fbdbc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-13-15-04-58.gh-issue-125398.UW7Ndv.rst @@ -0,0 +1 @@ +Fix the conversion of the :envvar:`!VIRTUAL_ENV` path in the activate script in :mod:`venv` when running in Git Bash for Windows. From 4c53b2577531c77193430cdcd66ad6385fcda81f Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sat, 19 Oct 2024 17:16:36 -0400 Subject: [PATCH 243/247] gh-124984: Enhance `ssl` thread safety (#124993) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make SSL objects thread safe in Free Theaded build by using critical sections. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_ssl.py | 51 + ...-10-04-22-43-48.gh-issue-124984.xjMv9b.rst | 1 + Modules/_ssl.c | 683 ++++++--- Modules/clinic/_ssl.c.h | 1347 +++++++++++++++-- 4 files changed, 1767 insertions(+), 315 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-04-22-43-48.gh-issue-124984.xjMv9b.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index b93fa0ed99f8ce..de5110a1cc4b6d 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -4,6 +4,7 @@ import unittest import unittest.mock from ast import literal_eval +from threading import Thread from test import support from test.support import import_helper from test.support import os_helper @@ -277,11 +278,19 @@ def test_wrap_socket(sock, *, return context.wrap_socket(sock, **kwargs) +USE_SAME_TEST_CONTEXT = False +_TEST_CONTEXT = None + def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True): """Create context client_context, server_context, hostname = testing_context() """ + global _TEST_CONTEXT + if USE_SAME_TEST_CONTEXT: + if _TEST_CONTEXT is not None: + return _TEST_CONTEXT + if server_cert == SIGNED_CERTFILE: hostname = SIGNED_CERTFILE_HOSTNAME elif server_cert == SIGNED_CERTFILE2: @@ -299,6 +308,10 @@ def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True): if server_chain: server_context.load_verify_locations(SIGNING_CA) + if USE_SAME_TEST_CONTEXT: + if _TEST_CONTEXT is not None: + _TEST_CONTEXT = client_context, server_context, hostname + return client_context, server_context, hostname @@ -2801,6 +2814,44 @@ def test_echo(self): 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context', str(e.exception)) + @unittest.skipUnless(support.Py_GIL_DISABLED, "test is only useful if the GIL is disabled") + def test_ssl_in_multiple_threads(self): + # See GH-124984: OpenSSL is not thread safe. + threads = [] + + global USE_SAME_TEST_CONTEXT + USE_SAME_TEST_CONTEXT = True + try: + for func in ( + self.test_echo, + self.test_alpn_protocols, + self.test_getpeercert, + self.test_crl_check, + self.test_check_hostname_idn, + self.test_wrong_cert_tls12, + self.test_wrong_cert_tls13, + ): + # Be careful with the number of threads here. + # Too many can result in failing tests. + for num in range(5): + with self.subTest(func=func, num=num): + threads.append(Thread(target=func)) + + with threading_helper.catch_threading_exception() as cm: + for thread in threads: + with self.subTest(thread=thread): + thread.start() + + for thread in threads: + with self.subTest(thread=thread): + thread.join() + if cm.exc_value is not None: + # Some threads can skip their test + if not isinstance(cm.exc_value, unittest.SkipTest): + raise cm.exc_value + finally: + USE_SAME_TEST_CONTEXT = False + def test_getpeercert(self): if support.verbose: sys.stdout.write("\n") diff --git a/Misc/NEWS.d/next/Library/2024-10-04-22-43-48.gh-issue-124984.xjMv9b.rst b/Misc/NEWS.d/next/Library/2024-10-04-22-43-48.gh-issue-124984.xjMv9b.rst new file mode 100644 index 00000000000000..dd0a55a6854c25 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-04-22-43-48.gh-issue-124984.xjMv9b.rst @@ -0,0 +1 @@ +Fixed thread safety in :mod:`ssl` in the free-threaded build. OpenSSL operations are now protected by a per-object lock. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index f2d3b331226a7a..62a94314512dd9 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -51,7 +51,6 @@ PySSL_BEGIN_ALLOW_THREADS_S(_save); #define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); } - #if defined(HAVE_POLL_H) #include #elif defined(HAVE_SYS_POLL_H) @@ -376,9 +375,6 @@ class _ssl.SSLSession "PySSLSession *" "get_state_type(type)->PySSLSession_Type" static int PySSL_select(PySocketSockObject *s, int writing, PyTime_t timeout); -static int PySSL_set_owner(PySSLSocket *, PyObject *, void *); -static int PySSL_set_session(PySSLSocket *, PyObject *, void *); - typedef enum { SOCKET_IS_NONBLOCKING, SOCKET_IS_BLOCKING, @@ -616,6 +612,7 @@ PySSL_SetError(PySSLSocket *sslsock, const char *filename, int lineno) _sslmodulestate *state = get_state_sock(sslsock); type = state->PySSLErrorObject; + // ERR functions are thread local, no need to lock them. e = ERR_peek_last_error(); if (sslsock->ssl != NULL) { @@ -926,13 +923,13 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, } } if (owner && owner != Py_None) { - if (PySSL_set_owner(self, owner, NULL) == -1) { + if (_ssl__SSLSocket_owner_set(self, owner, NULL) == -1) { Py_DECREF(self); return NULL; } } if (session && session != Py_None) { - if (PySSL_set_session(self, session, NULL) == -1) { + if (_ssl__SSLSocket_session_set(self, session, NULL) == -1) { Py_DECREF(self); return NULL; } @@ -945,12 +942,13 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, /* SSL object methods */ /*[clinic input] +@critical_section _ssl._SSLSocket.do_handshake [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) -/*[clinic end generated code: output=6c0898a8936548f6 input=d2d737de3df018c8]*/ +/*[clinic end generated code: output=6c0898a8936548f6 input=65619a7a4bea3176]*/ { int ret; _PySSLError err; @@ -1820,6 +1818,7 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path) /*[clinic input] +@critical_section _ssl._SSLSocket.getpeercert der as binary_mode: bool = False / @@ -1837,7 +1836,7 @@ return the certificate even if it wasn't validated. static PyObject * _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode) -/*[clinic end generated code: output=1f0ab66dfb693c88 input=c0fbe802e57629b7]*/ +/*[clinic end generated code: output=1f0ab66dfb693c88 input=e35af55fa5f9bab8]*/ { int verification; X509 *peer_cert; @@ -1867,13 +1866,14 @@ _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode) } /*[clinic input] +@critical_section _ssl._SSLSocket.get_verified_chain [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_get_verified_chain_impl(PySSLSocket *self) -/*[clinic end generated code: output=802421163cdc3110 input=5fb0714f77e2bd51]*/ +/*[clinic end generated code: output=802421163cdc3110 input=83035fe238ec057b]*/ { /* borrowed reference */ STACK_OF(X509) *chain = SSL_get0_verified_chain(self->ssl); @@ -1884,13 +1884,14 @@ _ssl__SSLSocket_get_verified_chain_impl(PySSLSocket *self) } /*[clinic input] +@critical_section _ssl._SSLSocket.get_unverified_chain [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_get_unverified_chain_impl(PySSLSocket *self) -/*[clinic end generated code: output=5acdae414e13f913 input=78c33c360c635cb5]*/ +/*[clinic end generated code: output=5acdae414e13f913 input=079f8ff5c205cb3b]*/ { PyObject *retval; /* borrowed reference */ @@ -2020,12 +2021,13 @@ cipher_to_dict(const SSL_CIPHER *cipher) } /*[clinic input] +@critical_section _ssl._SSLSocket.shared_ciphers [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) -/*[clinic end generated code: output=3d174ead2e42c4fd input=0bfe149da8fe6306]*/ +/*[clinic end generated code: output=3d174ead2e42c4fd input=869645271e3bc6d0]*/ { STACK_OF(SSL_CIPHER) *server_ciphers; STACK_OF(SSL_CIPHER) *client_ciphers; @@ -2069,12 +2071,13 @@ _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) } /*[clinic input] +@critical_section _ssl._SSLSocket.cipher [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_cipher_impl(PySSLSocket *self) -/*[clinic end generated code: output=376417c16d0e5815 input=548fb0e27243796d]*/ +/*[clinic end generated code: output=376417c16d0e5815 input=39e180269a36f486]*/ { const SSL_CIPHER *current; @@ -2087,12 +2090,13 @@ _ssl__SSLSocket_cipher_impl(PySSLSocket *self) } /*[clinic input] +@critical_section _ssl._SSLSocket.version [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_version_impl(PySSLSocket *self) -/*[clinic end generated code: output=178aed33193b2cdb input=900186a503436fd6]*/ +/*[clinic end generated code: output=178aed33193b2cdb input=2732bc3f7f597d09]*/ { const char *version; @@ -2109,12 +2113,13 @@ _ssl__SSLSocket_version_impl(PySSLSocket *self) } /*[clinic input] +@critical_section _ssl._SSLSocket.selected_alpn_protocol [clinic start generated code]*/ static PyObject * _ssl__SSLSocket_selected_alpn_protocol_impl(PySSLSocket *self) -/*[clinic end generated code: output=ec33688b303d250f input=442de30e35bc2913]*/ +/*[clinic end generated code: output=ec33688b303d250f input=f0b53506c9acdf8c]*/ { const unsigned char *out; unsigned int outlen; @@ -2152,13 +2157,29 @@ _ssl__SSLSocket_compression_impl(PySSLSocket *self) #endif } -static PySSLContext *PySSL_get_context(PySSLSocket *self, void *closure) { - return (PySSLContext*)Py_NewRef(self->ctx); +/*[clinic input] +@critical_section +@getter +_ssl._SSLSocket.context +[clinic start generated code]*/ + +static PyObject * +_ssl__SSLSocket_context_get_impl(PySSLSocket *self) +/*[clinic end generated code: output=d23e82f72f32e3d7 input=25aa82e4d9fa344a]*/ +{ + return Py_NewRef(self->ctx); } -static int PySSL_set_context(PySSLSocket *self, PyObject *value, - void *closure) { +/*[clinic input] +@critical_section +@setter +_ssl._SSLSocket.context +[clinic start generated code]*/ +static int +_ssl__SSLSocket_context_set_impl(PySSLSocket *self, PyObject *value) +/*[clinic end generated code: output=6b0a6cc5cf33d9fe input=48ece77724fd9dd4]*/ +{ if (PyObject_TypeCheck(value, self->ctx->state->PySSLContext_Type)) { Py_SETREF(self->ctx, (PySSLContext *)Py_NewRef(value)); SSL_set_SSL_CTX(self->ssl, self->ctx->ctx); @@ -2175,37 +2196,47 @@ static int PySSL_set_context(PySSLSocket *self, PyObject *value, return 0; } -PyDoc_STRVAR(PySSL_set_context_doc, -"_setter_context(ctx)\n\ -\ -This changes the context associated with the SSLSocket. This is typically\n\ -used from within a callback function set by the sni_callback\n\ -on the SSLContext to change the certificate information associated with the\n\ -SSLSocket before the cryptographic exchange handshake messages\n"); +/*[clinic input] +@critical_section +@getter +_ssl._SSLSocket.server_side +Whether this is a server-side socket. +[clinic start generated code]*/ static PyObject * -PySSL_get_server_side(PySSLSocket *self, void *c) +_ssl__SSLSocket_server_side_get_impl(PySSLSocket *self) +/*[clinic end generated code: output=ae51e372489148e3 input=b09b320510bc7cae]*/ { return PyBool_FromLong(self->socket_type == PY_SSL_SERVER); } -PyDoc_STRVAR(PySSL_get_server_side_doc, -"Whether this is a server-side socket."); +/*[clinic input] +@critical_section +@getter +_ssl._SSLSocket.server_hostname + +The currently set server hostname (for SNI). +[clinic start generated code]*/ static PyObject * -PySSL_get_server_hostname(PySSLSocket *self, void *c) +_ssl__SSLSocket_server_hostname_get_impl(PySSLSocket *self) +/*[clinic end generated code: output=1f40ea5a076de8e7 input=55d12a1dc6634b08]*/ { if (self->server_hostname == NULL) Py_RETURN_NONE; return Py_NewRef(self->server_hostname); } -PyDoc_STRVAR(PySSL_get_server_hostname_doc, -"The currently set server hostname (for SNI)."); +/*[clinic input] +@critical_section +@getter +_ssl._SSLSocket.owner +[clinic start generated code]*/ static PyObject * -PySSL_get_owner(PySSLSocket *self, void *c) +_ssl__SSLSocket_owner_get_impl(PySSLSocket *self) +/*[clinic end generated code: output=1f278cb930382927 input=bc2861ff3cf1402e]*/ { if (self->owner == NULL) { Py_RETURN_NONE; @@ -2217,8 +2248,15 @@ PySSL_get_owner(PySSLSocket *self, void *c) return owner; } +/*[clinic input] +@critical_section +@setter +_ssl._SSLSocket.owner +[clinic start generated code]*/ + static int -PySSL_set_owner(PySSLSocket *self, PyObject *value, void *c) +_ssl__SSLSocket_owner_set_impl(PySSLSocket *self, PyObject *value) +/*[clinic end generated code: output=2e3924498f2b6cde input=875666fd32367a73]*/ { Py_XSETREF(self->owner, PyWeakref_NewRef(value, NULL)); if (self->owner == NULL) @@ -2226,10 +2264,6 @@ PySSL_set_owner(PySSLSocket *self, PyObject *value, void *c) return 0; } -PyDoc_STRVAR(PySSL_get_owner_doc, -"The Python-level owner of this object.\ -Passed as \"self\" in servername callback."); - static int PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg) { @@ -2343,6 +2377,7 @@ PySSL_select(PySocketSockObject *s, int writing, PyTime_t timeout) } /*[clinic input] +@critical_section _ssl._SSLSocket.write b: Py_buffer / @@ -2354,7 +2389,7 @@ Returns the number of bytes written. static PyObject * _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) -/*[clinic end generated code: output=aa7a6be5527358d8 input=77262d994fe5100a]*/ +/*[clinic end generated code: output=aa7a6be5527358d8 input=967b5feeae641a26]*/ { size_t count = 0; int retval; @@ -2452,6 +2487,7 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) } /*[clinic input] +@critical_section _ssl._SSLSocket.pending Returns the number of already decrypted bytes available for read, pending on the connection. @@ -2459,7 +2495,7 @@ Returns the number of already decrypted bytes available for read, pending on the static PyObject * _ssl__SSLSocket_pending_impl(PySSLSocket *self) -/*[clinic end generated code: output=983d9fecdc308a83 input=2b77487d6dfd597f]*/ +/*[clinic end generated code: output=983d9fecdc308a83 input=32ab982a254e8866]*/ { int count = 0; _PySSLError err; @@ -2477,6 +2513,7 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self) } /*[clinic input] +@critical_section _ssl._SSLSocket.read size as len: Py_ssize_t [ @@ -2490,7 +2527,7 @@ Read up to size bytes from the SSL socket. static PyObject * _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, int group_right_1, Py_buffer *buffer) -/*[clinic end generated code: output=49b16e6406023734 input=ec48bf622be1c4a1]*/ +/*[clinic end generated code: output=49b16e6406023734 input=80ed30436df01a71]*/ { PyObject *dest = NULL; char *mem; @@ -2619,6 +2656,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, } /*[clinic input] +@critical_section _ssl._SSLSocket.shutdown Does the SSL shutdown handshake with the remote end. @@ -2626,7 +2664,7 @@ Does the SSL shutdown handshake with the remote end. static PyObject * _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) -/*[clinic end generated code: output=ca1aa7ed9d25ca42 input=11d39e69b0a2bf4a]*/ +/*[clinic end generated code: output=ca1aa7ed9d25ca42 input=98d9635cd4e16514]*/ { _PySSLError err; int sockstate, nonblocking, ret; @@ -2738,6 +2776,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) } /*[clinic input] +@critical_section _ssl._SSLSocket.get_channel_binding cb_type: str = "tls-unique" @@ -2751,7 +2790,7 @@ Only 'tls-unique' channel binding data from RFC 5929 is supported. static PyObject * _ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self, const char *cb_type) -/*[clinic end generated code: output=34bac9acb6a61d31 input=08b7e43b99c17d41]*/ +/*[clinic end generated code: output=34bac9acb6a61d31 input=e008004fc08744db]*/ { char buf[PySSL_CB_MAXLEN]; size_t len; @@ -2783,6 +2822,7 @@ _ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self, } /*[clinic input] +@critical_section _ssl._SSLSocket.verify_client_post_handshake Initiate TLS 1.3 post-handshake authentication @@ -2790,7 +2830,7 @@ Initiate TLS 1.3 post-handshake authentication static PyObject * _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self) -/*[clinic end generated code: output=532147f3b1341425 input=6bfa874810a3d889]*/ +/*[clinic end generated code: output=532147f3b1341425 input=42b5bb1f0981eda1]*/ { #if defined(PySSL_HAVE_POST_HS_AUTH) int err = SSL_verify_client_post_handshake(self->ssl); @@ -2806,8 +2846,16 @@ _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self) #endif } +/*[clinic input] +@critical_section +@getter +_ssl._SSLSocket.session +[clinic start generated code]*/ + static PyObject * -PySSL_get_session(PySSLSocket *self, void *closure) { +_ssl__SSLSocket_session_get_impl(PySSLSocket *self) +/*[clinic end generated code: output=a5cd5755b35da670 input=b9792df9255a9f63]*/ +{ /* get_session can return sessions from a server-side connection, * it does not check for handshake done or client socket. */ PySSLSession *pysess; @@ -2819,6 +2867,8 @@ PySSL_get_session(PySSLSocket *self, void *closure) { } pysess = PyObject_GC_New(PySSLSession, self->ctx->state->PySSLSession_Type); if (pysess == NULL) { + // It's not possible for another thread to access this, so + // we don't need to lock it. SSL_SESSION_free(session); return NULL; } @@ -2830,8 +2880,16 @@ PySSL_get_session(PySSLSocket *self, void *closure) { return (PyObject *)pysess; } -static int PySSL_set_session(PySSLSocket *self, PyObject *value, - void *closure) { +/*[clinic input] +@critical_section +@setter +_ssl._SSLSocket.session +[clinic start generated code]*/ + +static int +_ssl__SSLSocket_session_set_impl(PySSLSocket *self, PyObject *value) +/*[clinic end generated code: output=a3fa2ddd7c2d54a2 input=5fa5f921640db98b]*/ +{ PySSLSession *pysess; if (!Py_IS_TYPE(value, get_state_sock(self)->PySSLSession_Type)) { @@ -2855,6 +2913,7 @@ static int PySSL_set_session(PySSLSocket *self, PyObject *value, "Cannot set session after handshake."); return -1; } + if (SSL_set_session(self->ssl, pysess->session) == 0) { _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); return -1; @@ -2862,36 +2921,29 @@ static int PySSL_set_session(PySSLSocket *self, PyObject *value, return 0; } -PyDoc_STRVAR(PySSL_set_session_doc, -"_setter_session(session)\n\ -\ -Get / set SSLSession."); +/*[clinic input] +@critical_section +@getter +_ssl._SSLSocket.session_reused + +Was the client session reused during handshake? +[clinic start generated code]*/ static PyObject * -PySSL_get_session_reused(PySSLSocket *self, void *closure) { - if (SSL_session_reused(self->ssl)) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } +_ssl__SSLSocket_session_reused_get_impl(PySSLSocket *self) +/*[clinic end generated code: output=c8916909bcb80893 input=cec8bfec73a4461e]*/ +{ + int res = SSL_session_reused(self->ssl); + return res ? Py_True : Py_False; } -PyDoc_STRVAR(PySSL_get_session_reused_doc, -"Was the client session reused during handshake?"); - static PyGetSetDef ssl_getsetlist[] = { - {"context", (getter) PySSL_get_context, - (setter) PySSL_set_context, PySSL_set_context_doc}, - {"server_side", (getter) PySSL_get_server_side, NULL, - PySSL_get_server_side_doc}, - {"server_hostname", (getter) PySSL_get_server_hostname, NULL, - PySSL_get_server_hostname_doc}, - {"owner", (getter) PySSL_get_owner, (setter) PySSL_set_owner, - PySSL_get_owner_doc}, - {"session", (getter) PySSL_get_session, - (setter) PySSL_set_session, PySSL_set_session_doc}, - {"session_reused", (getter) PySSL_get_session_reused, NULL, - PySSL_get_session_reused_doc}, + _SSL__SSLSOCKET_CONTEXT_GETSETDEF + _SSL__SSLSOCKET_SERVER_SIDE_GETSETDEF + _SSL__SSLSOCKET_SERVER_HOSTNAME_GETSETDEF + _SSL__SSLSOCKET_OWNER_GETSETDEF + _SSL__SSLSOCKET_SESSION_GETSETDEF + _SSL__SSLSOCKET_SESSION_REUSED_GETSETDEF {NULL}, /* sentinel */ }; @@ -2964,6 +3016,7 @@ _set_verify_mode(PySSLContext *self, enum py_ssl_cert_requirements n) } /*[clinic input] +@critical_section @classmethod _ssl._SSLContext.__new__ protocol as proto_version: int @@ -2972,7 +3025,7 @@ _ssl._SSLContext.__new__ static PyObject * _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) -/*[clinic end generated code: output=2cf0d7a0741b6bd1 input=8d58a805b95fc534]*/ +/*[clinic end generated code: output=2cf0d7a0741b6bd1 input=6fc79e62ae9d143c]*/ { PySSLContext *self; uint64_t options; @@ -3042,6 +3095,10 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) return NULL; } + // This is the constructor, no need to lock it, because + // no other thread can be touching this object yet. + // (Technically, we can't even lock if we wanted to, as the + // lock hasn't been initialized yet.) PySSL_BEGIN_ALLOW_THREADS ctx = SSL_CTX_new(method); PySSL_END_ALLOW_THREADS @@ -3208,6 +3265,7 @@ context_dealloc(PySSLContext *self) } /*[clinic input] +@critical_section _ssl._SSLContext.set_ciphers cipherlist: str / @@ -3215,7 +3273,7 @@ _ssl._SSLContext.set_ciphers static PyObject * _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist) -/*[clinic end generated code: output=3a3162f3557c0f3f input=a7ac931b9f3ca7fc]*/ +/*[clinic end generated code: output=3a3162f3557c0f3f input=40b583cded5c6ff9]*/ { int ret = SSL_CTX_set_cipher_list(self->ctx, cipherlist); if (ret == 0) { @@ -3231,12 +3289,13 @@ _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist) } /*[clinic input] +@critical_section _ssl._SSLContext.get_ciphers [clinic start generated code]*/ static PyObject * _ssl__SSLContext_get_ciphers_impl(PySSLContext *self) -/*[clinic end generated code: output=a56e4d68a406dfc4 input=a2aadc9af89b79c5]*/ +/*[clinic end generated code: output=a56e4d68a406dfc4 input=d7fff51631a260ae]*/ { SSL *ssl = NULL; STACK_OF(SSL_CIPHER) *sk = NULL; @@ -3311,6 +3370,7 @@ _selectALPN_cb(SSL *s, } /*[clinic input] +@critical_section _ssl._SSLContext._set_alpn_protocols protos: Py_buffer / @@ -3319,7 +3379,7 @@ _ssl._SSLContext._set_alpn_protocols static PyObject * _ssl__SSLContext__set_alpn_protocols_impl(PySSLContext *self, Py_buffer *protos) -/*[clinic end generated code: output=87599a7f76651a9b input=9bba964595d519be]*/ +/*[clinic end generated code: output=87599a7f76651a9b input=b5096b186e49287d]*/ { if ((size_t)protos->len > UINT_MAX) { PyErr_Format(PyExc_OverflowError, @@ -3329,25 +3389,34 @@ _ssl__SSLContext__set_alpn_protocols_impl(PySSLContext *self, PyMem_Free(self->alpn_protocols); self->alpn_protocols = PyMem_Malloc(protos->len); - if (!self->alpn_protocols) + if (!self->alpn_protocols) { return PyErr_NoMemory(); + } memcpy(self->alpn_protocols, protos->buf, protos->len); self->alpn_protocols_len = (unsigned int)protos->len; - - if (SSL_CTX_set_alpn_protos(self->ctx, self->alpn_protocols, self->alpn_protocols_len)) + if (SSL_CTX_set_alpn_protos(self->ctx, self->alpn_protocols, self->alpn_protocols_len)) { return PyErr_NoMemory(); + } SSL_CTX_set_alpn_select_cb(self->ctx, _selectALPN_cb, self); Py_RETURN_NONE; } +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.verify_mode +[clinic start generated code]*/ + static PyObject * -get_verify_mode(PySSLContext *self, void *c) +_ssl__SSLContext_verify_mode_get_impl(PySSLContext *self) +/*[clinic end generated code: output=3e788736cc7229bc input=7e3c7f4454121d0a]*/ { /* ignore SSL_VERIFY_CLIENT_ONCE and SSL_VERIFY_POST_HANDSHAKE */ int mask = (SSL_VERIFY_NONE | SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT); - switch (SSL_CTX_get_verify_mode(self->ctx) & mask) { + int verify_mode = SSL_CTX_get_verify_mode(self->ctx); + switch (verify_mode & mask) { case SSL_VERIFY_NONE: return PyLong_FromLong(PY_SSL_CERT_NONE); case SSL_VERIFY_PEER: @@ -3360,11 +3429,18 @@ get_verify_mode(PySSLContext *self, void *c) return NULL; } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.verify_mode +[clinic start generated code]*/ + static int -set_verify_mode(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_verify_mode_set_impl(PySSLContext *self, PyObject *value) +/*[clinic end generated code: output=d698e16c58db3118 input=3ee60057c3a22378]*/ { int n; - if (!PyArg_Parse(arg, "i", &n)) + if (!PyArg_Parse(value, "i", &n)) return -1; if (n == PY_SSL_CERT_NONE && self->check_hostname) { PyErr_SetString(PyExc_ValueError, @@ -3375,8 +3451,15 @@ set_verify_mode(PySSLContext *self, PyObject *arg, void *c) return _set_verify_mode(self, n); } +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.verify_flags +[clinic start generated code]*/ + static PyObject * -get_verify_flags(PySSLContext *self, void *c) +_ssl__SSLContext_verify_flags_get_impl(PySSLContext *self) +/*[clinic end generated code: output=fbbf8ba28ad6e56e input=c1ec36d610b3f391]*/ { X509_VERIFY_PARAM *param; unsigned long flags; @@ -3386,13 +3469,20 @@ get_verify_flags(PySSLContext *self, void *c) return PyLong_FromUnsignedLong(flags); } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.verify_flags +[clinic start generated code]*/ + static int -set_verify_flags(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_verify_flags_set_impl(PySSLContext *self, PyObject *value) +/*[clinic end generated code: output=a3e3b2a0ce6c2e99 input=b2a0c42583d4f34e]*/ { X509_VERIFY_PARAM *param; unsigned long new_flags, flags, set, clear; - if (!PyArg_Parse(arg, "k", &new_flags)) + if (!PyArg_Parse(value, "k", &new_flags)) return -1; param = SSL_CTX_get0_param(self->ctx); flags = X509_VERIFY_PARAM_get_flags(param); @@ -3500,8 +3590,15 @@ set_min_max_proto_version(PySSLContext *self, PyObject *arg, int what) return 0; } +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.minimum_version +[clinic start generated code]*/ + static PyObject * -get_minimum_version(PySSLContext *self, void *c) +_ssl__SSLContext_minimum_version_get_impl(PySSLContext *self) +/*[clinic end generated code: output=27fa8382276635ed input=6832821e7e974d40]*/ { int v = SSL_CTX_get_min_proto_version(self->ctx); if (v == 0) { @@ -3510,14 +3607,29 @@ get_minimum_version(PySSLContext *self, void *c) return PyLong_FromLong(v); } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.minimum_version +[clinic start generated code]*/ + static int -set_minimum_version(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_minimum_version_set_impl(PySSLContext *self, + PyObject *value) +/*[clinic end generated code: output=482e82f7372afb78 input=2c64724901a514b3]*/ { - return set_min_max_proto_version(self, arg, 0); + return set_min_max_proto_version(self, value, 0); } +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.maximum_version +[clinic start generated code]*/ + static PyObject * -get_maximum_version(PySSLContext *self, void *c) +_ssl__SSLContext_maximum_version_get_impl(PySSLContext *self) +/*[clinic end generated code: output=889249475112826a input=2b9e4c2d45f16b14]*/ { int v = SSL_CTX_get_max_proto_version(self->ctx); if (v == 0) { @@ -3526,24 +3638,51 @@ get_maximum_version(PySSLContext *self, void *c) return PyLong_FromLong(v); } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.maximum_version +[clinic start generated code]*/ + static int -set_maximum_version(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_maximum_version_set_impl(PySSLContext *self, + PyObject *value) +/*[clinic end generated code: output=4c0eed3042ca20d5 input=fe27e9fbbeb73c89]*/ { - return set_min_max_proto_version(self, arg, 1); + return set_min_max_proto_version(self, value, 1); } -#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.num_tickets +[clinic start generated code]*/ + static PyObject * -get_num_tickets(PySSLContext *self, void *c) +_ssl__SSLContext_num_tickets_get_impl(PySSLContext *self) +/*[clinic end generated code: output=3d06d016318846c9 input=1dee26d75163c073]*/ { - return PyLong_FromSize_t(SSL_CTX_get_num_tickets(self->ctx)); + // Clinic seems to be misbehaving when the comment is wrapped with in directive +#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) + PyObject *res = PyLong_FromSize_t(SSL_CTX_get_num_tickets(self->ctx)); + return res; +#else + return 0; +#endif } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.num_tickets +[clinic start generated code]*/ + static int -set_num_tickets(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_num_tickets_set_impl(PySSLContext *self, PyObject *value) +/*[clinic end generated code: output=ced81b46f3beab09 input=6ef8067ac55607e7]*/ { long num; - if (!PyArg_Parse(arg, "l", &num)) + if (!PyArg_Parse(value, "l", &num)) return -1; if (num < 0) { PyErr_SetString(PyExc_ValueError, "value must be non-negative"); @@ -3561,27 +3700,44 @@ set_num_tickets(PySSLContext *self, PyObject *arg, void *c) return 0; } -PyDoc_STRVAR(PySSLContext_num_tickets_doc, -"Control the number of TLSv1.3 session tickets"); -#endif /* defined(TLS1_3_VERSION) */ +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.security_level +[clinic start generated code]*/ static PyObject * -get_security_level(PySSLContext *self, void *c) +_ssl__SSLContext_security_level_get_impl(PySSLContext *self) +/*[clinic end generated code: output=56ece09e6a9572d0 input=a0416598e07c3183]*/ { - return PyLong_FromLong(SSL_CTX_get_security_level(self->ctx)); + PyObject *res = PyLong_FromLong(SSL_CTX_get_security_level(self->ctx)); + return res; } -PyDoc_STRVAR(PySSLContext_security_level_doc, "The current security level"); + +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.options +[clinic start generated code]*/ static PyObject * -get_options(PySSLContext *self, void *c) +_ssl__SSLContext_options_get_impl(PySSLContext *self) +/*[clinic end generated code: output=3dfa6a74837f525b input=f5a2805c7cda6f25]*/ { uint64_t options = SSL_CTX_get_options(self->ctx); Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(options)); return PyLong_FromUnsignedLongLong(options); } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.options +[clinic start generated code]*/ + static int -set_options(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_options_set_impl(PySSLContext *self, PyObject *value) +/*[clinic end generated code: output=92ca34731ece5dbb input=2b94bf789e9ae5dd]*/ { PyObject *new_opts_obj; unsigned long long new_opts_arg; @@ -3591,7 +3747,7 @@ set_options(PySSLContext *self, PyObject *arg, void *c) SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3 ); - if (!PyArg_Parse(arg, "O!", &PyLong_Type, &new_opts_obj)) { + if (!PyArg_Parse(value, "O!", &PyLong_Type, &new_opts_obj)) { return -1; } new_opts_arg = PyLong_AsUnsignedLongLong(new_opts_obj); @@ -3620,19 +3776,33 @@ set_options(PySSLContext *self, PyObject *arg, void *c) return 0; } +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext._host_flags +[clinic start generated code]*/ + static PyObject * -get_host_flags(PySSLContext *self, void *c) +_ssl__SSLContext__host_flags_get_impl(PySSLContext *self) +/*[clinic end generated code: output=0f9db6654ce32582 input=8e3c49499eefd0e5]*/ { return PyLong_FromUnsignedLong(self->hostflags); } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext._host_flags +[clinic start generated code]*/ + static int -set_host_flags(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext__host_flags_set_impl(PySSLContext *self, PyObject *value) +/*[clinic end generated code: output=1ed6f4027aaf2e3e input=28caf1fb9c32f6cb]*/ { X509_VERIFY_PARAM *param; unsigned int new_flags = 0; - if (!PyArg_Parse(arg, "I", &new_flags)) + if (!PyArg_Parse(value, "I", &new_flags)) return -1; param = SSL_CTX_get0_param(self->ctx); @@ -3641,20 +3811,35 @@ set_host_flags(PySSLContext *self, PyObject *arg, void *c) return 0; } +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.check_hostname +[clinic start generated code]*/ + static PyObject * -get_check_hostname(PySSLContext *self, void *c) +_ssl__SSLContext_check_hostname_get_impl(PySSLContext *self) +/*[clinic end generated code: output=e046d6eeefc76063 input=1b8341e705f9ecf5]*/ { return PyBool_FromLong(self->check_hostname); } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.check_hostname +[clinic start generated code]*/ + static int -set_check_hostname(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_check_hostname_set_impl(PySSLContext *self, PyObject *value) +/*[clinic end generated code: output=0e767b4784e7dc3f input=e6a771cb5919f74d]*/ { int check_hostname; - if (!PyArg_Parse(arg, "p", &check_hostname)) + if (!PyArg_Parse(value, "p", &check_hostname)) return -1; + int verify_mode = check_hostname ? SSL_CTX_get_verify_mode(self->ctx) : 0; if (check_hostname && - SSL_CTX_get_verify_mode(self->ctx) == SSL_VERIFY_NONE) { + verify_mode == SSL_VERIFY_NONE) { /* check_hostname = True sets verify_mode = CERT_REQUIRED */ if (_set_verify_mode(self, PY_SSL_CERT_REQUIRED) == -1) { return -1; @@ -3694,8 +3879,16 @@ set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) { } #endif +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.protocol +[clinic start generated code]*/ + static PyObject * -get_protocol(PySSLContext *self, void *c) { +_ssl__SSLContext_protocol_get_impl(PySSLContext *self) +/*[clinic end generated code: output=a9a48febc16cee22 input=c9f5fa1a2bd4b8a8]*/ +{ return PyLong_FromLong(self->protocol); } @@ -3809,6 +4002,7 @@ _password_callback(char *buf, int size, int rwflag, void *userdata) } /*[clinic input] +@critical_section _ssl._SSLContext.load_cert_chain certfile: object keyfile: object = None @@ -3819,7 +4013,7 @@ _ssl._SSLContext.load_cert_chain static PyObject * _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, PyObject *keyfile, PyObject *password) -/*[clinic end generated code: output=9480bc1c380e2095 input=30bc7e967ea01a58]*/ +/*[clinic end generated code: output=9480bc1c380e2095 input=6c7c5e8b73e4264b]*/ { PyObject *certfile_bytes = NULL, *keyfile_bytes = NULL; pem_password_cb *orig_passwd_cb = SSL_CTX_get_default_passwd_cb(self->ctx); @@ -4013,6 +4207,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, /*[clinic input] +@critical_section _ssl._SSLContext.load_verify_locations cafile: object = None capath: object = None @@ -4025,7 +4220,7 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self, PyObject *cafile, PyObject *capath, PyObject *cadata) -/*[clinic end generated code: output=454c7e41230ca551 input=42ecfe258233e194]*/ +/*[clinic end generated code: output=454c7e41230ca551 input=b178852b41618414]*/ { PyObject *cafile_bytes = NULL, *capath_bytes = NULL; const char *cafile_buf = NULL, *capath_buf = NULL; @@ -4141,6 +4336,7 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self, } /*[clinic input] +@critical_section _ssl._SSLContext.load_dh_params path as filepath: object / @@ -4148,8 +4344,8 @@ _ssl._SSLContext.load_dh_params [clinic start generated code]*/ static PyObject * -_ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath) -/*[clinic end generated code: output=1c8e57a38e055af0 input=c8871f3c796ae1d6]*/ +_ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath) +/*[clinic end generated code: output=dd74b3c524dd2723 input=832769a0734b8c4d]*/ { FILE *f; DH *dh; @@ -4182,6 +4378,7 @@ _ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath) } /*[clinic input] +@critical_section _ssl._SSLContext._wrap_socket sock: object(subclass_of="get_state_ctx(self)->Sock_Type") server_side: bool @@ -4196,7 +4393,7 @@ static PyObject * _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock, int server_side, PyObject *hostname_obj, PyObject *owner, PyObject *session) -/*[clinic end generated code: output=f103f238633940b4 input=700ca8fedff53994]*/ +/*[clinic end generated code: output=f103f238633940b4 input=eceadcee4434a06f]*/ { char *hostname = NULL; PyObject *res; @@ -4218,6 +4415,7 @@ _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock, } /*[clinic input] +@critical_section _ssl._SSLContext._wrap_bio incoming: object(subclass_of="get_state_ctx(self)->PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") outgoing: object(subclass_of="get_state_ctx(self)->PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") @@ -4234,7 +4432,7 @@ _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming, PySSLMemoryBIO *outgoing, int server_side, PyObject *hostname_obj, PyObject *owner, PyObject *session) -/*[clinic end generated code: output=5c5d6d9b41f99332 input=a9205d097fd45a82]*/ +/*[clinic end generated code: output=5c5d6d9b41f99332 input=58277fc962a60182]*/ { char *hostname = NULL; PyObject *res; @@ -4255,12 +4453,13 @@ _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming, } /*[clinic input] +@critical_section _ssl._SSLContext.session_stats [clinic start generated code]*/ static PyObject * _ssl__SSLContext_session_stats_impl(PySSLContext *self) -/*[clinic end generated code: output=0d96411c42893bfb input=7e0a81fb11102c8b]*/ +/*[clinic end generated code: output=0d96411c42893bfb input=db62af53004127a4]*/ { int r; PyObject *value, *stats = PyDict_New(); @@ -4299,12 +4498,13 @@ _ssl__SSLContext_session_stats_impl(PySSLContext *self) } /*[clinic input] +@critical_section _ssl._SSLContext.set_default_verify_paths [clinic start generated code]*/ static PyObject * _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self) -/*[clinic end generated code: output=0bee74e6e09deaaa input=35f3408021463d74]*/ +/*[clinic end generated code: output=0bee74e6e09deaaa input=939a88e78f634119]*/ { int rc; Py_BEGIN_ALLOW_THREADS @@ -4318,6 +4518,7 @@ _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self) } /*[clinic input] +@critical_section _ssl._SSLContext.set_ecdh_curve name: object / @@ -4325,8 +4526,8 @@ _ssl._SSLContext.set_ecdh_curve [clinic start generated code]*/ static PyObject * -_ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) -/*[clinic end generated code: output=23022c196e40d7d2 input=c2bafb6f6e34726b]*/ +_ssl__SSLContext_set_ecdh_curve_impl(PySSLContext *self, PyObject *name) +/*[clinic end generated code: output=01081151ce0ecc45 input=039df032e666870e]*/ { PyObject *name_bytes; int nid; @@ -4460,8 +4661,15 @@ _servername_callback(SSL *s, int *al, void *args) return ret; } +/*[clinic input] +@critical_section +@getter +_ssl._SSLContext.sni_callback +[clinic start generated code]*/ + static PyObject * -get_sni_callback(PySSLContext *self, void *c) +_ssl__SSLContext_sni_callback_get_impl(PySSLContext *self) +/*[clinic end generated code: output=961e6575cdfaf036 input=22dd28c31fdc4318]*/ { PyObject *cb = self->set_sni_cb; if (cb == NULL) { @@ -4470,8 +4678,15 @@ get_sni_callback(PySSLContext *self, void *c) return Py_NewRef(cb); } +/*[clinic input] +@critical_section +@setter +_ssl._SSLContext.sni_callback +[clinic start generated code]*/ + static int -set_sni_callback(PySSLContext *self, PyObject *arg, void *c) +_ssl__SSLContext_sni_callback_set_impl(PySSLContext *self, PyObject *value) +/*[clinic end generated code: output=b32736c6b891f61a input=c3c4ff33540b3c85]*/ { if (self->protocol == PY_SSL_VERSION_TLS_CLIENT) { PyErr_SetString(PyExc_ValueError, @@ -4479,17 +4694,17 @@ set_sni_callback(PySSLContext *self, PyObject *arg, void *c) return -1; } Py_CLEAR(self->set_sni_cb); - if (arg == Py_None) { + if (value == Py_None) { SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); } else { - if (!PyCallable_Check(arg)) { + if (!PyCallable_Check(value)) { SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); PyErr_SetString(PyExc_TypeError, "not a callable object"); return -1; } - self->set_sni_cb = Py_NewRef(arg); + self->set_sni_cb = Py_NewRef(value); SSL_CTX_set_tlsext_servername_callback(self->ctx, _servername_callback); SSL_CTX_set_tlsext_servername_arg(self->ctx, self); } @@ -4540,14 +4755,8 @@ X509_STORE_get1_objects(X509_STORE *store) } #endif -PyDoc_STRVAR(PySSLContext_sni_callback_doc, -"Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n\ -\n\ -If the argument is None then the callback is disabled. The method is called\n\ -with the SSLSocket, the server name as a string, and the SSLContext object.\n\ -See RFC 6066 for details of the SNI extension."); - /*[clinic input] +@critical_section _ssl._SSLContext.cert_store_stats Returns quantities of loaded X.509 certificates. @@ -4561,7 +4770,7 @@ been used at least once. static PyObject * _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self) -/*[clinic end generated code: output=5f356f4d9cca874d input=eb40dd0f6d0e40cf]*/ +/*[clinic end generated code: output=5f356f4d9cca874d input=d13c6e3f2b48539b]*/ { X509_STORE *store; STACK_OF(X509_OBJECT) *objs; @@ -4598,6 +4807,7 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self) } /*[clinic input] +@critical_section _ssl._SSLContext.get_ca_certs binary_form: bool = False @@ -4612,7 +4822,7 @@ been used at least once. static PyObject * _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form) -/*[clinic end generated code: output=0d58f148f37e2938 input=6887b5a09b7f9076]*/ +/*[clinic end generated code: output=0d58f148f37e2938 input=eb0592909c9ad6e7]*/ { X509_STORE *store; STACK_OF(X509_OBJECT) *objs; @@ -4738,6 +4948,7 @@ static unsigned int psk_client_callback(SSL *s, #endif /*[clinic input] +@critical_section _ssl._SSLContext.set_psk_client_callback callback: object @@ -4746,7 +4957,7 @@ _ssl._SSLContext.set_psk_client_callback static PyObject * _ssl__SSLContext_set_psk_client_callback_impl(PySSLContext *self, PyObject *callback) -/*[clinic end generated code: output=0aba86f6ed75119e input=7627bae0e5ee7635]*/ +/*[clinic end generated code: output=0aba86f6ed75119e input=1e436eea625cfc35]*/ { #ifndef OPENSSL_NO_PSK if (self->protocol == PY_SSL_VERSION_TLS_SERVER) { @@ -4846,6 +5057,7 @@ static unsigned int psk_server_callback(SSL *s, #endif /*[clinic input] +@critical_section _ssl._SSLContext.set_psk_server_callback callback: object identity_hint: str(accept={str, NoneType}) = None @@ -4856,7 +5068,7 @@ static PyObject * _ssl__SSLContext_set_psk_server_callback_impl(PySSLContext *self, PyObject *callback, const char *identity_hint) -/*[clinic end generated code: output=1f4d6a4e09a92b03 input=65d4b6022aa85ea3]*/ +/*[clinic end generated code: output=1f4d6a4e09a92b03 input=5f79d932458284a7]*/ { #ifndef OPENSSL_NO_PSK if (self->protocol == PY_SSL_VERSION_TLS_CLIENT) { @@ -4901,26 +5113,19 @@ _ssl__SSLContext_set_psk_server_callback_impl(PySSLContext *self, static PyGetSetDef context_getsetlist[] = { - {"check_hostname", (getter) get_check_hostname, - (setter) set_check_hostname, NULL}, - {"_host_flags", (getter) get_host_flags, - (setter) set_host_flags, NULL}, - {"minimum_version", (getter) get_minimum_version, - (setter) set_minimum_version, NULL}, - {"maximum_version", (getter) get_maximum_version, - (setter) set_maximum_version, NULL}, + _SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF + _SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF + _SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF + _SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF {"keylog_filename", (getter) _PySSLContext_get_keylog_filename, (setter) _PySSLContext_set_keylog_filename, NULL}, {"_msg_callback", (getter) _PySSLContext_get_msg_callback, (setter) _PySSLContext_set_msg_callback, NULL}, - {"sni_callback", (getter) get_sni_callback, - (setter) set_sni_callback, PySSLContext_sni_callback_doc}, + _SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF #if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) - {"num_tickets", (getter) get_num_tickets, - (setter) set_num_tickets, PySSLContext_num_tickets_doc}, + _SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF #endif - {"options", (getter) get_options, - (setter) set_options, NULL}, + _SSL__SSLCONTEXT_OPTIONS_GETSETDEF {"post_handshake_auth", (getter) get_post_handshake_auth, #if defined(PySSL_HAVE_POST_HS_AUTH) (setter) set_post_handshake_auth, @@ -4928,14 +5133,10 @@ static PyGetSetDef context_getsetlist[] = { NULL, #endif NULL}, - {"protocol", (getter) get_protocol, - NULL, NULL}, - {"verify_flags", (getter) get_verify_flags, - (setter) set_verify_flags, NULL}, - {"verify_mode", (getter) get_verify_mode, - (setter) set_verify_mode, NULL}, - {"security_level", (getter) get_security_level, - NULL, PySSLContext_security_level_doc}, + _SSL__SSLCONTEXT_PROTOCOL_GETSETDEF + _SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF + _SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF + _SSL__SSLCONTEXT_SECURITY_LEVEL_GETSETDEF {NULL}, /* sentinel */ }; @@ -4982,6 +5183,7 @@ static PyType_Spec PySSLContext_spec = { */ /*[clinic input] +@critical_section @classmethod _ssl.MemoryBIO.__new__ @@ -4989,7 +5191,7 @@ _ssl.MemoryBIO.__new__ static PyObject * _ssl_MemoryBIO_impl(PyTypeObject *type) -/*[clinic end generated code: output=8820a58db78330ac input=26d22e4909ecb1b5]*/ +/*[clinic end generated code: output=8820a58db78330ac input=87f146cf30af454e]*/ { BIO *bio; PySSLMemoryBIO *self; @@ -5034,26 +5236,36 @@ memory_bio_dealloc(PySSLMemoryBIO *self) Py_DECREF(tp); } +/*[clinic input] +@critical_section +@getter +_ssl.MemoryBIO.pending +[clinic start generated code]*/ + static PyObject * -memory_bio_get_pending(PySSLMemoryBIO *self, void *c) +_ssl_MemoryBIO_pending_get_impl(PySSLMemoryBIO *self) +/*[clinic end generated code: output=19236a32a51ac8ff input=c0b6d14eba107f6a]*/ { - return PyLong_FromSize_t(BIO_ctrl_pending(self->bio)); + size_t res = BIO_ctrl_pending(self->bio); + return PyLong_FromSize_t(res); } -PyDoc_STRVAR(PySSL_memory_bio_pending_doc, -"The number of bytes pending in the memory BIO."); +/*[clinic input] +@critical_section +@getter +_ssl.MemoryBIO.eof +[clinic start generated code]*/ static PyObject * -memory_bio_get_eof(PySSLMemoryBIO *self, void *c) +_ssl_MemoryBIO_eof_get_impl(PySSLMemoryBIO *self) +/*[clinic end generated code: output=c255a9ea16e31b92 input=0f5c6be69752e04c]*/ { - return PyBool_FromLong((BIO_ctrl_pending(self->bio) == 0) - && self->eof_written); + size_t pending = BIO_ctrl_pending(self->bio); + return PyBool_FromLong((pending == 0) && self->eof_written); } -PyDoc_STRVAR(PySSL_memory_bio_eof_doc, -"Whether the memory BIO is at EOF."); - /*[clinic input] +@critical_section _ssl.MemoryBIO.read size as len: int = -1 / @@ -5068,7 +5280,7 @@ distinguish between the two. static PyObject * _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len) -/*[clinic end generated code: output=a657aa1e79cd01b3 input=574d7be06a902366]*/ +/*[clinic end generated code: output=a657aa1e79cd01b3 input=21046f2d7dac3a90]*/ { int avail, nbytes; PyObject *result; @@ -5098,6 +5310,7 @@ _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len) } /*[clinic input] +@critical_section _ssl.MemoryBIO.write b: Py_buffer / @@ -5109,7 +5322,7 @@ Returns the number of bytes written. static PyObject * _ssl_MemoryBIO_write_impl(PySSLMemoryBIO *self, Py_buffer *b) -/*[clinic end generated code: output=156ec59110d75935 input=e45757b3e17c4808]*/ +/*[clinic end generated code: output=156ec59110d75935 input=107da3f5fba26b37]*/ { int nbytes; @@ -5139,6 +5352,7 @@ _ssl_MemoryBIO_write_impl(PySSLMemoryBIO *self, Py_buffer *b) } /*[clinic input] +@critical_section _ssl.MemoryBIO.write_eof Write an EOF marker to the memory BIO. @@ -5148,7 +5362,7 @@ When all data has been read, the "eof" property will be True. static PyObject * _ssl_MemoryBIO_write_eof_impl(PySSLMemoryBIO *self) -/*[clinic end generated code: output=d4106276ccd1ed34 input=56a945f1d29e8bd6]*/ +/*[clinic end generated code: output=d4106276ccd1ed34 input=1e914231b1c5900a]*/ { self->eof_written = 1; /* After an EOF is written, a zero return from read() should be a real EOF @@ -5160,10 +5374,8 @@ _ssl_MemoryBIO_write_eof_impl(PySSLMemoryBIO *self) } static PyGetSetDef memory_bio_getsetlist[] = { - {"pending", (getter) memory_bio_get_pending, NULL, - PySSL_memory_bio_pending_doc}, - {"eof", (getter) memory_bio_get_eof, NULL, - PySSL_memory_bio_eof_doc}, + _SSL_MEMORYBIO_PENDING_GETSETDEF + _SSL_MEMORYBIO_EOF_GETSETDEF {NULL}, /* sentinel */ }; @@ -5283,8 +5495,16 @@ PySSLSession_clear(PySSLSession *self) } +/*[clinic input] +@critical_section +@getter +_ssl.SSLSession.time +[clinic start generated code]*/ + static PyObject * -PySSLSession_get_time(PySSLSession *self, void *closure) { +_ssl_SSLSession_time_get_impl(PySSLSession *self) +/*[clinic end generated code: output=4b887b9299de9be4 input=8d1e4afd09103279]*/ +{ #if OPENSSL_VERSION_NUMBER >= 0x30300000L return _PyLong_FromTime_t(SSL_SESSION_get_time_ex(self->session)); #else @@ -5292,65 +5512,72 @@ PySSLSession_get_time(PySSLSession *self, void *closure) { #endif } -PyDoc_STRVAR(PySSLSession_get_time_doc, -"Session creation time (seconds since epoch)."); - +/*[clinic input] +@critical_section +@getter +_ssl.SSLSession.timeout +[clinic start generated code]*/ static PyObject * -PySSLSession_get_timeout(PySSLSession *self, void *closure) { - return PyLong_FromLong(SSL_SESSION_get_timeout(self->session)); +_ssl_SSLSession_timeout_get_impl(PySSLSession *self) +/*[clinic end generated code: output=82339c148ab2f7d1 input=ae5e84a9d85df60d]*/ +{ + long timeout = SSL_SESSION_get_timeout(self->session); + PyObject *res = PyLong_FromLong(timeout); + return res; } -PyDoc_STRVAR(PySSLSession_get_timeout_doc, -"Session timeout (delta in seconds)."); - +/*[clinic input] +@critical_section +@getter +_ssl.SSLSession.ticket_lifetime_hint +[clinic start generated code]*/ static PyObject * -PySSLSession_get_ticket_lifetime_hint(PySSLSession *self, void *closure) { +_ssl_SSLSession_ticket_lifetime_hint_get_impl(PySSLSession *self) +/*[clinic end generated code: output=c8b6db498136c275 input=d0e06942ddd8d07f]*/ +{ unsigned long hint = SSL_SESSION_get_ticket_lifetime_hint(self->session); return PyLong_FromUnsignedLong(hint); } -PyDoc_STRVAR(PySSLSession_get_ticket_lifetime_hint_doc, -"Ticket life time hint."); - +/*[clinic input] +@critical_section +@getter +_ssl.SSLSession.id +[clinic start generated code]*/ static PyObject * -PySSLSession_get_session_id(PySSLSession *self, void *closure) { +_ssl_SSLSession_id_get_impl(PySSLSession *self) +/*[clinic end generated code: output=c532fb96b10c5adf input=e7322372cf6325dd]*/ + +{ const unsigned char *id; unsigned int len; id = SSL_SESSION_get_id(self->session, &len); return PyBytes_FromStringAndSize((const char *)id, len); } -PyDoc_STRVAR(PySSLSession_get_session_id_doc, -"Session id"); - +/*[clinic input] +@critical_section +@getter +_ssl.SSLSession.has_ticket +[clinic start generated code]*/ static PyObject * -PySSLSession_get_has_ticket(PySSLSession *self, void *closure) { - if (SSL_SESSION_has_ticket(self->session)) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } +_ssl_SSLSession_has_ticket_get_impl(PySSLSession *self) +/*[clinic end generated code: output=aa3ccfc40b10b96d input=1a48ae8955fa9601]*/ +{ + int res = SSL_SESSION_has_ticket(self->session); + return res ? Py_True : Py_False; } -PyDoc_STRVAR(PySSLSession_get_has_ticket_doc, -"Does the session contain a ticket?"); - - static PyGetSetDef PySSLSession_getsetlist[] = { - {"has_ticket", (getter) PySSLSession_get_has_ticket, NULL, - PySSLSession_get_has_ticket_doc}, - {"id", (getter) PySSLSession_get_session_id, NULL, - PySSLSession_get_session_id_doc}, - {"ticket_lifetime_hint", (getter) PySSLSession_get_ticket_lifetime_hint, - NULL, PySSLSession_get_ticket_lifetime_hint_doc}, - {"time", (getter) PySSLSession_get_time, NULL, - PySSLSession_get_time_doc}, - {"timeout", (getter) PySSLSession_get_timeout, NULL, - PySSLSession_get_timeout_doc}, + _SSL_SSLSESSION_HAS_TICKET_GETSETDEF + _SSL_SSLSESSION_ID_GETSETDEF + _SSL_SSLSESSION_TICKET_LIFETIME_HINT_GETSETDEF + _SSL_SSLSESSION_TIME_GETSETDEF + _SSL_SSLSESSION_TIMEOUT_GETSETDEF {NULL}, /* sentinel */ }; @@ -5375,6 +5602,7 @@ static PyType_Spec PySSLSession_spec = { /* helper routines for seeding the SSL PRNG */ /*[clinic input] +@critical_section _ssl.RAND_add string as view: Py_buffer(accept={str, buffer}) entropy: double @@ -5388,7 +5616,7 @@ string. See RFC 4086. static PyObject * _ssl_RAND_add_impl(PyObject *module, Py_buffer *view, double entropy) -/*[clinic end generated code: output=e6dd48df9c9024e9 input=5c33017422828f5c]*/ +/*[clinic end generated code: output=e6dd48df9c9024e9 input=313cb73b34db31d5]*/ { const char *buf; Py_ssize_t len, written; @@ -5444,6 +5672,7 @@ PySSL_RAND(PyObject *module, int len, int pseudo) } /*[clinic input] +@critical_section _ssl.RAND_bytes n: int / @@ -5453,13 +5682,14 @@ Generate n cryptographically strong pseudo-random bytes. static PyObject * _ssl_RAND_bytes_impl(PyObject *module, int n) -/*[clinic end generated code: output=977da635e4838bc7 input=678ddf2872dfebfc]*/ +/*[clinic end generated code: output=977da635e4838bc7 input=2e78ce1e86336776]*/ { return PySSL_RAND(module, n, 0); } /*[clinic input] +@critical_section _ssl.RAND_status Returns True if the OpenSSL PRNG has been seeded with enough data and False if not. @@ -5470,12 +5700,13 @@ using the ssl() function. static PyObject * _ssl_RAND_status_impl(PyObject *module) -/*[clinic end generated code: output=7e0aaa2d39fdc1ad input=d5ae5aea52f36e01]*/ +/*[clinic end generated code: output=7e0aaa2d39fdc1ad input=636fb5659ea2e727]*/ { return PyBool_FromLong(RAND_status()); } /*[clinic input] +@critical_section _ssl.get_default_verify_paths Return search paths and environment vars that are used by SSLContext's set_default_verify_paths() to load default CAs. @@ -5485,7 +5716,7 @@ The values are 'cert_file_env', 'cert_file', 'cert_dir_env', 'cert_dir'. static PyObject * _ssl_get_default_verify_paths_impl(PyObject *module) -/*[clinic end generated code: output=e5b62a466271928b input=5210c953d98c3eb5]*/ +/*[clinic end generated code: output=e5b62a466271928b input=c6ae00bc04eb2b6e]*/ { PyObject *ofile_env = NULL; PyObject *ofile = NULL; @@ -5534,6 +5765,7 @@ asn1obj2py(_sslmodulestate *state, ASN1_OBJECT *obj) } /*[clinic input] +@critical_section _ssl.txt2obj txt: str name: bool = False @@ -5546,7 +5778,7 @@ long name are also matched. static PyObject * _ssl_txt2obj_impl(PyObject *module, const char *txt, int name) -/*[clinic end generated code: output=c38e3991347079c1 input=1c1e7d0aa7c48602]*/ +/*[clinic end generated code: output=c38e3991347079c1 input=c99b134d70173c5e]*/ { PyObject *result = NULL; ASN1_OBJECT *obj; @@ -5562,6 +5794,7 @@ _ssl_txt2obj_impl(PyObject *module, const char *txt, int name) } /*[clinic input] +@critical_section _ssl.nid2obj nid: int / @@ -5571,7 +5804,7 @@ Lookup NID, short name, long name and OID of an ASN1_OBJECT by NID. static PyObject * _ssl_nid2obj_impl(PyObject *module, int nid) -/*[clinic end generated code: output=4a98ab691cd4f84a input=51787a3bee7d8f98]*/ +/*[clinic end generated code: output=4a98ab691cd4f84a input=1b1170506fa83a53]*/ { PyObject *result = NULL; ASN1_OBJECT *obj; @@ -5723,6 +5956,7 @@ ssl_collect_certificates(const char *store_name) } /*[clinic input] +@critical_section _ssl.enum_certificates store_name: str @@ -5737,7 +5971,7 @@ a set of OIDs or the boolean True. static PyObject * _ssl_enum_certificates_impl(PyObject *module, const char *store_name) -/*[clinic end generated code: output=5134dc8bb3a3c893 input=915f60d70461ea4e]*/ +/*[clinic end generated code: output=5134dc8bb3a3c893 input=263c22e6c6988cf3]*/ { HCERTSTORE hCollectionStore = NULL; PCCERT_CONTEXT pCertCtx = NULL; @@ -5822,6 +6056,7 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name) } /*[clinic input] +@critical_section _ssl.enum_crls store_name: str @@ -5835,7 +6070,7 @@ X509_ASN_ENCODING or PKCS_7_ASN_ENCODING. static PyObject * _ssl_enum_crls_impl(PyObject *module, const char *store_name) -/*[clinic end generated code: output=bce467f60ccd03b6 input=a1f1d7629f1c5d3d]*/ +/*[clinic end generated code: output=bce467f60ccd03b6 input=51a1b1059e55ce43]*/ { HCERTSTORE hCollectionStore = NULL; PCCRL_CONTEXT pCrlCtx = NULL; diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index e8d1342ed35e66..9d5b70dfad553d 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_ssl__SSLSocket_do_handshake__doc__, @@ -22,7 +23,13 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_do_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_do_handshake_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_do_handshake_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__test_decode_cert__doc__, @@ -88,7 +95,9 @@ _ssl__SSLSocket_getpeercert(PySSLSocket *self, PyObject *const *args, Py_ssize_t goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLSocket_getpeercert_impl(self, binary_mode); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -108,7 +117,13 @@ _ssl__SSLSocket_get_verified_chain_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_get_verified_chain(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_get_verified_chain_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_get_verified_chain_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_get_unverified_chain__doc__, @@ -125,7 +140,13 @@ _ssl__SSLSocket_get_unverified_chain_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_get_unverified_chain(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_get_unverified_chain_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_get_unverified_chain_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_shared_ciphers__doc__, @@ -142,7 +163,13 @@ _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_shared_ciphers(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_shared_ciphers_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_shared_ciphers_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_cipher__doc__, @@ -159,7 +186,13 @@ _ssl__SSLSocket_cipher_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_cipher(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_cipher_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_cipher_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_version__doc__, @@ -176,7 +209,13 @@ _ssl__SSLSocket_version_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_version(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_version_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_version_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_selected_alpn_protocol__doc__, @@ -193,7 +232,13 @@ _ssl__SSLSocket_selected_alpn_protocol_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_selected_alpn_protocol(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_selected_alpn_protocol_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_selected_alpn_protocol_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_compression__doc__, @@ -213,6 +258,176 @@ _ssl__SSLSocket_compression(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) return _ssl__SSLSocket_compression_impl(self); } +#if defined(_ssl__SSLSocket_context_HAS_DOCSTR) +# define _ssl__SSLSocket_context_DOCSTR _ssl__SSLSocket_context__doc__ +#else +# define _ssl__SSLSocket_context_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_CONTEXT_GETSETDEF) +# undef _SSL__SSLSOCKET_CONTEXT_GETSETDEF +# define _SSL__SSLSOCKET_CONTEXT_GETSETDEF {"context", (getter)_ssl__SSLSocket_context_get, (setter)_ssl__SSLSocket_context_set, _ssl__SSLSocket_context_DOCSTR}, +#else +# define _SSL__SSLSOCKET_CONTEXT_GETSETDEF {"context", (getter)_ssl__SSLSocket_context_get, NULL, _ssl__SSLSocket_context_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLSocket_context_get_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_context_get(PySSLSocket *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_context_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLSOCKET_CONTEXT_HAS_DOCSTR) +# define _ssl__SSLSocket_context_DOCSTR _ssl__SSLSocket_context__doc__ +#else +# define _ssl__SSLSocket_context_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_CONTEXT_GETSETDEF) +# undef _SSL__SSLSOCKET_CONTEXT_GETSETDEF +# define _SSL__SSLSOCKET_CONTEXT_GETSETDEF {"context", (getter)_ssl__SSLSocket_context_get, (setter)_ssl__SSLSocket_context_set, _ssl__SSLSocket_context_DOCSTR}, +#else +# define _SSL__SSLSOCKET_CONTEXT_GETSETDEF {"context", NULL, (setter)_ssl__SSLSocket_context_set, NULL}, +#endif + +static int +_ssl__SSLSocket_context_set_impl(PySSLSocket *self, PyObject *value); + +static int +_ssl__SSLSocket_context_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_context_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLSocket_server_side__doc__, +"Whether this is a server-side socket."); +#define _ssl__SSLSocket_server_side_HAS_DOCSTR + +#if defined(_ssl__SSLSocket_server_side_HAS_DOCSTR) +# define _ssl__SSLSocket_server_side_DOCSTR _ssl__SSLSocket_server_side__doc__ +#else +# define _ssl__SSLSocket_server_side_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_SERVER_SIDE_GETSETDEF) +# undef _SSL__SSLSOCKET_SERVER_SIDE_GETSETDEF +# define _SSL__SSLSOCKET_SERVER_SIDE_GETSETDEF {"server_side", (getter)_ssl__SSLSocket_server_side_get, (setter)_ssl__SSLSocket_server_side_set, _ssl__SSLSocket_server_side_DOCSTR}, +#else +# define _SSL__SSLSOCKET_SERVER_SIDE_GETSETDEF {"server_side", (getter)_ssl__SSLSocket_server_side_get, NULL, _ssl__SSLSocket_server_side_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLSocket_server_side_get_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_server_side_get(PySSLSocket *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_server_side_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLSocket_server_hostname__doc__, +"The currently set server hostname (for SNI)."); +#define _ssl__SSLSocket_server_hostname_HAS_DOCSTR + +#if defined(_ssl__SSLSocket_server_hostname_HAS_DOCSTR) +# define _ssl__SSLSocket_server_hostname_DOCSTR _ssl__SSLSocket_server_hostname__doc__ +#else +# define _ssl__SSLSocket_server_hostname_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_SERVER_HOSTNAME_GETSETDEF) +# undef _SSL__SSLSOCKET_SERVER_HOSTNAME_GETSETDEF +# define _SSL__SSLSOCKET_SERVER_HOSTNAME_GETSETDEF {"server_hostname", (getter)_ssl__SSLSocket_server_hostname_get, (setter)_ssl__SSLSocket_server_hostname_set, _ssl__SSLSocket_server_hostname_DOCSTR}, +#else +# define _SSL__SSLSOCKET_SERVER_HOSTNAME_GETSETDEF {"server_hostname", (getter)_ssl__SSLSocket_server_hostname_get, NULL, _ssl__SSLSocket_server_hostname_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLSocket_server_hostname_get_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_server_hostname_get(PySSLSocket *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_server_hostname_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLSocket_owner_HAS_DOCSTR) +# define _ssl__SSLSocket_owner_DOCSTR _ssl__SSLSocket_owner__doc__ +#else +# define _ssl__SSLSocket_owner_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_OWNER_GETSETDEF) +# undef _SSL__SSLSOCKET_OWNER_GETSETDEF +# define _SSL__SSLSOCKET_OWNER_GETSETDEF {"owner", (getter)_ssl__SSLSocket_owner_get, (setter)_ssl__SSLSocket_owner_set, _ssl__SSLSocket_owner_DOCSTR}, +#else +# define _SSL__SSLSOCKET_OWNER_GETSETDEF {"owner", (getter)_ssl__SSLSocket_owner_get, NULL, _ssl__SSLSocket_owner_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLSocket_owner_get_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_owner_get(PySSLSocket *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_owner_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLSOCKET_OWNER_HAS_DOCSTR) +# define _ssl__SSLSocket_owner_DOCSTR _ssl__SSLSocket_owner__doc__ +#else +# define _ssl__SSLSocket_owner_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_OWNER_GETSETDEF) +# undef _SSL__SSLSOCKET_OWNER_GETSETDEF +# define _SSL__SSLSOCKET_OWNER_GETSETDEF {"owner", (getter)_ssl__SSLSocket_owner_get, (setter)_ssl__SSLSocket_owner_set, _ssl__SSLSocket_owner_DOCSTR}, +#else +# define _SSL__SSLSOCKET_OWNER_GETSETDEF {"owner", NULL, (setter)_ssl__SSLSocket_owner_set, NULL}, +#endif + +static int +_ssl__SSLSocket_owner_set_impl(PySSLSocket *self, PyObject *value); + +static int +_ssl__SSLSocket_owner_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_owner_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(_ssl__SSLSocket_write__doc__, "write($self, b, /)\n" "--\n" @@ -236,7 +451,9 @@ _ssl__SSLSocket_write(PySSLSocket *self, PyObject *arg) if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { goto exit; } + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLSocket_write_impl(self, &b); + Py_END_CRITICAL_SECTION(); exit: /* Cleanup for b */ @@ -262,7 +479,13 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_pending(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_pending_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_pending_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_read__doc__, @@ -300,7 +523,9 @@ _ssl__SSLSocket_read(PySSLSocket *self, PyObject *args) PyErr_SetString(PyExc_TypeError, "_ssl._SSLSocket.read requires 1 to 2 arguments"); goto exit; } + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLSocket_read_impl(self, len, group_right_1, &buffer); + Py_END_CRITICAL_SECTION(); exit: /* Cleanup for buffer */ @@ -326,7 +551,13 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_shutdown(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_shutdown_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_shutdown_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLSocket_get_channel_binding__doc__, @@ -400,7 +631,9 @@ _ssl__SSLSocket_get_channel_binding(PySSLSocket *self, PyObject *const *args, Py goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLSocket_get_channel_binding_impl(self, cb_type); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -421,117 +654,708 @@ _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self); static PyObject * _ssl__SSLSocket_verify_client_post_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLSocket_verify_client_post_handshake_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_verify_client_post_handshake_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLSocket_session_HAS_DOCSTR) +# define _ssl__SSLSocket_session_DOCSTR _ssl__SSLSocket_session__doc__ +#else +# define _ssl__SSLSocket_session_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_SESSION_GETSETDEF) +# undef _SSL__SSLSOCKET_SESSION_GETSETDEF +# define _SSL__SSLSOCKET_SESSION_GETSETDEF {"session", (getter)_ssl__SSLSocket_session_get, (setter)_ssl__SSLSocket_session_set, _ssl__SSLSocket_session_DOCSTR}, +#else +# define _SSL__SSLSOCKET_SESSION_GETSETDEF {"session", (getter)_ssl__SSLSocket_session_get, NULL, _ssl__SSLSocket_session_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLSocket_session_get_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_session_get(PySSLSocket *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_session_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLSOCKET_SESSION_HAS_DOCSTR) +# define _ssl__SSLSocket_session_DOCSTR _ssl__SSLSocket_session__doc__ +#else +# define _ssl__SSLSocket_session_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_SESSION_GETSETDEF) +# undef _SSL__SSLSOCKET_SESSION_GETSETDEF +# define _SSL__SSLSOCKET_SESSION_GETSETDEF {"session", (getter)_ssl__SSLSocket_session_get, (setter)_ssl__SSLSocket_session_set, _ssl__SSLSocket_session_DOCSTR}, +#else +# define _SSL__SSLSOCKET_SESSION_GETSETDEF {"session", NULL, (setter)_ssl__SSLSocket_session_set, NULL}, +#endif + +static int +_ssl__SSLSocket_session_set_impl(PySSLSocket *self, PyObject *value); + +static int +_ssl__SSLSocket_session_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_session_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLSocket_session_reused__doc__, +"Was the client session reused during handshake?"); +#define _ssl__SSLSocket_session_reused_HAS_DOCSTR + +#if defined(_ssl__SSLSocket_session_reused_HAS_DOCSTR) +# define _ssl__SSLSocket_session_reused_DOCSTR _ssl__SSLSocket_session_reused__doc__ +#else +# define _ssl__SSLSocket_session_reused_DOCSTR NULL +#endif +#if defined(_SSL__SSLSOCKET_SESSION_REUSED_GETSETDEF) +# undef _SSL__SSLSOCKET_SESSION_REUSED_GETSETDEF +# define _SSL__SSLSOCKET_SESSION_REUSED_GETSETDEF {"session_reused", (getter)_ssl__SSLSocket_session_reused_get, (setter)_ssl__SSLSocket_session_reused_set, _ssl__SSLSocket_session_reused_DOCSTR}, +#else +# define _SSL__SSLSOCKET_SESSION_REUSED_GETSETDEF {"session_reused", (getter)_ssl__SSLSocket_session_reused_get, NULL, _ssl__SSLSocket_session_reused_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLSocket_session_reused_get_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_session_reused_get(PySSLSocket *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_session_reused_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +static PyObject * +_ssl__SSLContext_impl(PyTypeObject *type, int proto_version); + +static PyObject * +_ssl__SSLContext(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = get_state_type(type)->PySSLContext_Type; + int proto_version; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("_SSLContext", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("_SSLContext", PyTuple_GET_SIZE(args), 1, 1)) { + goto exit; + } + proto_version = PyLong_AsInt(PyTuple_GET_ITEM(args, 0)); + if (proto_version == -1 && PyErr_Occurred()) { + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(type); + return_value = _ssl__SSLContext_impl(type, proto_version); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLContext_set_ciphers__doc__, +"set_ciphers($self, cipherlist, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLCONTEXT_SET_CIPHERS_METHODDEF \ + {"set_ciphers", (PyCFunction)_ssl__SSLContext_set_ciphers, METH_O, _ssl__SSLContext_set_ciphers__doc__}, + +static PyObject * +_ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist); + +static PyObject * +_ssl__SSLContext_set_ciphers(PySSLContext *self, PyObject *arg) +{ + PyObject *return_value = NULL; + const char *cipherlist; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("set_ciphers", "argument", "str", arg); + goto exit; + } + Py_ssize_t cipherlist_length; + cipherlist = PyUnicode_AsUTF8AndSize(arg, &cipherlist_length); + if (cipherlist == NULL) { + goto exit; + } + if (strlen(cipherlist) != (size_t)cipherlist_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_set_ciphers_impl(self, cipherlist); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLContext_get_ciphers__doc__, +"get_ciphers($self, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF \ + {"get_ciphers", (PyCFunction)_ssl__SSLContext_get_ciphers, METH_NOARGS, _ssl__SSLContext_get_ciphers__doc__}, + +static PyObject * +_ssl__SSLContext_get_ciphers_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_get_ciphers(PySSLContext *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_get_ciphers_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLContext__set_alpn_protocols__doc__, +"_set_alpn_protocols($self, protos, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLCONTEXT__SET_ALPN_PROTOCOLS_METHODDEF \ + {"_set_alpn_protocols", (PyCFunction)_ssl__SSLContext__set_alpn_protocols, METH_O, _ssl__SSLContext__set_alpn_protocols__doc__}, + +static PyObject * +_ssl__SSLContext__set_alpn_protocols_impl(PySSLContext *self, + Py_buffer *protos); + +static PyObject * +_ssl__SSLContext__set_alpn_protocols(PySSLContext *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer protos = {NULL, NULL}; + + if (PyObject_GetBuffer(arg, &protos, PyBUF_SIMPLE) != 0) { + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext__set_alpn_protocols_impl(self, &protos); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for protos */ + if (protos.obj) { + PyBuffer_Release(&protos); + } + + return return_value; +} + +#if defined(_ssl__SSLContext_verify_mode_HAS_DOCSTR) +# define _ssl__SSLContext_verify_mode_DOCSTR _ssl__SSLContext_verify_mode__doc__ +#else +# define _ssl__SSLContext_verify_mode_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF) +# undef _SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF +# define _SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF {"verify_mode", (getter)_ssl__SSLContext_verify_mode_get, (setter)_ssl__SSLContext_verify_mode_set, _ssl__SSLContext_verify_mode_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF {"verify_mode", (getter)_ssl__SSLContext_verify_mode_get, NULL, _ssl__SSLContext_verify_mode_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_verify_mode_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_verify_mode_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_verify_mode_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLCONTEXT_VERIFY_MODE_HAS_DOCSTR) +# define _ssl__SSLContext_verify_mode_DOCSTR _ssl__SSLContext_verify_mode__doc__ +#else +# define _ssl__SSLContext_verify_mode_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF) +# undef _SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF +# define _SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF {"verify_mode", (getter)_ssl__SSLContext_verify_mode_get, (setter)_ssl__SSLContext_verify_mode_set, _ssl__SSLContext_verify_mode_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_VERIFY_MODE_GETSETDEF {"verify_mode", NULL, (setter)_ssl__SSLContext_verify_mode_set, NULL}, +#endif + +static int +_ssl__SSLContext_verify_mode_set_impl(PySSLContext *self, PyObject *value); + +static int +_ssl__SSLContext_verify_mode_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_verify_mode_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_verify_flags_HAS_DOCSTR) +# define _ssl__SSLContext_verify_flags_DOCSTR _ssl__SSLContext_verify_flags__doc__ +#else +# define _ssl__SSLContext_verify_flags_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF) +# undef _SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF +# define _SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF {"verify_flags", (getter)_ssl__SSLContext_verify_flags_get, (setter)_ssl__SSLContext_verify_flags_set, _ssl__SSLContext_verify_flags_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF {"verify_flags", (getter)_ssl__SSLContext_verify_flags_get, NULL, _ssl__SSLContext_verify_flags_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_verify_flags_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_verify_flags_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_verify_flags_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLCONTEXT_VERIFY_FLAGS_HAS_DOCSTR) +# define _ssl__SSLContext_verify_flags_DOCSTR _ssl__SSLContext_verify_flags__doc__ +#else +# define _ssl__SSLContext_verify_flags_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF) +# undef _SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF +# define _SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF {"verify_flags", (getter)_ssl__SSLContext_verify_flags_get, (setter)_ssl__SSLContext_verify_flags_set, _ssl__SSLContext_verify_flags_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_VERIFY_FLAGS_GETSETDEF {"verify_flags", NULL, (setter)_ssl__SSLContext_verify_flags_set, NULL}, +#endif + +static int +_ssl__SSLContext_verify_flags_set_impl(PySSLContext *self, PyObject *value); + +static int +_ssl__SSLContext_verify_flags_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_verify_flags_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_minimum_version_HAS_DOCSTR) +# define _ssl__SSLContext_minimum_version_DOCSTR _ssl__SSLContext_minimum_version__doc__ +#else +# define _ssl__SSLContext_minimum_version_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF) +# undef _SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF +# define _SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF {"minimum_version", (getter)_ssl__SSLContext_minimum_version_get, (setter)_ssl__SSLContext_minimum_version_set, _ssl__SSLContext_minimum_version_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF {"minimum_version", (getter)_ssl__SSLContext_minimum_version_get, NULL, _ssl__SSLContext_minimum_version_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_minimum_version_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_minimum_version_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_minimum_version_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLCONTEXT_MINIMUM_VERSION_HAS_DOCSTR) +# define _ssl__SSLContext_minimum_version_DOCSTR _ssl__SSLContext_minimum_version__doc__ +#else +# define _ssl__SSLContext_minimum_version_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF) +# undef _SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF +# define _SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF {"minimum_version", (getter)_ssl__SSLContext_minimum_version_get, (setter)_ssl__SSLContext_minimum_version_set, _ssl__SSLContext_minimum_version_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF {"minimum_version", NULL, (setter)_ssl__SSLContext_minimum_version_set, NULL}, +#endif + +static int +_ssl__SSLContext_minimum_version_set_impl(PySSLContext *self, + PyObject *value); + +static int +_ssl__SSLContext_minimum_version_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_minimum_version_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_maximum_version_HAS_DOCSTR) +# define _ssl__SSLContext_maximum_version_DOCSTR _ssl__SSLContext_maximum_version__doc__ +#else +# define _ssl__SSLContext_maximum_version_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF) +# undef _SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF +# define _SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF {"maximum_version", (getter)_ssl__SSLContext_maximum_version_get, (setter)_ssl__SSLContext_maximum_version_set, _ssl__SSLContext_maximum_version_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF {"maximum_version", (getter)_ssl__SSLContext_maximum_version_get, NULL, _ssl__SSLContext_maximum_version_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_maximum_version_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_maximum_version_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_maximum_version_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLCONTEXT_MAXIMUM_VERSION_HAS_DOCSTR) +# define _ssl__SSLContext_maximum_version_DOCSTR _ssl__SSLContext_maximum_version__doc__ +#else +# define _ssl__SSLContext_maximum_version_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF) +# undef _SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF +# define _SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF {"maximum_version", (getter)_ssl__SSLContext_maximum_version_get, (setter)_ssl__SSLContext_maximum_version_set, _ssl__SSLContext_maximum_version_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF {"maximum_version", NULL, (setter)_ssl__SSLContext_maximum_version_set, NULL}, +#endif + +static int +_ssl__SSLContext_maximum_version_set_impl(PySSLContext *self, + PyObject *value); + +static int +_ssl__SSLContext_maximum_version_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_maximum_version_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_num_tickets_HAS_DOCSTR) +# define _ssl__SSLContext_num_tickets_DOCSTR _ssl__SSLContext_num_tickets__doc__ +#else +# define _ssl__SSLContext_num_tickets_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF) +# undef _SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF +# define _SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF {"num_tickets", (getter)_ssl__SSLContext_num_tickets_get, (setter)_ssl__SSLContext_num_tickets_set, _ssl__SSLContext_num_tickets_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF {"num_tickets", (getter)_ssl__SSLContext_num_tickets_get, NULL, _ssl__SSLContext_num_tickets_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_num_tickets_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_num_tickets_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_num_tickets_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLCONTEXT_NUM_TICKETS_HAS_DOCSTR) +# define _ssl__SSLContext_num_tickets_DOCSTR _ssl__SSLContext_num_tickets__doc__ +#else +# define _ssl__SSLContext_num_tickets_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF) +# undef _SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF +# define _SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF {"num_tickets", (getter)_ssl__SSLContext_num_tickets_get, (setter)_ssl__SSLContext_num_tickets_set, _ssl__SSLContext_num_tickets_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF {"num_tickets", NULL, (setter)_ssl__SSLContext_num_tickets_set, NULL}, +#endif + +static int +_ssl__SSLContext_num_tickets_set_impl(PySSLContext *self, PyObject *value); + +static int +_ssl__SSLContext_num_tickets_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_num_tickets_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_security_level_HAS_DOCSTR) +# define _ssl__SSLContext_security_level_DOCSTR _ssl__SSLContext_security_level__doc__ +#else +# define _ssl__SSLContext_security_level_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_SECURITY_LEVEL_GETSETDEF) +# undef _SSL__SSLCONTEXT_SECURITY_LEVEL_GETSETDEF +# define _SSL__SSLCONTEXT_SECURITY_LEVEL_GETSETDEF {"security_level", (getter)_ssl__SSLContext_security_level_get, (setter)_ssl__SSLContext_security_level_set, _ssl__SSLContext_security_level_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_SECURITY_LEVEL_GETSETDEF {"security_level", (getter)_ssl__SSLContext_security_level_get, NULL, _ssl__SSLContext_security_level_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_security_level_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_security_level_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_security_level_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_options_HAS_DOCSTR) +# define _ssl__SSLContext_options_DOCSTR _ssl__SSLContext_options__doc__ +#else +# define _ssl__SSLContext_options_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_OPTIONS_GETSETDEF) +# undef _SSL__SSLCONTEXT_OPTIONS_GETSETDEF +# define _SSL__SSLCONTEXT_OPTIONS_GETSETDEF {"options", (getter)_ssl__SSLContext_options_get, (setter)_ssl__SSLContext_options_set, _ssl__SSLContext_options_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_OPTIONS_GETSETDEF {"options", (getter)_ssl__SSLContext_options_get, NULL, _ssl__SSLContext_options_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_options_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_options_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_options_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLCONTEXT_OPTIONS_HAS_DOCSTR) +# define _ssl__SSLContext_options_DOCSTR _ssl__SSLContext_options__doc__ +#else +# define _ssl__SSLContext_options_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_OPTIONS_GETSETDEF) +# undef _SSL__SSLCONTEXT_OPTIONS_GETSETDEF +# define _SSL__SSLCONTEXT_OPTIONS_GETSETDEF {"options", (getter)_ssl__SSLContext_options_get, (setter)_ssl__SSLContext_options_set, _ssl__SSLContext_options_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_OPTIONS_GETSETDEF {"options", NULL, (setter)_ssl__SSLContext_options_set, NULL}, +#endif + +static int +_ssl__SSLContext_options_set_impl(PySSLContext *self, PyObject *value); + +static int +_ssl__SSLContext_options_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_options_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; } +#if defined(_ssl__SSLContext__host_flags_HAS_DOCSTR) +# define _ssl__SSLContext__host_flags_DOCSTR _ssl__SSLContext__host_flags__doc__ +#else +# define _ssl__SSLContext__host_flags_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF) +# undef _SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF +# define _SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF {"_host_flags", (getter)_ssl__SSLContext__host_flags_get, (setter)_ssl__SSLContext__host_flags_set, _ssl__SSLContext__host_flags_DOCSTR}, +#else +# define _SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF {"_host_flags", (getter)_ssl__SSLContext__host_flags_get, NULL, _ssl__SSLContext__host_flags_DOCSTR}, +#endif + static PyObject * -_ssl__SSLContext_impl(PyTypeObject *type, int proto_version); +_ssl__SSLContext__host_flags_get_impl(PySSLContext *self); static PyObject * -_ssl__SSLContext(PyTypeObject *type, PyObject *args, PyObject *kwargs) +_ssl__SSLContext__host_flags_get(PySSLContext *self, void *Py_UNUSED(context)) { PyObject *return_value = NULL; - PyTypeObject *base_tp = get_state_type(type)->PySSLContext_Type; - int proto_version; - if ((type == base_tp || type->tp_init == base_tp->tp_init) && - !_PyArg_NoKeywords("_SSLContext", kwargs)) { - goto exit; - } - if (!_PyArg_CheckPositional("_SSLContext", PyTuple_GET_SIZE(args), 1, 1)) { - goto exit; - } - proto_version = PyLong_AsInt(PyTuple_GET_ITEM(args, 0)); - if (proto_version == -1 && PyErr_Occurred()) { - goto exit; - } - return_value = _ssl__SSLContext_impl(type, proto_version); + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext__host_flags_get_impl(self); + Py_END_CRITICAL_SECTION(); -exit: return return_value; } -PyDoc_STRVAR(_ssl__SSLContext_set_ciphers__doc__, -"set_ciphers($self, cipherlist, /)\n" -"--\n" -"\n"); +#if defined(_SSL__SSLCONTEXT__HOST_FLAGS_HAS_DOCSTR) +# define _ssl__SSLContext__host_flags_DOCSTR _ssl__SSLContext__host_flags__doc__ +#else +# define _ssl__SSLContext__host_flags_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF) +# undef _SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF +# define _SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF {"_host_flags", (getter)_ssl__SSLContext__host_flags_get, (setter)_ssl__SSLContext__host_flags_set, _ssl__SSLContext__host_flags_DOCSTR}, +#else +# define _SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF {"_host_flags", NULL, (setter)_ssl__SSLContext__host_flags_set, NULL}, +#endif -#define _SSL__SSLCONTEXT_SET_CIPHERS_METHODDEF \ - {"set_ciphers", (PyCFunction)_ssl__SSLContext_set_ciphers, METH_O, _ssl__SSLContext_set_ciphers__doc__}, +static int +_ssl__SSLContext__host_flags_set_impl(PySSLContext *self, PyObject *value); + +static int +_ssl__SSLContext__host_flags_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext__host_flags_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_check_hostname_HAS_DOCSTR) +# define _ssl__SSLContext_check_hostname_DOCSTR _ssl__SSLContext_check_hostname__doc__ +#else +# define _ssl__SSLContext_check_hostname_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF) +# undef _SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF +# define _SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF {"check_hostname", (getter)_ssl__SSLContext_check_hostname_get, (setter)_ssl__SSLContext_check_hostname_set, _ssl__SSLContext_check_hostname_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF {"check_hostname", (getter)_ssl__SSLContext_check_hostname_get, NULL, _ssl__SSLContext_check_hostname_DOCSTR}, +#endif static PyObject * -_ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist); +_ssl__SSLContext_check_hostname_get_impl(PySSLContext *self); static PyObject * -_ssl__SSLContext_set_ciphers(PySSLContext *self, PyObject *arg) +_ssl__SSLContext_check_hostname_get(PySSLContext *self, void *Py_UNUSED(context)) { PyObject *return_value = NULL; - const char *cipherlist; - if (!PyUnicode_Check(arg)) { - _PyArg_BadArgument("set_ciphers", "argument", "str", arg); - goto exit; - } - Py_ssize_t cipherlist_length; - cipherlist = PyUnicode_AsUTF8AndSize(arg, &cipherlist_length); - if (cipherlist == NULL) { - goto exit; - } - if (strlen(cipherlist) != (size_t)cipherlist_length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } - return_value = _ssl__SSLContext_set_ciphers_impl(self, cipherlist); + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_check_hostname_get_impl(self); + Py_END_CRITICAL_SECTION(); -exit: return return_value; } -PyDoc_STRVAR(_ssl__SSLContext_get_ciphers__doc__, -"get_ciphers($self, /)\n" -"--\n" -"\n"); - -#define _SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF \ - {"get_ciphers", (PyCFunction)_ssl__SSLContext_get_ciphers, METH_NOARGS, _ssl__SSLContext_get_ciphers__doc__}, +#if defined(_SSL__SSLCONTEXT_CHECK_HOSTNAME_HAS_DOCSTR) +# define _ssl__SSLContext_check_hostname_DOCSTR _ssl__SSLContext_check_hostname__doc__ +#else +# define _ssl__SSLContext_check_hostname_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF) +# undef _SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF +# define _SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF {"check_hostname", (getter)_ssl__SSLContext_check_hostname_get, (setter)_ssl__SSLContext_check_hostname_set, _ssl__SSLContext_check_hostname_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_CHECK_HOSTNAME_GETSETDEF {"check_hostname", NULL, (setter)_ssl__SSLContext_check_hostname_set, NULL}, +#endif -static PyObject * -_ssl__SSLContext_get_ciphers_impl(PySSLContext *self); +static int +_ssl__SSLContext_check_hostname_set_impl(PySSLContext *self, PyObject *value); -static PyObject * -_ssl__SSLContext_get_ciphers(PySSLContext *self, PyObject *Py_UNUSED(ignored)) +static int +_ssl__SSLContext_check_hostname_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) { - return _ssl__SSLContext_get_ciphers_impl(self); -} + int return_value; -PyDoc_STRVAR(_ssl__SSLContext__set_alpn_protocols__doc__, -"_set_alpn_protocols($self, protos, /)\n" -"--\n" -"\n"); + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_check_hostname_set_impl(self, value); + Py_END_CRITICAL_SECTION(); -#define _SSL__SSLCONTEXT__SET_ALPN_PROTOCOLS_METHODDEF \ - {"_set_alpn_protocols", (PyCFunction)_ssl__SSLContext__set_alpn_protocols, METH_O, _ssl__SSLContext__set_alpn_protocols__doc__}, + return return_value; +} + +#if defined(_ssl__SSLContext_protocol_HAS_DOCSTR) +# define _ssl__SSLContext_protocol_DOCSTR _ssl__SSLContext_protocol__doc__ +#else +# define _ssl__SSLContext_protocol_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_PROTOCOL_GETSETDEF) +# undef _SSL__SSLCONTEXT_PROTOCOL_GETSETDEF +# define _SSL__SSLCONTEXT_PROTOCOL_GETSETDEF {"protocol", (getter)_ssl__SSLContext_protocol_get, (setter)_ssl__SSLContext_protocol_set, _ssl__SSLContext_protocol_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_PROTOCOL_GETSETDEF {"protocol", (getter)_ssl__SSLContext_protocol_get, NULL, _ssl__SSLContext_protocol_DOCSTR}, +#endif static PyObject * -_ssl__SSLContext__set_alpn_protocols_impl(PySSLContext *self, - Py_buffer *protos); +_ssl__SSLContext_protocol_get_impl(PySSLContext *self); static PyObject * -_ssl__SSLContext__set_alpn_protocols(PySSLContext *self, PyObject *arg) +_ssl__SSLContext_protocol_get(PySSLContext *self, void *Py_UNUSED(context)) { PyObject *return_value = NULL; - Py_buffer protos = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &protos, PyBUF_SIMPLE) != 0) { - goto exit; - } - return_value = _ssl__SSLContext__set_alpn_protocols_impl(self, &protos); - -exit: - /* Cleanup for protos */ - if (protos.obj) { - PyBuffer_Release(&protos); - } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_protocol_get_impl(self); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -599,7 +1423,9 @@ _ssl__SSLContext_load_cert_chain(PySSLContext *self, PyObject *const *args, Py_s } password = args[2]; skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext_load_cert_chain_impl(self, certfile, keyfile, password); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -675,7 +1501,9 @@ _ssl__SSLContext_load_verify_locations(PySSLContext *self, PyObject *const *args } cadata = args[2]; skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext_load_verify_locations_impl(self, cafile, capath, cadata); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -689,6 +1517,21 @@ PyDoc_STRVAR(_ssl__SSLContext_load_dh_params__doc__, #define _SSL__SSLCONTEXT_LOAD_DH_PARAMS_METHODDEF \ {"load_dh_params", (PyCFunction)_ssl__SSLContext_load_dh_params, METH_O, _ssl__SSLContext_load_dh_params__doc__}, +static PyObject * +_ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath); + +static PyObject * +_ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_load_dh_params_impl(self, filepath); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(_ssl__SSLContext__wrap_socket__doc__, "_wrap_socket($self, /, sock, server_side, server_hostname=None, *,\n" " owner=None, session=None)\n" @@ -774,7 +1617,9 @@ _ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssiz } session = args[4]; skip_optional_kwonly: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext__wrap_socket_impl(self, sock, server_side, hostname_obj, owner, session); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -872,7 +1717,9 @@ _ssl__SSLContext__wrap_bio(PySSLContext *self, PyObject *const *args, Py_ssize_t } session = args[5]; skip_optional_kwonly: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext__wrap_bio_impl(self, incoming, outgoing, server_side, hostname_obj, owner, session); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -892,7 +1739,13 @@ _ssl__SSLContext_session_stats_impl(PySSLContext *self); static PyObject * _ssl__SSLContext_session_stats(PySSLContext *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLContext_session_stats_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_session_stats_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLContext_set_default_verify_paths__doc__, @@ -909,7 +1762,13 @@ _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self); static PyObject * _ssl__SSLContext_set_default_verify_paths(PySSLContext *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLContext_set_default_verify_paths_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_set_default_verify_paths_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLContext_set_ecdh_curve__doc__, @@ -920,6 +1779,75 @@ PyDoc_STRVAR(_ssl__SSLContext_set_ecdh_curve__doc__, #define _SSL__SSLCONTEXT_SET_ECDH_CURVE_METHODDEF \ {"set_ecdh_curve", (PyCFunction)_ssl__SSLContext_set_ecdh_curve, METH_O, _ssl__SSLContext_set_ecdh_curve__doc__}, +static PyObject * +_ssl__SSLContext_set_ecdh_curve_impl(PySSLContext *self, PyObject *name); + +static PyObject * +_ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_set_ecdh_curve_impl(self, name); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl__SSLContext_sni_callback_HAS_DOCSTR) +# define _ssl__SSLContext_sni_callback_DOCSTR _ssl__SSLContext_sni_callback__doc__ +#else +# define _ssl__SSLContext_sni_callback_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF) +# undef _SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF +# define _SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF {"sni_callback", (getter)_ssl__SSLContext_sni_callback_get, (setter)_ssl__SSLContext_sni_callback_set, _ssl__SSLContext_sni_callback_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF {"sni_callback", (getter)_ssl__SSLContext_sni_callback_get, NULL, _ssl__SSLContext_sni_callback_DOCSTR}, +#endif + +static PyObject * +_ssl__SSLContext_sni_callback_get_impl(PySSLContext *self); + +static PyObject * +_ssl__SSLContext_sni_callback_get(PySSLContext *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_sni_callback_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_SSL__SSLCONTEXT_SNI_CALLBACK_HAS_DOCSTR) +# define _ssl__SSLContext_sni_callback_DOCSTR _ssl__SSLContext_sni_callback__doc__ +#else +# define _ssl__SSLContext_sni_callback_DOCSTR NULL +#endif +#if defined(_SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF) +# undef _SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF +# define _SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF {"sni_callback", (getter)_ssl__SSLContext_sni_callback_get, (setter)_ssl__SSLContext_sni_callback_set, _ssl__SSLContext_sni_callback_DOCSTR}, +#else +# define _SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF {"sni_callback", NULL, (setter)_ssl__SSLContext_sni_callback_set, NULL}, +#endif + +static int +_ssl__SSLContext_sni_callback_set_impl(PySSLContext *self, PyObject *value); + +static int +_ssl__SSLContext_sni_callback_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_sni_callback_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(_ssl__SSLContext_cert_store_stats__doc__, "cert_store_stats($self, /)\n" "--\n" @@ -941,7 +1869,13 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self); static PyObject * _ssl__SSLContext_cert_store_stats(PySSLContext *self, PyObject *Py_UNUSED(ignored)) { - return _ssl__SSLContext_cert_store_stats_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_cert_store_stats_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl__SSLContext_get_ca_certs__doc__, @@ -1007,7 +1941,9 @@ _ssl__SSLContext_get_ca_certs(PySSLContext *self, PyObject *const *args, Py_ssiz goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext_get_ca_certs_impl(self, binary_form); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1062,7 +1998,9 @@ _ssl__SSLContext_set_psk_client_callback(PySSLContext *self, PyObject *const *ar goto exit; } callback = args[0]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext_set_psk_client_callback_impl(self, callback); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1142,7 +2080,9 @@ _ssl__SSLContext_set_psk_server_callback(PySSLContext *self, PyObject *const *ar goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext_set_psk_server_callback_impl(self, callback, identity_hint); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1165,12 +2105,68 @@ _ssl_MemoryBIO(PyTypeObject *type, PyObject *args, PyObject *kwargs) !_PyArg_NoKeywords("MemoryBIO", kwargs)) { goto exit; } + Py_BEGIN_CRITICAL_SECTION(type); return_value = _ssl_MemoryBIO_impl(type); + Py_END_CRITICAL_SECTION(); exit: return return_value; } +#if defined(_ssl_MemoryBIO_pending_HAS_DOCSTR) +# define _ssl_MemoryBIO_pending_DOCSTR _ssl_MemoryBIO_pending__doc__ +#else +# define _ssl_MemoryBIO_pending_DOCSTR NULL +#endif +#if defined(_SSL_MEMORYBIO_PENDING_GETSETDEF) +# undef _SSL_MEMORYBIO_PENDING_GETSETDEF +# define _SSL_MEMORYBIO_PENDING_GETSETDEF {"pending", (getter)_ssl_MemoryBIO_pending_get, (setter)_ssl_MemoryBIO_pending_set, _ssl_MemoryBIO_pending_DOCSTR}, +#else +# define _SSL_MEMORYBIO_PENDING_GETSETDEF {"pending", (getter)_ssl_MemoryBIO_pending_get, NULL, _ssl_MemoryBIO_pending_DOCSTR}, +#endif + +static PyObject * +_ssl_MemoryBIO_pending_get_impl(PySSLMemoryBIO *self); + +static PyObject * +_ssl_MemoryBIO_pending_get(PySSLMemoryBIO *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_MemoryBIO_pending_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl_MemoryBIO_eof_HAS_DOCSTR) +# define _ssl_MemoryBIO_eof_DOCSTR _ssl_MemoryBIO_eof__doc__ +#else +# define _ssl_MemoryBIO_eof_DOCSTR NULL +#endif +#if defined(_SSL_MEMORYBIO_EOF_GETSETDEF) +# undef _SSL_MEMORYBIO_EOF_GETSETDEF +# define _SSL_MEMORYBIO_EOF_GETSETDEF {"eof", (getter)_ssl_MemoryBIO_eof_get, (setter)_ssl_MemoryBIO_eof_set, _ssl_MemoryBIO_eof_DOCSTR}, +#else +# define _SSL_MEMORYBIO_EOF_GETSETDEF {"eof", (getter)_ssl_MemoryBIO_eof_get, NULL, _ssl_MemoryBIO_eof_DOCSTR}, +#endif + +static PyObject * +_ssl_MemoryBIO_eof_get_impl(PySSLMemoryBIO *self); + +static PyObject * +_ssl_MemoryBIO_eof_get(PySSLMemoryBIO *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_MemoryBIO_eof_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(_ssl_MemoryBIO_read__doc__, "read($self, size=-1, /)\n" "--\n" @@ -1205,7 +2201,9 @@ _ssl_MemoryBIO_read(PySSLMemoryBIO *self, PyObject *const *args, Py_ssize_t narg goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl_MemoryBIO_read_impl(self, len); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1234,7 +2232,9 @@ _ssl_MemoryBIO_write(PySSLMemoryBIO *self, PyObject *arg) if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { goto exit; } + Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl_MemoryBIO_write_impl(self, &b); + Py_END_CRITICAL_SECTION(); exit: /* Cleanup for b */ @@ -1262,7 +2262,148 @@ _ssl_MemoryBIO_write_eof_impl(PySSLMemoryBIO *self); static PyObject * _ssl_MemoryBIO_write_eof(PySSLMemoryBIO *self, PyObject *Py_UNUSED(ignored)) { - return _ssl_MemoryBIO_write_eof_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_MemoryBIO_write_eof_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl_SSLSession_time_HAS_DOCSTR) +# define _ssl_SSLSession_time_DOCSTR _ssl_SSLSession_time__doc__ +#else +# define _ssl_SSLSession_time_DOCSTR NULL +#endif +#if defined(_SSL_SSLSESSION_TIME_GETSETDEF) +# undef _SSL_SSLSESSION_TIME_GETSETDEF +# define _SSL_SSLSESSION_TIME_GETSETDEF {"time", (getter)_ssl_SSLSession_time_get, (setter)_ssl_SSLSession_time_set, _ssl_SSLSession_time_DOCSTR}, +#else +# define _SSL_SSLSESSION_TIME_GETSETDEF {"time", (getter)_ssl_SSLSession_time_get, NULL, _ssl_SSLSession_time_DOCSTR}, +#endif + +static PyObject * +_ssl_SSLSession_time_get_impl(PySSLSession *self); + +static PyObject * +_ssl_SSLSession_time_get(PySSLSession *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_SSLSession_time_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl_SSLSession_timeout_HAS_DOCSTR) +# define _ssl_SSLSession_timeout_DOCSTR _ssl_SSLSession_timeout__doc__ +#else +# define _ssl_SSLSession_timeout_DOCSTR NULL +#endif +#if defined(_SSL_SSLSESSION_TIMEOUT_GETSETDEF) +# undef _SSL_SSLSESSION_TIMEOUT_GETSETDEF +# define _SSL_SSLSESSION_TIMEOUT_GETSETDEF {"timeout", (getter)_ssl_SSLSession_timeout_get, (setter)_ssl_SSLSession_timeout_set, _ssl_SSLSession_timeout_DOCSTR}, +#else +# define _SSL_SSLSESSION_TIMEOUT_GETSETDEF {"timeout", (getter)_ssl_SSLSession_timeout_get, NULL, _ssl_SSLSession_timeout_DOCSTR}, +#endif + +static PyObject * +_ssl_SSLSession_timeout_get_impl(PySSLSession *self); + +static PyObject * +_ssl_SSLSession_timeout_get(PySSLSession *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_SSLSession_timeout_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl_SSLSession_ticket_lifetime_hint_HAS_DOCSTR) +# define _ssl_SSLSession_ticket_lifetime_hint_DOCSTR _ssl_SSLSession_ticket_lifetime_hint__doc__ +#else +# define _ssl_SSLSession_ticket_lifetime_hint_DOCSTR NULL +#endif +#if defined(_SSL_SSLSESSION_TICKET_LIFETIME_HINT_GETSETDEF) +# undef _SSL_SSLSESSION_TICKET_LIFETIME_HINT_GETSETDEF +# define _SSL_SSLSESSION_TICKET_LIFETIME_HINT_GETSETDEF {"ticket_lifetime_hint", (getter)_ssl_SSLSession_ticket_lifetime_hint_get, (setter)_ssl_SSLSession_ticket_lifetime_hint_set, _ssl_SSLSession_ticket_lifetime_hint_DOCSTR}, +#else +# define _SSL_SSLSESSION_TICKET_LIFETIME_HINT_GETSETDEF {"ticket_lifetime_hint", (getter)_ssl_SSLSession_ticket_lifetime_hint_get, NULL, _ssl_SSLSession_ticket_lifetime_hint_DOCSTR}, +#endif + +static PyObject * +_ssl_SSLSession_ticket_lifetime_hint_get_impl(PySSLSession *self); + +static PyObject * +_ssl_SSLSession_ticket_lifetime_hint_get(PySSLSession *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_SSLSession_ticket_lifetime_hint_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl_SSLSession_id_HAS_DOCSTR) +# define _ssl_SSLSession_id_DOCSTR _ssl_SSLSession_id__doc__ +#else +# define _ssl_SSLSession_id_DOCSTR NULL +#endif +#if defined(_SSL_SSLSESSION_ID_GETSETDEF) +# undef _SSL_SSLSESSION_ID_GETSETDEF +# define _SSL_SSLSESSION_ID_GETSETDEF {"id", (getter)_ssl_SSLSession_id_get, (setter)_ssl_SSLSession_id_set, _ssl_SSLSession_id_DOCSTR}, +#else +# define _SSL_SSLSESSION_ID_GETSETDEF {"id", (getter)_ssl_SSLSession_id_get, NULL, _ssl_SSLSession_id_DOCSTR}, +#endif + +static PyObject * +_ssl_SSLSession_id_get_impl(PySSLSession *self); + +static PyObject * +_ssl_SSLSession_id_get(PySSLSession *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_SSLSession_id_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_ssl_SSLSession_has_ticket_HAS_DOCSTR) +# define _ssl_SSLSession_has_ticket_DOCSTR _ssl_SSLSession_has_ticket__doc__ +#else +# define _ssl_SSLSession_has_ticket_DOCSTR NULL +#endif +#if defined(_SSL_SSLSESSION_HAS_TICKET_GETSETDEF) +# undef _SSL_SSLSESSION_HAS_TICKET_GETSETDEF +# define _SSL_SSLSESSION_HAS_TICKET_GETSETDEF {"has_ticket", (getter)_ssl_SSLSession_has_ticket_get, (setter)_ssl_SSLSession_has_ticket_set, _ssl_SSLSession_has_ticket_DOCSTR}, +#else +# define _SSL_SSLSESSION_HAS_TICKET_GETSETDEF {"has_ticket", (getter)_ssl_SSLSession_has_ticket_get, NULL, _ssl_SSLSession_has_ticket_DOCSTR}, +#endif + +static PyObject * +_ssl_SSLSession_has_ticket_get_impl(PySSLSession *self); + +static PyObject * +_ssl_SSLSession_has_ticket_get(PySSLSession *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl_SSLSession_has_ticket_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl_RAND_add__doc__, @@ -1315,7 +2456,9 @@ _ssl_RAND_add(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } } + Py_BEGIN_CRITICAL_SECTION(module); return_value = _ssl_RAND_add_impl(module, &view, entropy); + Py_END_CRITICAL_SECTION(); exit: /* Cleanup for view */ @@ -1348,7 +2491,9 @@ _ssl_RAND_bytes(PyObject *module, PyObject *arg) if (n == -1 && PyErr_Occurred()) { goto exit; } + Py_BEGIN_CRITICAL_SECTION(module); return_value = _ssl_RAND_bytes_impl(module, n); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1372,7 +2517,13 @@ _ssl_RAND_status_impl(PyObject *module); static PyObject * _ssl_RAND_status(PyObject *module, PyObject *Py_UNUSED(ignored)) { - return _ssl_RAND_status_impl(module); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(module); + return_value = _ssl_RAND_status_impl(module); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl_get_default_verify_paths__doc__, @@ -1392,7 +2543,13 @@ _ssl_get_default_verify_paths_impl(PyObject *module); static PyObject * _ssl_get_default_verify_paths(PyObject *module, PyObject *Py_UNUSED(ignored)) { - return _ssl_get_default_verify_paths_impl(module); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(module); + return_value = _ssl_get_default_verify_paths_impl(module); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_ssl_txt2obj__doc__, @@ -1469,7 +2626,9 @@ _ssl_txt2obj(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(module); return_value = _ssl_txt2obj_impl(module, txt, name); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1497,7 +2656,9 @@ _ssl_nid2obj(PyObject *module, PyObject *arg) if (nid == -1 && PyErr_Occurred()) { goto exit; } + Py_BEGIN_CRITICAL_SECTION(module); return_value = _ssl_nid2obj_impl(module, nid); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1572,7 +2733,9 @@ _ssl_enum_certificates(PyObject *module, PyObject *const *args, Py_ssize_t nargs PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } + Py_BEGIN_CRITICAL_SECTION(module); return_value = _ssl_enum_certificates_impl(module, store_name); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1648,7 +2811,9 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } + Py_BEGIN_CRITICAL_SECTION(module); return_value = _ssl_enum_crls_impl(module, store_name); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -1663,4 +2828,4 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=28a22f2b09d631cb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c1489122072a9f5e input=a9049054013a1b77]*/ From 8f5e39d5c885318e3128a3e84464c098b5f79a79 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sat, 19 Oct 2024 14:46:57 -0700 Subject: [PATCH 244/247] gh-125378: Trigger a repeat for the full multi-line statement for empty line command (#125717) --- Lib/pdb.py | 1 + Lib/test/test_pdb.py | 16 +++++++++++++--- ...024-10-19-01-30-40.gh-issue-125378.WTosxX.rst | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-19-01-30-40.gh-issue-125378.WTosxX.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index cd7a7042fa6987..832213abbb98e6 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -755,6 +755,7 @@ def default(self, line): else: line = line.rstrip('\r\n') buffer += '\n' + line + self.lastcmd = buffer save_stdout = sys.stdout save_stdin = sys.stdin save_displayhook = sys.displayhook diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 7e6f276d355a14..1ea93ed037005d 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -2448,7 +2448,12 @@ def test_pdb_multiline_statement(): ... 'def f(x):', ... ' return x * 2', ... '', - ... 'f(2)', + ... 'val = 2', + ... 'if val > 0:', + ... ' val = f(val)', + ... '', + ... '', # empty line should repeat the multi-line statement + ... 'val', ... 'c' ... ]): ... test_function() @@ -2457,8 +2462,13 @@ def test_pdb_multiline_statement(): (Pdb) def f(x): ... return x * 2 ... - (Pdb) f(2) - 4 + (Pdb) val = 2 + (Pdb) if val > 0: + ... val = f(val) + ... + (Pdb) + (Pdb) val + 8 (Pdb) c """ diff --git a/Misc/NEWS.d/next/Library/2024-10-19-01-30-40.gh-issue-125378.WTosxX.rst b/Misc/NEWS.d/next/Library/2024-10-19-01-30-40.gh-issue-125378.WTosxX.rst new file mode 100644 index 00000000000000..dc76889d3b210a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-19-01-30-40.gh-issue-125378.WTosxX.rst @@ -0,0 +1 @@ +Fixed the bug in :mod:`pdb` where after a multi-line command, an empty line repeats the first line of the multi-line command, instead of the full command. From 14cafe1a108cf0be73a27a0001003b5897eec8f0 Mon Sep 17 00:00:00 2001 From: Tom Most Date: Sat, 19 Oct 2024 17:48:06 -0700 Subject: [PATCH 245/247] Doc: Fix pluralization in os.process_cpu_count() documentation (#125678) --- Doc/library/os.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 33dd58febd9a5e..081d7a6f97b079 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -5579,7 +5579,7 @@ Miscellaneous System Information If :option:`-X cpu_count <-X>` is given or :envvar:`PYTHON_CPU_COUNT` is set, :func:`process_cpu_count` returns the overridden value *n*. - See also the :func:`sched_getaffinity` functions. + See also the :func:`sched_getaffinity` function. .. versionadded:: 3.13 From e924bb667a19ee1812d6c7592a37dd37346dda04 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 20 Oct 2024 03:10:17 +0200 Subject: [PATCH 246/247] gh-125698: Replace EXEEXT with EXE_SUFFIX (#125699) --- Makefile.pre.in | 2 +- configure | 22 +++++++++++----------- configure.ac | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index fb6f22d57397db..9c313c8029fb68 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -176,7 +176,7 @@ EXPORTSYMS= @EXPORTSYMS@ EXPORTSFROM= @EXPORTSFROM@ # Executable suffix (.exe on Windows and Mac OS X) -EXE= @EXEEXT@ +EXE= @EXE_SUFFIX@ BUILDEXE= @BUILDEXEEXT@ # Name of the patch file to apply for app store compliance diff --git a/configure b/configure index b11f41d5379958..ab35f69f73011f 100755 --- a/configure +++ b/configure @@ -7296,11 +7296,11 @@ then : withval=$with_suffix; case $with_suffix in #( no) : - EXEEXT= ;; #( + EXE_SUFFIX= ;; #( yes) : - EXEEXT=.exe ;; #( + EXE_SUFFIX=.exe ;; #( *) : - EXEEXT=$with_suffix + EXE_SUFFIX=$with_suffix ;; esac @@ -7308,20 +7308,20 @@ else $as_nop case $ac_sys_system/$ac_sys_emscripten_target in #( Emscripten/browser*) : - EXEEXT=.js ;; #( + EXE_SUFFIX=.js ;; #( Emscripten/node*) : - EXEEXT=.js ;; #( + EXE_SUFFIX=.js ;; #( WASI/*) : - EXEEXT=.wasm ;; #( + EXE_SUFFIX=.wasm ;; #( *) : - EXEEXT= + EXE_SUFFIX= ;; esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXEEXT" >&5 -printf "%s\n" "$EXEEXT" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXE_SUFFIX" >&5 +printf "%s\n" "$EXE_SUFFIX" >&6; } # Test whether we're running on a non-case-sensitive system, in which # case we give a warning if no ext is given @@ -7332,7 +7332,7 @@ if test ! -d CaseSensitiveTestDir; then mkdir CaseSensitiveTestDir fi -if test -d casesensitivetestdir && test -z "$EXEEXT" +if test -d casesensitivetestdir && test -z "$EXE_SUFFIX" then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } @@ -7340,7 +7340,7 @@ printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - BUILDEXEEXT=$EXEEXT + BUILDEXEEXT=$EXE_SUFFIX fi rmdir CaseSensitiveTestDir diff --git a/configure.ac b/configure.ac index d5bc739c34c90f..9e50eae6a7ece8 100644 --- a/configure.ac +++ b/configure.ac @@ -1325,19 +1325,19 @@ AC_ARG_WITH([suffix], [AS_HELP_STRING([--with-suffix=SUFFIX], [set executable suffix to SUFFIX (default is empty, yes is mapped to '.exe')])], [ AS_CASE([$with_suffix], - [no], [EXEEXT=], - [yes], [EXEEXT=.exe], - [EXEEXT=$with_suffix] + [no], [EXE_SUFFIX=], + [yes], [EXE_SUFFIX=.exe], + [EXE_SUFFIX=$with_suffix] ) ], [ AS_CASE([$ac_sys_system/$ac_sys_emscripten_target], - [Emscripten/browser*], [EXEEXT=.js], - [Emscripten/node*], [EXEEXT=.js], - [WASI/*], [EXEEXT=.wasm], - [EXEEXT=] + [Emscripten/browser*], [EXE_SUFFIX=.js], + [Emscripten/node*], [EXE_SUFFIX=.js], + [WASI/*], [EXE_SUFFIX=.wasm], + [EXE_SUFFIX=] ) ]) -AC_MSG_RESULT([$EXEEXT]) +AC_MSG_RESULT([$EXE_SUFFIX]) # Test whether we're running on a non-case-sensitive system, in which # case we give a warning if no ext is given @@ -1347,13 +1347,13 @@ if test ! -d CaseSensitiveTestDir; then mkdir CaseSensitiveTestDir fi -if test -d casesensitivetestdir && test -z "$EXEEXT" +if test -d casesensitivetestdir && test -z "$EXE_SUFFIX" then AC_MSG_RESULT([yes]) BUILDEXEEXT=.exe else AC_MSG_RESULT([no]) - BUILDEXEEXT=$EXEEXT + BUILDEXEEXT=$EXE_SUFFIX fi rmdir CaseSensitiveTestDir From ed24702bd0f9925908ce48584c31dfad732208b2 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 20 Oct 2024 16:55:26 +0900 Subject: [PATCH 247/247] gh-125741: Update check_generated_files CI to use our published container image (gh-125744) --- .github/workflows/build.yml | 53 ++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec7904c2e2cc73..a72d4a1bb97cb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,50 @@ jobs: if: fromJSON(needs.check_source.outputs.run-docs) uses: ./.github/workflows/reusable-docs.yml + check_autoconf_regen: + name: 'Check if Autoconf files are up to date' + # Don't use ubuntu-latest but a specific version to make the job + # reproducible: to get the same tools versions (autoconf, aclocal, ...) + runs-on: ubuntu-24.04 + container: + image: ghcr.io/python/autoconf:2024.10.11.11293396815 + timeout-minutes: 60 + needs: check_source + if: needs.check_source.outputs.run_tests == 'true' + steps: + - name: Install Git + run: | + apt install git -yq + git config --global --add safe.directory "$GITHUB_WORKSPACE" + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - name: Runner image version + run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV + - name: Check Autoconf and aclocal versions + run: | + grep "Generated by GNU Autoconf 2.71" configure + grep "aclocal 1.16.5" aclocal.m4 + grep -q "runstatedir" configure + grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4 + - name: Regenerate autoconf files + # Same command used by Tools/build/regen-configure.sh ($AUTORECONF) + run: autoreconf -ivf -Werror + - name: Check for changes + run: | + git add -u + changes=$(git status --porcelain) + # Check for changes in regenerated files + if test -n "$changes"; then + echo "Generated files not up to date." + echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)" + echo "configure files must be regenerated with a specific version of autoconf." + echo "$changes" + echo "" + git diff --staged || true + exit 1 + fi + check_generated_files: name: 'Check if generated files are up to date' # Don't use ubuntu-latest but a specific version to make the job @@ -69,19 +113,10 @@ jobs: uses: hendrikmuhs/ccache-action@v1.2 with: save: false - - name: Check Autoconf and aclocal versions - run: | - grep "Generated by GNU Autoconf 2.71" configure - grep "aclocal 1.16.5" aclocal.m4 - grep -q "runstatedir" configure - grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4 - name: Configure CPython run: | # Build Python with the libpython dynamic library ./configure --config-cache --with-pydebug --enable-shared - - name: Regenerate autoconf files - # Same command used by Tools/build/regen-configure.sh ($AUTORECONF) - run: autoreconf -ivf -Werror - name: Build CPython run: | make -j4 regen-all