From bb91678bc40587dd1b60febb70ec5639d2d765bf Mon Sep 17 00:00:00 2001 From: Wojusensei <3442006415@qq.com> Date: Sat, 4 Jul 2026 16:49:36 +0800 Subject: [PATCH 01/61] gh-152798: Return 'pymutex' on POSIX except Windows/WASI --- Python/thread.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Python/thread.c b/Python/thread.c index 0365f977d82b0ed..8660e7cbad51f28 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -334,6 +334,11 @@ PyThread_GetInfo(void) #ifdef HAVE_PTHREAD_STUBS value = Py_NewRef(Py_None); +#else +#ifdef MS_WINDOWS + value = Py_NewRef(Py_None); +#elif defined(__wasi__) + value = Py_NewRef(Py_None); #else value = PyUnicode_FromString("pymutex"); if (value == NULL) { @@ -341,6 +346,8 @@ PyThread_GetInfo(void) return NULL; } #endif +#endif + PyStructSequence_SET_ITEM(threadinfo, pos++, value); #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ @@ -361,7 +368,6 @@ PyThread_GetInfo(void) return threadinfo; } - void _PyThread_FiniType(PyInterpreterState *interp) { From b6160b42cc7b0c7ba3a43daff6da99f76a610a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 4 Jul 2026 12:09:42 +0200 Subject: [PATCH 02/61] gh-152851: fix a crash when copying a BLAKE-2s/2b object (#153008) --- .../Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst | 2 ++ Modules/blake2module.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst b/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst new file mode 100644 index 000000000000000..aab033ebeed6954 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-04-11-14-06.gh-issue-152851.diYvTf.rst @@ -0,0 +1,2 @@ +Prevent a crash when allocation fails while copying a :func:`BLAKE-2s/2b +` object. Patch by Bénédikt Tran. diff --git a/Modules/blake2module.c b/Modules/blake2module.c index b71dd20925611ef..ac7265bb9d6836c 100644 --- a/Modules/blake2module.c +++ b/Modules/blake2module.c @@ -757,6 +757,10 @@ blake2_blake2b_copy_unlocked(Blake2Object *self, Blake2Object *cpy) } \ } while (0) + // Ensure that the implementation type is consistent with the HACL* state. + // See https://github.com/python/cpython/issues/152851 for details. + cpy->impl = self->impl; + switch (self->impl) { #if _Py_HACL_CAN_COMPILE_VEC256 case Blake2b_256: @@ -778,7 +782,6 @@ blake2_blake2b_copy_unlocked(Blake2Object *self, Blake2Object *cpy) Py_UNREACHABLE(); } #undef BLAKE2_COPY - cpy->impl = self->impl; return 0; error: From b8ade579e2de300b138c7ffc5a0d3715aed9820e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 4 Jul 2026 12:21:16 +0200 Subject: [PATCH 03/61] gh-153009: Fix compilation of `curses` on platforms that define the `stdscr` macro (#153010) --- Include/py_curses.h | 2 +- ...6-07-04-11-26-24.gh-issue-153009.KGl-nQ.rst | 2 ++ Modules/_cursesmodule.c | 18 +++++++++--------- 3 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-04-11-26-24.gh-issue-153009.KGl-nQ.rst diff --git a/Include/py_curses.h b/Include/py_curses.h index 23e67c4e6e634d0..a5f5f3d76075827 100644 --- a/Include/py_curses.h +++ b/Include/py_curses.h @@ -96,7 +96,7 @@ typedef struct { SCREEN *screen; /* NULL after the screen has been deleted */ FILE *outfp; /* owned output stream, or NULL */ FILE *infp; /* owned input stream, or NULL */ - PyObject *stdscr; /* the screen's standard window, or NULL */ + PyObject *stdscr_win; /* the screen's standard window, or NULL */ } PyCursesScreenObject; #define PyCurses_CAPSULE_NAME "_curses._C_API" diff --git a/Misc/NEWS.d/next/Library/2026-07-04-11-26-24.gh-issue-153009.KGl-nQ.rst b/Misc/NEWS.d/next/Library/2026-07-04-11-26-24.gh-issue-153009.KGl-nQ.rst new file mode 100644 index 000000000000000..a8a74caa41042ac --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-04-11-26-24.gh-issue-153009.KGl-nQ.rst @@ -0,0 +1,2 @@ +Fix compilation of :mod:`curses` on platforms that define the ``stdscr`` +macro. Patch by Bénédikt Tran. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 03e399b252fcfb2..cc68a51f0bed935 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -5125,7 +5125,7 @@ static PyType_Spec PyCursesWindow_Type_spec = { static PyObject * PyCursesScreen_New(cursesmodule_state *state, SCREEN *screen, - FILE *outfp, FILE *infp, PyObject *stdscr) + FILE *outfp, FILE *infp, PyObject *stdscr_win) { PyCursesScreenObject *so = PyObject_GC_New(PyCursesScreenObject, state->screen_type); @@ -5135,7 +5135,7 @@ PyCursesScreen_New(cursesmodule_state *state, SCREEN *screen, so->screen = screen; so->outfp = outfp; so->infp = infp; - so->stdscr = Py_XNewRef(stdscr); + so->stdscr_win = Py_XNewRef(stdscr_win); PyObject_GC_Track((PyObject *)so); return (PyObject *)so; } @@ -5169,17 +5169,17 @@ static PyObject * PyCursesScreen_get_stdscr(PyObject *self, void *Py_UNUSED(closure)) { PyCursesScreenObject *so = _PyCursesScreenObject_CAST(self); - if (so->stdscr == NULL) { + if (so->stdscr_win == NULL) { Py_RETURN_NONE; } - return Py_NewRef(so->stdscr); + return Py_NewRef(so->stdscr_win); } static int PyCursesScreen_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); - Py_VISIT(_PyCursesScreenObject_CAST(self)->stdscr); + Py_VISIT(_PyCursesScreenObject_CAST(self)->stdscr_win); return 0; } @@ -5194,10 +5194,10 @@ PyCursesScreen_clear(PyObject *self) detach it from its wrapper first: the wrapper must not delwin() a window that delscreen() frees. Any further use of the wrapper operates on a NULL window and fails cleanly. */ - if (so->stdscr != NULL) { - ((PyCursesWindowObject *)so->stdscr)->win = NULL; + if (so->stdscr_win != NULL) { + ((PyCursesWindowObject *)so->stdscr_win)->win = NULL; } - Py_CLEAR(so->stdscr); + Py_CLEAR(so->stdscr_win); return 0; } @@ -6724,7 +6724,7 @@ _curses_newterm_impl(PyObject *module, const char *type, PyObject *fd, Py_DECREF(screenobj); return NULL; } - ((PyCursesScreenObject *)screenobj)->stdscr = Py_NewRef(win); + ((PyCursesScreenObject *)screenobj)->stdscr_win = Py_NewRef(win); Py_DECREF(win); Py_XSETREF(state->topscreen, Py_NewRef(screenobj)); return screenobj; From 61f111e7d364f3db613b9b4de08c3e4d53c34fcc Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 4 Jul 2026 15:05:07 +0300 Subject: [PATCH 04/61] gh-135661: Fix abrupt closing of empty comment in HTMLParser (GH-153007) An abruptly closed empty comment ("" or "") no longer extends up to a later "-->" in the same feed() call. test_htmlparser now also feeds each string source as a single chunk, in addition to one character at a time, to exercise different input buffering. Co-authored-by: Claude Opus 4.8 --- Lib/html/parser.py | 6 ++++-- Lib/test/test_htmlparser.py | 10 ++++++++++ .../2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst diff --git a/Lib/html/parser.py b/Lib/html/parser.py index 80fb8c3f929f6b6..38ddf9ef442d368 100644 --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -387,9 +387,11 @@ def parse_html_declaration(self, i): def parse_comment(self, i, report=True): rawdata = self.rawdata assert rawdata.startswith('" or "--!>" close. + match = commentabruptclose.match(rawdata, i+4) if not match: - match = commentabruptclose.match(rawdata, i+4) + match = commentclose.search(rawdata, i+4) if not match: return -1 if report: diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py index e4eff1ea17a670b..6b7624f11505d92 100644 --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -116,6 +116,11 @@ def _run_check(self, source, expected_events, *, collector=None, convert_charrefs=False): if collector is None: collector = self.get_collector(convert_charrefs=convert_charrefs) + if isinstance(source, str): + # Also feed the whole string at once, not just character by + # character (below), to exercise different input buffering. + self._run_check([source], expected_events, + convert_charrefs=convert_charrefs) parser = collector for s in source: parser.feed(s) @@ -593,6 +598,9 @@ def test_comments(self): ' -->' '' '' + # abruptly closed empty comment must not swallow later text + 'x-->' + 'y-->' ) expected = [('comment', " I'm a valid comment "), ('comment', 'me too!'), @@ -613,6 +621,8 @@ def test_comments(self): ('comment', ' '), ('comment', ''), + ('comment', ''), ('data', 'y-->'), ] self._run_check(html, expected) diff --git a/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst b/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst new file mode 100644 index 000000000000000..26a912a6f3a1949 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-04-13-00-00.gh-issue-135661.CIkADG.rst @@ -0,0 +1,3 @@ +Fix :class:`html.parser.HTMLParser`: an abruptly closed empty comment +(```` or ````) no longer extends up to a later ``-->`` in the same +:meth:`~html.parser.HTMLParser.feed` call. From 844dbd6972ac9f0b65e7d406833ec02a809c6117 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Sat, 4 Jul 2026 06:16:02 -0700 Subject: [PATCH 05/61] gh-152068: Reset PyREPL Colors on prompt finish (#152108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use ANSI Escape Codes from Colorize * Print ANSI Color reset on finish and restore * 📜🤖 Added by blurb_it. * Update imports * Update Misc/NEWS.d/next/macOS/2026-06-24-18-00-39.gh-issue-152068.ThsmJU.rst Co-authored-by: Pablo Galindo Salgado * Remove news entry * 📜🤖 Added by blurb_it. * gh-152068: Test ANSI reset is emitted on console finish() and restore() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Pablo Galindo Salgado Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Lib/_pyrepl/render.py | 10 ++++---- Lib/_pyrepl/unix_console.py | 4 ++++ Lib/_pyrepl/windows_console.py | 5 ++++ Lib/test/test_pyrepl/test_unix_console.py | 19 +++++++++++++++ Lib/test/test_pyrepl/test_windows_console.py | 23 +++++++++++++++++++ ...-07-02-19-21-15.gh-issue-152068.ThsmJU.rst | 1 + 6 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst diff --git a/Lib/_pyrepl/render.py b/Lib/_pyrepl/render.py index b821f35d850825e..b835778e366c539 100644 --- a/Lib/_pyrepl/render.py +++ b/Lib/_pyrepl/render.py @@ -4,8 +4,10 @@ from dataclasses import dataclass, field from typing import Literal, Protocol, Self -from .utils import ANSI_ESCAPE_SEQUENCE, THEME, StyleRef, str_width +from _colorize import ANSIColors + from .types import CursorXY +from .utils import ANSI_ESCAPE_SEQUENCE, THEME, StyleRef, str_width type RenderStyle = StyleRef | str | None type LineUpdateKind = Literal[ @@ -55,7 +57,7 @@ def _style_escape(style: StyleRef) -> str: def _update_terminal_state(state: str, escape: str) -> str: - if escape in {"\x1b[0m", "\x1b[m"}: + if escape in {ANSIColors.RESET, "\x1b[m"}: return "" return state + escape @@ -344,14 +346,14 @@ def render_cells( target_escape += visual_style if target_escape != active_escape: if active_escape: - rendered.append("\x1b[0m") + rendered.append(ANSIColors.RESET) if target_escape: rendered.append(target_escape) active_escape = target_escape rendered.append(cell.text) if active_escape: - rendered.append("\x1b[0m") + rendered.append(ANSIColors.RESET) return "".join(rendered) diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py index 9a4f8e0c623abfa..8edd1c36a7232d7 100644 --- a/Lib/_pyrepl/unix_console.py +++ b/Lib/_pyrepl/unix_console.py @@ -36,6 +36,8 @@ from fcntl import ioctl from typing import TYPE_CHECKING, overload +from _colorize import ANSIColors + from . import terminfo from .console import Console, Event from .fancy_termios import tcgetattr, tcsetattr, TermState @@ -517,6 +519,7 @@ def restore(self) -> None: Restore the console to the default state """ trace("unix.restore") + self.__write(ANSIColors.RESET) self.__disable_bracketed_paste() self.__maybe_write_code(self._rmkx) self.flushoutput() @@ -654,6 +657,7 @@ def finish(self): while y >= 0 and not rendered_lines[y].text: y -= 1 self.__move(0, min(y, self.height + self.__offset - 1)) + self.__write(ANSIColors.RESET) self.__write("\n\r") self.flushoutput() diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index c1f9a19545d35fd..3768a22ad16f7bb 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -39,6 +39,9 @@ ) from ctypes import Structure, POINTER, Union from typing import TYPE_CHECKING + +from _colorize import ANSIColors + from .console import Event, Console from .render import ( EMPTY_RENDER_LINE, @@ -480,6 +483,7 @@ def prepare(self) -> None: def restore(self) -> None: trace("windows.restore") if self.__vt_support: + self.__write(ANSIColors.RESET) # Recover to original mode before running REPL self._disable_bracketed_paste() if not SetConsoleMode(InHandle, self.__original_input_mode): @@ -647,6 +651,7 @@ def finish(self) -> None: while y >= 0 and not rendered_lines[y].text: y -= 1 self._move_relative(0, min(y, self.height + self.__offset - 1)) + self.__write(ANSIColors.RESET) self.__write("\r\n") def flushoutput(self) -> None: diff --git a/Lib/test/test_pyrepl/test_unix_console.py b/Lib/test/test_pyrepl/test_unix_console.py index 71b2e17e3341510..2fc8398923cbf38 100644 --- a/Lib/test/test_pyrepl/test_unix_console.py +++ b/Lib/test/test_pyrepl/test_unix_console.py @@ -6,6 +6,7 @@ import threading import unittest from functools import partial +from _colorize import ANSIColors from test.support import force_color, os_helper, force_not_colorized_test_class from test.support import threading_helper @@ -147,6 +148,24 @@ def test_no_newline(self, _os_write): self.assertNotIn(call(ANY, b'\n'), _os_write.mock_calls) con.restore() + def test_reset_on_finish(self, _os_write): + # gh-152068: finish() must emit the ANSI reset sequence so any + # active color does not leak past the prompt. + code = "1" + events = code_to_events(code) + _, con = handle_events_unix_console(events) + con.finish() + _os_write.assert_any_call(ANY, ANSIColors.RESET.encode(con.encoding)) + con.restore() + + def test_reset_on_restore(self, _os_write): + # gh-152068: restore() must emit the ANSI reset sequence. + code = "1" + events = code_to_events(code) + _, con = handle_events_unix_console(events) + con.restore() + _os_write.assert_any_call(ANY, ANSIColors.RESET.encode(con.encoding)) + def test_newline(self, _os_write): code = "\n" events = code_to_events(code) diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py index 2b6075b3274c05c..32c4255aa6b1904 100644 --- a/Lib/test/test_pyrepl/test_windows_console.py +++ b/Lib/test/test_pyrepl/test_windows_console.py @@ -6,6 +6,7 @@ import itertools +from _colorize import ANSIColors from functools import partial from test.support import force_not_colorized_test_class from typing import Iterable @@ -380,6 +381,28 @@ def test_multiline_ctrl_z(self): self.assertEqual(reader.cxy, (2, 3)) con.restore() + def test_reset_on_finish(self): + # gh-152068: finish() must emit the ANSI reset sequence so any + # active color does not leak past the prompt. + code = "1" + events = code_to_events(code) + _, con = self.handle_events(events) + con.finish() + con.out.write.assert_any_call(ANSIColors.RESET.encode(con.encoding)) + con.restore() + + def test_reset_on_restore(self): + # gh-152068: restore() must emit the ANSI reset sequence when VT + # support is enabled. + code = "1" + events = code_to_events(code) + _, con = self.handle_events(events) + con._WindowsConsole__vt_support = True + con._WindowsConsole__original_input_mode = 0 + with patch.object(wc, "SetConsoleMode", return_value=1): + con.restore() + con.out.write.assert_any_call(ANSIColors.RESET.encode(con.encoding)) + @patch.object(WindowsConsole, '__init__', _mock_console_init) class WindowsConsoleGetEventTests(TestCase): diff --git a/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst b/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst new file mode 100644 index 000000000000000..9ec8413b4ac424c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-19-21-15.gh-issue-152068.ThsmJU.rst @@ -0,0 +1 @@ +Fixes a bug when a line was split (particularly on macOS Terminal.app) in the middle of a colorized keyword, causing the ANSI Color Reset sequence (ESC0m) to not be properly printed, causing the output to be colored when it shouldn't From 612929bc6f1b139d47252395d9456a5681fac951 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 4 Jul 2026 16:17:58 +0300 Subject: [PATCH 06/61] gh-150459: Fix `SyntaxError` message for `from x lazy import y` (#150877) --- Grammar/python.gram | 8 +- Include/internal/pycore_pyerrors.h | 8 +- Lib/test/test_syntax.py | 93 ++ ...-06-03-21-14-28.gh-issue-150459.qpsCEl.rst | 3 + Parser/action_helpers.c | 71 +- Parser/parser.c | 863 ++++++++++-------- Parser/pegen.h | 6 +- 7 files changed, 651 insertions(+), 401 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index a8adeb566aaf5d1..221629a6230270d 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -229,8 +229,9 @@ import_name[stmt_ty]: # note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS import_from[stmt_ty]: + | invalid_import_from | lazy="lazy"? 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets { - _PyPegen_checked_future_import(p, b->v.Name.id, c, _PyPegen_seq_count_dots(a), lazy, EXTRA) } + _PyPegen_checked_from_import(p, a, b, c, lazy, EXTRA) } | lazy="lazy"? 'from' a=('.' | '...')+ 'import' b=import_from_targets { _PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), lazy ? 1 : 0, EXTRA) } import_from_targets[asdl_alias_seq*]: @@ -1445,6 +1446,11 @@ invalid_import_from_as_name: RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use %s as import target", _PyPegen_get_expr_name(a)) } +invalid_import_from: + | 'from' ('.' | '...')* dotted_name a="lazy" 'import' import_from_targets { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, + "use 'lazy from ... ' instead of 'from ... lazy import'") } + invalid_import_from_targets: | import_from_as_names ',' NEWLINE { RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") } diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h index e436aa6bf12cb27..c1f9d71e40077c1 100644 --- a/Include/internal/pycore_pyerrors.h +++ b/Include/internal/pycore_pyerrors.h @@ -123,9 +123,11 @@ extern void _PyErr_SetNone(PyThreadState *tstate, PyObject *exception); extern PyObject* _PyErr_NoMemory(PyThreadState *tstate); -extern int _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset, - int end_lineno, int end_col_offset, - PyObject *module); +// Export for test_peg_generator +PyAPI_FUNC(int) _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, + int lineno, int col_offset, + int end_lineno, int end_col_offset, + PyObject *module); extern void _PyErr_RaiseSyntaxError(PyObject *msg, PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset); diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 04e60c74ce1bea6..013917614178fde 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -2872,6 +2872,14 @@ def check_warning(self, code, errtext, filename="", mode="exec"): with self.assertWarnsRegex(SyntaxWarning, errtext): compile(code, filename, mode) + def check_no_warning(self, code, filename="", mode="exec"): + """Check that compiling code does not raise any warnings.""" + import warnings + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + compile(code, filename, mode) + self.assertEqual(caught, []) + def test_return_in_finally(self): source = textwrap.dedent(""" def f(): @@ -2942,6 +2950,75 @@ def test_break_and_continue_in_finally(self): """) self.check_warning(source, f"'{kw}' in a 'finally' block") + def test_from_lazy_imports(self): + # gh-150459 + self.check_warning( + "from . lazy import x", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from . lazy import x as y", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from . lazy import *", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from .. lazy import x", + "did you mean 'lazy from .. import'?", + ) + self.check_warning( + "from ... lazy import x", + "did you mean 'lazy from ... import'?", + ) + self.check_warning( + "from .... lazy import x", + "did you mean 'lazy from .... import'?", + ) + self.check_warning( + "from . \\\n lazy import x", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from .\\\nlazy import x", + "did you mean 'lazy from . import'?", + ) + self.check_warning( + "from .\tlazy import x", + "did you mean 'lazy from . import'?", + ) + + def test_not_from_lazy_imports(self): + self.check_no_warning("from .lazy import x") + self.check_no_warning("from .lazy import *") + self.check_no_warning("from ..lazy import x") + self.check_no_warning("from ...lazy import x") + self.check_no_warning("from .lazy.sub import x") + self.check_no_warning("from ..lazy.sub import x") + self.check_no_warning("from ...lazy.sub import x") + self.check_no_warning("from . lazier import x") + self.check_no_warning("from . lazy_module import x") + self.check_no_warning("from . lazy.sub import x") + self.check_no_warning("from . sub.lazy import x") + self.check_no_warning("from lazy import x") + self.check_no_warning("from lazy.sub import x") + self.check_no_warning("lazy from . lazy import x") + self.check_no_warning("from . import lazy") + + def test_from_lazy_imports_as_error(self): + import warnings + with warnings.catch_warnings(): + warnings.simplefilter("error", SyntaxWarning) + with self.assertRaisesRegex( + SyntaxError, + re.escape("did you mean 'lazy from . import'?"), + ) as cm: + compile("from . lazy import x", "", "exec") + self.assertEqual(cm.exception.lineno, 1) + self.assertEqual(cm.exception.offset, 8) + self.assertEqual(cm.exception.end_offset, 12) + class SyntaxErrorTestCase(unittest.TestCase): @@ -3662,6 +3739,22 @@ def inner(): lazy from collections import deque """, "lazy from ... import not allowed inside functions") + self._check_error("""\ +from os lazy import path +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from os.path lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from .mod lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from ..mod lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + self._check_error("""\ +from ...mod lazy import join +""", "use 'lazy from ... ' instead of 'from ... lazy import'") + def test_lazy_import_valid_cases(self): """Test that lazy imports work at module level.""" # These should compile without errors diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst new file mode 100644 index 000000000000000..a3e3e38ddcd1f43 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-03-21-14-28.gh-issue-150459.qpsCEl.rst @@ -0,0 +1,3 @@ +Fix :exc:`SyntaxError` error message for ``from x lazy import y``. +Raise :exc:`SyntaxWarning` on ``from . lazy import x`` +(with whitespace between the dots and a module named ``lazy``). diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 381c173589904ba..809f3c0a7b270e8 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -2,6 +2,7 @@ #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_runtime.h" // _PyRuntime #include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal() +#include "pycore_pyerrors.h" // _PyErr_EmitSyntaxWarning() #include "pegen.h" #include "string_parser.h" // _PyPegen_decode_string() @@ -2007,11 +2008,64 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, col_offset, end_lineno, end_col_offset, arena); } +static int +_warn_relative_import_of_lazy(Parser *p, asdl_seq *dots, expr_ty module) +{ + // Warn about `from . lazy import x`: the whitespace between the dots and + // the module name is insignificant, so this is parsed exactly like + // `from .lazy import x` (an import of the relative module "lazy"), but it + // is most likely a transposition of `lazy from . import x` (PEP 810). + if (p->call_invalid_rules) { + return 0; + } + + // Only fire if there is whitespace between the last dot and the name, + // i.e. not for the common `from .lazy import x` spelling. + Token *last_dot = asdl_seq_GET_UNTYPED(dots, asdl_seq_LEN(dots) - 1); + if ( + last_dot->end_lineno == module->lineno + && last_dot->end_col_offset == module->col_offset + ) { + return 0; + } + + int count = _PyPegen_seq_count_dots(dots); + char *buf = PyMem_RawMalloc(count + 1); + if (buf == NULL) { + PyErr_NoMemory(); + return -1; + } + memset(buf, '.', count); + buf[count] = '\0'; + + PyObject *msg = PyUnicode_FromFormat( + "'from %s lazy import' is the same as 'from %slazy import'; " + "did you mean 'lazy from %s import'?", + buf, buf, buf); + PyMem_RawFree(buf); + if (msg == NULL) { + return -1; + } + + int res = _PyErr_EmitSyntaxWarning(msg, + p->tok->filename, + module->lineno, + module->col_offset + 1, + module->end_lineno, + module->end_col_offset + 1, + p->tok->module); + Py_DECREF(msg); + return res; +} + stmt_ty -_PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq * names, - int level, expr_ty lazy_token, int lineno, - int col_offset, int end_lineno, int end_col_offset, - PyArena *arena) { +_PyPegen_checked_from_import(Parser *p, asdl_seq *dots, expr_ty module_name, + asdl_alias_seq *names, expr_ty lazy_token, int lineno, + int col_offset, int end_lineno, int end_col_offset, + PyArena *arena) +{ + identifier module = module_name->v.Name.id; + int level = _PyPegen_seq_count_dots(dots); if (level == 0 && PyUnicode_CompareWithASCIIString(module, "__future__") == 0) { if (lazy_token) { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(lazy_token, @@ -2025,6 +2079,15 @@ _PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq * na } } } + else if ( + level > 0 + && lazy_token == NULL + && PyUnicode_CompareWithASCIIString(module, "lazy") == 0 + ) { + if (_warn_relative_import_of_lazy(p, dots, module_name) < 0) { + return NULL; + } + } return _PyAST_ImportFrom(module, names, level, lazy_token ? 1 : 0, lineno, col_offset, end_lineno, end_col_offset, arena); } diff --git a/Parser/parser.c b/Parser/parser.c index 58b6dd77a38b26d..8f218077a8b9033 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -22,28 +22,28 @@ static KeywordToken *reserved_keywords[] = { (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) { - {"if", 698}, - {"as", 696}, - {"in", 711}, + {"if", 700}, + {"as", 698}, + {"in", 713}, {"or", 589}, {"is", 597}, {NULL, -1}, }, (KeywordToken[]) { {"del", 634}, - {"def", 715}, - {"for", 710}, - {"try", 672}, + {"def", 717}, + {"for", 712}, + {"try", 674}, {"and", 590}, - {"not", 719}, + {"not", 721}, {NULL, -1}, }, (KeywordToken[]) { - {"from", 646}, + {"from", 650}, {"pass", 527}, - {"with", 663}, - {"elif", 703}, - {"else", 702}, + {"with", 665}, + {"elif", 705}, + {"else", 704}, {"None", 628}, {"True", 627}, {NULL, -1}, @@ -52,24 +52,24 @@ static KeywordToken *reserved_keywords[] = { {"raise", 632}, {"yield", 588}, {"break", 528}, - {"async", 714}, - {"class", 717}, - {"while", 705}, + {"async", 716}, + {"class", 719}, + {"while", 707}, {"False", 629}, {"await", 598}, {NULL, -1}, }, (KeywordToken[]) { - {"import", 647}, + {"import", 651}, {"return", 522}, {"assert", 638}, {"global", 530}, - {"except", 693}, + {"except", 695}, {"lambda", 622}, {NULL, -1}, }, (KeywordToken[]) { - {"finally", 689}, + {"finally", 691}, {NULL, -1}, }, (KeywordToken[]) { @@ -326,224 +326,225 @@ static char *soft_keywords[] = { #define invalid_import_type 1237 #define invalid_dotted_as_name_type 1238 #define invalid_import_from_as_name_type 1239 -#define invalid_import_from_targets_type 1240 -#define invalid_with_stmt_type 1241 -#define invalid_with_stmt_indent_type 1242 -#define invalid_try_stmt_type 1243 -#define invalid_except_stmt_type 1244 -#define invalid_except_star_stmt_type 1245 -#define invalid_finally_stmt_type 1246 -#define invalid_except_stmt_indent_type 1247 -#define invalid_except_star_stmt_indent_type 1248 -#define invalid_match_stmt_type 1249 -#define invalid_case_block_type 1250 -#define invalid_as_pattern_type 1251 -#define invalid_class_pattern_type 1252 -#define invalid_mapping_pattern_type 1253 -#define invalid_class_argument_pattern_type 1254 -#define invalid_if_stmt_type 1255 -#define invalid_elif_stmt_type 1256 -#define invalid_else_stmt_type 1257 -#define invalid_while_stmt_type 1258 -#define invalid_for_stmt_type 1259 -#define invalid_def_raw_type 1260 -#define invalid_class_def_raw_type 1261 -#define invalid_double_starred_kvpairs_type 1262 -#define invalid_kvpair_unpacking_type 1263 -#define invalid_kvpair_type 1264 -#define invalid_starred_expression_unpacking_type 1265 -#define invalid_starred_expression_unpacking_sequence_type 1266 -#define invalid_starred_expression_type 1267 -#define invalid_fstring_replacement_field_type 1268 -#define invalid_fstring_conversion_character_type 1269 -#define invalid_tstring_replacement_field_type 1270 -#define invalid_tstring_conversion_character_type 1271 -#define invalid_string_tstring_concat_type 1272 -#define invalid_arithmetic_type 1273 -#define invalid_factor_type 1274 -#define invalid_type_params_type 1275 -#define invalid_bitwise_and_type 1276 // Left-recursive -#define invalid_bitwise_or_type 1277 // Left-recursive -#define _loop0_1_type 1278 -#define _loop1_2_type 1279 -#define _loop0_3_type 1280 -#define _gather_4_type 1281 -#define _tmp_5_type 1282 -#define _tmp_6_type 1283 -#define _tmp_7_type 1284 -#define _tmp_8_type 1285 -#define _tmp_9_type 1286 -#define _tmp_10_type 1287 -#define _tmp_11_type 1288 -#define _loop1_12_type 1289 -#define _loop0_13_type 1290 -#define _gather_14_type 1291 -#define _tmp_15_type 1292 -#define _tmp_16_type 1293 -#define _loop0_17_type 1294 -#define _loop1_18_type 1295 -#define _loop0_19_type 1296 -#define _gather_20_type 1297 -#define _tmp_21_type 1298 -#define _loop0_22_type 1299 -#define _gather_23_type 1300 -#define _loop1_24_type 1301 -#define _tmp_25_type 1302 -#define _tmp_26_type 1303 -#define _loop0_27_type 1304 -#define _loop0_28_type 1305 -#define _loop1_29_type 1306 -#define _loop1_30_type 1307 -#define _loop0_31_type 1308 -#define _loop1_32_type 1309 -#define _loop0_33_type 1310 -#define _gather_34_type 1311 -#define _tmp_35_type 1312 -#define _loop1_36_type 1313 -#define _loop1_37_type 1314 -#define _loop1_38_type 1315 -#define _loop0_39_type 1316 -#define _gather_40_type 1317 -#define _tmp_41_type 1318 -#define _tmp_42_type 1319 -#define _tmp_43_type 1320 -#define _loop0_44_type 1321 -#define _gather_45_type 1322 -#define _loop0_46_type 1323 -#define _gather_47_type 1324 -#define _tmp_48_type 1325 -#define _loop0_49_type 1326 -#define _gather_50_type 1327 -#define _loop0_51_type 1328 -#define _gather_52_type 1329 -#define _loop0_53_type 1330 -#define _gather_54_type 1331 -#define _loop1_55_type 1332 -#define _loop1_56_type 1333 -#define _loop0_57_type 1334 -#define _gather_58_type 1335 -#define _loop0_59_type 1336 -#define _gather_60_type 1337 -#define _loop1_61_type 1338 -#define _loop1_62_type 1339 -#define _loop1_63_type 1340 -#define _tmp_64_type 1341 -#define _loop0_65_type 1342 -#define _gather_66_type 1343 -#define _tmp_67_type 1344 -#define _tmp_68_type 1345 -#define _tmp_69_type 1346 -#define _tmp_70_type 1347 -#define _tmp_71_type 1348 -#define _loop0_72_type 1349 -#define _loop0_73_type 1350 -#define _loop1_74_type 1351 -#define _loop1_75_type 1352 -#define _loop0_76_type 1353 -#define _loop1_77_type 1354 -#define _loop0_78_type 1355 -#define _loop0_79_type 1356 -#define _loop0_80_type 1357 -#define _loop0_81_type 1358 -#define _loop1_82_type 1359 -#define _loop1_83_type 1360 -#define _tmp_84_type 1361 -#define _loop0_85_type 1362 -#define _gather_86_type 1363 -#define _loop1_87_type 1364 -#define _loop0_88_type 1365 -#define _tmp_89_type 1366 -#define _loop0_90_type 1367 -#define _gather_91_type 1368 -#define _tmp_92_type 1369 -#define _loop0_93_type 1370 -#define _gather_94_type 1371 -#define _loop0_95_type 1372 -#define _gather_96_type 1373 -#define _loop0_97_type 1374 -#define _loop0_98_type 1375 -#define _gather_99_type 1376 -#define _loop1_100_type 1377 -#define _tmp_101_type 1378 -#define _loop0_102_type 1379 -#define _gather_103_type 1380 -#define _loop0_104_type 1381 -#define _gather_105_type 1382 -#define _tmp_106_type 1383 -#define _tmp_107_type 1384 -#define _loop0_108_type 1385 -#define _gather_109_type 1386 -#define _tmp_110_type 1387 -#define _tmp_111_type 1388 -#define _tmp_112_type 1389 -#define _tmp_113_type 1390 -#define _tmp_114_type 1391 -#define _loop1_115_type 1392 -#define _tmp_116_type 1393 -#define _tmp_117_type 1394 -#define _tmp_118_type 1395 -#define _tmp_119_type 1396 -#define _tmp_120_type 1397 -#define _loop0_121_type 1398 -#define _loop0_122_type 1399 -#define _tmp_123_type 1400 -#define _tmp_124_type 1401 -#define _tmp_125_type 1402 -#define _tmp_126_type 1403 -#define _tmp_127_type 1404 -#define _tmp_128_type 1405 -#define _tmp_129_type 1406 -#define _tmp_130_type 1407 -#define _loop0_131_type 1408 -#define _gather_132_type 1409 -#define _tmp_133_type 1410 -#define _tmp_134_type 1411 -#define _tmp_135_type 1412 -#define _tmp_136_type 1413 -#define _loop0_137_type 1414 -#define _gather_138_type 1415 -#define _tmp_139_type 1416 -#define _loop0_140_type 1417 -#define _gather_141_type 1418 -#define _loop0_142_type 1419 -#define _gather_143_type 1420 -#define _tmp_144_type 1421 -#define _loop0_145_type 1422 -#define _tmp_146_type 1423 -#define _tmp_147_type 1424 -#define _tmp_148_type 1425 -#define _tmp_149_type 1426 -#define _tmp_150_type 1427 -#define _tmp_151_type 1428 -#define _tmp_152_type 1429 -#define _tmp_153_type 1430 -#define _tmp_154_type 1431 -#define _tmp_155_type 1432 -#define _tmp_156_type 1433 -#define _tmp_157_type 1434 -#define _tmp_158_type 1435 -#define _tmp_159_type 1436 -#define _tmp_160_type 1437 -#define _tmp_161_type 1438 -#define _tmp_162_type 1439 -#define _tmp_163_type 1440 -#define _tmp_164_type 1441 -#define _tmp_165_type 1442 -#define _tmp_166_type 1443 -#define _tmp_167_type 1444 -#define _tmp_168_type 1445 -#define _tmp_169_type 1446 -#define _tmp_170_type 1447 -#define _tmp_171_type 1448 -#define _tmp_172_type 1449 -#define _tmp_173_type 1450 -#define _loop0_174_type 1451 -#define _tmp_175_type 1452 -#define _tmp_176_type 1453 -#define _tmp_177_type 1454 -#define _tmp_178_type 1455 -#define _tmp_179_type 1456 -#define _tmp_180_type 1457 +#define invalid_import_from_type 1240 +#define invalid_import_from_targets_type 1241 +#define invalid_with_stmt_type 1242 +#define invalid_with_stmt_indent_type 1243 +#define invalid_try_stmt_type 1244 +#define invalid_except_stmt_type 1245 +#define invalid_except_star_stmt_type 1246 +#define invalid_finally_stmt_type 1247 +#define invalid_except_stmt_indent_type 1248 +#define invalid_except_star_stmt_indent_type 1249 +#define invalid_match_stmt_type 1250 +#define invalid_case_block_type 1251 +#define invalid_as_pattern_type 1252 +#define invalid_class_pattern_type 1253 +#define invalid_mapping_pattern_type 1254 +#define invalid_class_argument_pattern_type 1255 +#define invalid_if_stmt_type 1256 +#define invalid_elif_stmt_type 1257 +#define invalid_else_stmt_type 1258 +#define invalid_while_stmt_type 1259 +#define invalid_for_stmt_type 1260 +#define invalid_def_raw_type 1261 +#define invalid_class_def_raw_type 1262 +#define invalid_double_starred_kvpairs_type 1263 +#define invalid_kvpair_unpacking_type 1264 +#define invalid_kvpair_type 1265 +#define invalid_starred_expression_unpacking_type 1266 +#define invalid_starred_expression_unpacking_sequence_type 1267 +#define invalid_starred_expression_type 1268 +#define invalid_fstring_replacement_field_type 1269 +#define invalid_fstring_conversion_character_type 1270 +#define invalid_tstring_replacement_field_type 1271 +#define invalid_tstring_conversion_character_type 1272 +#define invalid_string_tstring_concat_type 1273 +#define invalid_arithmetic_type 1274 +#define invalid_factor_type 1275 +#define invalid_type_params_type 1276 +#define invalid_bitwise_and_type 1277 // Left-recursive +#define invalid_bitwise_or_type 1278 // Left-recursive +#define _loop0_1_type 1279 +#define _loop1_2_type 1280 +#define _loop0_3_type 1281 +#define _gather_4_type 1282 +#define _tmp_5_type 1283 +#define _tmp_6_type 1284 +#define _tmp_7_type 1285 +#define _tmp_8_type 1286 +#define _tmp_9_type 1287 +#define _tmp_10_type 1288 +#define _tmp_11_type 1289 +#define _loop1_12_type 1290 +#define _loop0_13_type 1291 +#define _gather_14_type 1292 +#define _tmp_15_type 1293 +#define _tmp_16_type 1294 +#define _loop0_17_type 1295 +#define _loop1_18_type 1296 +#define _loop0_19_type 1297 +#define _gather_20_type 1298 +#define _tmp_21_type 1299 +#define _loop0_22_type 1300 +#define _gather_23_type 1301 +#define _loop1_24_type 1302 +#define _tmp_25_type 1303 +#define _tmp_26_type 1304 +#define _loop0_27_type 1305 +#define _loop0_28_type 1306 +#define _loop1_29_type 1307 +#define _loop1_30_type 1308 +#define _loop0_31_type 1309 +#define _loop1_32_type 1310 +#define _loop0_33_type 1311 +#define _gather_34_type 1312 +#define _tmp_35_type 1313 +#define _loop1_36_type 1314 +#define _loop1_37_type 1315 +#define _loop1_38_type 1316 +#define _loop0_39_type 1317 +#define _gather_40_type 1318 +#define _tmp_41_type 1319 +#define _tmp_42_type 1320 +#define _tmp_43_type 1321 +#define _loop0_44_type 1322 +#define _gather_45_type 1323 +#define _loop0_46_type 1324 +#define _gather_47_type 1325 +#define _tmp_48_type 1326 +#define _loop0_49_type 1327 +#define _gather_50_type 1328 +#define _loop0_51_type 1329 +#define _gather_52_type 1330 +#define _loop0_53_type 1331 +#define _gather_54_type 1332 +#define _loop1_55_type 1333 +#define _loop1_56_type 1334 +#define _loop0_57_type 1335 +#define _gather_58_type 1336 +#define _loop0_59_type 1337 +#define _gather_60_type 1338 +#define _loop1_61_type 1339 +#define _loop1_62_type 1340 +#define _loop1_63_type 1341 +#define _tmp_64_type 1342 +#define _loop0_65_type 1343 +#define _gather_66_type 1344 +#define _tmp_67_type 1345 +#define _tmp_68_type 1346 +#define _tmp_69_type 1347 +#define _tmp_70_type 1348 +#define _tmp_71_type 1349 +#define _loop0_72_type 1350 +#define _loop0_73_type 1351 +#define _loop1_74_type 1352 +#define _loop1_75_type 1353 +#define _loop0_76_type 1354 +#define _loop1_77_type 1355 +#define _loop0_78_type 1356 +#define _loop0_79_type 1357 +#define _loop0_80_type 1358 +#define _loop0_81_type 1359 +#define _loop1_82_type 1360 +#define _loop1_83_type 1361 +#define _tmp_84_type 1362 +#define _loop0_85_type 1363 +#define _gather_86_type 1364 +#define _loop1_87_type 1365 +#define _loop0_88_type 1366 +#define _tmp_89_type 1367 +#define _loop0_90_type 1368 +#define _gather_91_type 1369 +#define _tmp_92_type 1370 +#define _loop0_93_type 1371 +#define _gather_94_type 1372 +#define _loop0_95_type 1373 +#define _gather_96_type 1374 +#define _loop0_97_type 1375 +#define _loop0_98_type 1376 +#define _gather_99_type 1377 +#define _loop1_100_type 1378 +#define _tmp_101_type 1379 +#define _loop0_102_type 1380 +#define _gather_103_type 1381 +#define _loop0_104_type 1382 +#define _gather_105_type 1383 +#define _tmp_106_type 1384 +#define _tmp_107_type 1385 +#define _loop0_108_type 1386 +#define _gather_109_type 1387 +#define _tmp_110_type 1388 +#define _tmp_111_type 1389 +#define _tmp_112_type 1390 +#define _tmp_113_type 1391 +#define _tmp_114_type 1392 +#define _loop1_115_type 1393 +#define _tmp_116_type 1394 +#define _tmp_117_type 1395 +#define _tmp_118_type 1396 +#define _tmp_119_type 1397 +#define _tmp_120_type 1398 +#define _loop0_121_type 1399 +#define _loop0_122_type 1400 +#define _tmp_123_type 1401 +#define _tmp_124_type 1402 +#define _tmp_125_type 1403 +#define _tmp_126_type 1404 +#define _tmp_127_type 1405 +#define _tmp_128_type 1406 +#define _tmp_129_type 1407 +#define _tmp_130_type 1408 +#define _loop0_131_type 1409 +#define _gather_132_type 1410 +#define _tmp_133_type 1411 +#define _tmp_134_type 1412 +#define _tmp_135_type 1413 +#define _tmp_136_type 1414 +#define _loop0_137_type 1415 +#define _gather_138_type 1416 +#define _tmp_139_type 1417 +#define _loop0_140_type 1418 +#define _gather_141_type 1419 +#define _loop0_142_type 1420 +#define _gather_143_type 1421 +#define _tmp_144_type 1422 +#define _loop0_145_type 1423 +#define _tmp_146_type 1424 +#define _tmp_147_type 1425 +#define _tmp_148_type 1426 +#define _tmp_149_type 1427 +#define _tmp_150_type 1428 +#define _tmp_151_type 1429 +#define _tmp_152_type 1430 +#define _tmp_153_type 1431 +#define _tmp_154_type 1432 +#define _tmp_155_type 1433 +#define _tmp_156_type 1434 +#define _tmp_157_type 1435 +#define _tmp_158_type 1436 +#define _tmp_159_type 1437 +#define _tmp_160_type 1438 +#define _tmp_161_type 1439 +#define _tmp_162_type 1440 +#define _tmp_163_type 1441 +#define _tmp_164_type 1442 +#define _tmp_165_type 1443 +#define _tmp_166_type 1444 +#define _tmp_167_type 1445 +#define _tmp_168_type 1446 +#define _tmp_169_type 1447 +#define _tmp_170_type 1448 +#define _tmp_171_type 1449 +#define _tmp_172_type 1450 +#define _tmp_173_type 1451 +#define _loop0_174_type 1452 +#define _tmp_175_type 1453 +#define _tmp_176_type 1454 +#define _tmp_177_type 1455 +#define _tmp_178_type 1456 +#define _tmp_179_type 1457 +#define _tmp_180_type 1458 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -785,6 +786,7 @@ static void *invalid_group_rule(Parser *p); static void *invalid_import_rule(Parser *p); static void *invalid_dotted_as_name_rule(Parser *p); static void *invalid_import_from_as_name_rule(Parser *p); +static void *invalid_import_from_rule(Parser *p); static void *invalid_import_from_targets_rule(Parser *p); static void *invalid_with_stmt_rule(Parser *p); static void *invalid_with_stmt_indent_rule(Parser *p); @@ -1968,7 +1970,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'if' if_stmt")); stmt_ty if_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 698) // token='if' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 700) // token='if' && (if_stmt_var = if_stmt_rule(p)) // if_stmt ) @@ -2052,7 +2054,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'try' try_stmt")); stmt_ty try_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 672) // token='try' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 674) // token='try' && (try_stmt_var = try_stmt_rule(p)) // try_stmt ) @@ -2073,7 +2075,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'while' while_stmt")); stmt_ty while_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 705) // token='while' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 707) // token='while' && (while_stmt_var = while_stmt_rule(p)) // while_stmt ) @@ -2840,7 +2842,7 @@ raise_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='from' && (b = expression_rule(p)) // expression ) @@ -3619,7 +3621,7 @@ import_name_rule(Parser *p) if ( (lazy = _PyPegen_expect_soft_keyword(p, "lazy"), !p->error_indicator) // "lazy"? && - (_keyword = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword = _PyPegen_expect_token(p, 651)) // token='import' && (a = dotted_as_names_rule(p)) // dotted_as_names ) @@ -3653,6 +3655,7 @@ import_name_rule(Parser *p) } // import_from: +// | invalid_import_from // | "lazy"? 'from' (('.' | '...'))* dotted_name 'import' import_from_targets // | "lazy"? 'from' (('.' | '...'))+ 'import' import_from_targets static stmt_ty @@ -3676,6 +3679,25 @@ import_from_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro + if (p->call_invalid_rules) { // invalid_import_from + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> import_from[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_import_from")); + void *invalid_import_from_var; + if ( + (invalid_import_from_var = invalid_import_from_rule(p)) // invalid_import_from + ) + { + D(fprintf(stderr, "%*c+ import_from[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_import_from")); + _res = invalid_import_from_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s import_from[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_import_from")); + } { // "lazy"? 'from' (('.' | '...'))* dotted_name 'import' import_from_targets if (p->error_indicator) { p->level--; @@ -3691,13 +3713,13 @@ import_from_rule(Parser *p) if ( (lazy = _PyPegen_expect_soft_keyword(p, "lazy"), !p->error_indicator) // "lazy"? && - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' && (a = _loop0_17_rule(p)) // (('.' | '...'))* && (b = dotted_name_rule(p)) // dotted_name && - (_keyword_1 = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='import' && (c = import_from_targets_rule(p)) // import_from_targets ) @@ -3712,7 +3734,7 @@ import_from_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyPegen_checked_future_import ( p , b -> v . Name . id , c , _PyPegen_seq_count_dots ( a ) , lazy , EXTRA ); + _res = _PyPegen_checked_from_import ( p , a , b , c , lazy , EXTRA ); if ((_res == NULL || p->error_indicator) && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -3738,11 +3760,11 @@ import_from_rule(Parser *p) if ( (lazy = _PyPegen_expect_soft_keyword(p, "lazy"), !p->error_indicator) // "lazy"? && - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' && (a = _loop1_18_rule(p)) // (('.' | '...'))+ && - (_keyword_1 = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='import' && (b = import_from_targets_rule(p)) // import_from_targets ) @@ -4529,7 +4551,7 @@ class_def_raw_rule(Parser *p) asdl_stmt_seq* c; void *t; if ( - (_keyword = _PyPegen_expect_token(p, 717)) // token='class' + (_keyword = _PyPegen_expect_token(p, 719)) // token='class' && (a = _PyPegen_name_token(p)) // NAME && @@ -4696,7 +4718,7 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword = _PyPegen_expect_token(p, 717)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -4757,9 +4779,9 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword_1 = _PyPegen_expect_token(p, 717)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -6097,7 +6119,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6142,7 +6164,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6237,7 +6259,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 705)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6282,7 +6304,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 705)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6363,7 +6385,7 @@ else_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword = _PyPegen_expect_token(p, 704)) // token='else' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -6442,7 +6464,7 @@ while_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 705)) // token='while' + (_keyword = _PyPegen_expect_token(p, 707)) // token='while' && (a = named_expression_rule(p)) // named_expression && @@ -6542,11 +6564,11 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -6604,13 +6626,13 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 712)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -6739,7 +6761,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6790,7 +6812,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6839,9 +6861,9 @@ with_stmt_rule(Parser *p) asdl_withitem_seq* a; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6891,9 +6913,9 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 665)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6979,7 +7001,7 @@ with_item_rule(Parser *p) if ( (e = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (t = star_target_rule(p)) // star_target && @@ -7104,7 +7126,7 @@ try_stmt_rule(Parser *p) asdl_stmt_seq* b; asdl_stmt_seq* f; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7148,7 +7170,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7196,7 +7218,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7295,7 +7317,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (e = expression_rule(p)) // expression && @@ -7339,11 +7361,11 @@ except_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7385,7 +7407,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (e = expressions_rule(p)) // expressions && @@ -7426,7 +7448,7 @@ except_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7538,7 +7560,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7585,13 +7607,13 @@ except_star_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7634,7 +7656,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7734,7 +7756,7 @@ finally_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 689)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 691)) // token='finally' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -8042,7 +8064,7 @@ guard_rule(Parser *p) Token * _keyword; expr_ty guard; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (guard = named_expression_rule(p)) // named_expression ) @@ -8237,7 +8259,7 @@ as_pattern_rule(Parser *p) if ( (pattern = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (target = pattern_capture_target_rule(p)) // pattern_capture_target ) @@ -11732,11 +11754,11 @@ if_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (c = expression_rule(p)) // expression ) @@ -11803,7 +11825,7 @@ yield_expr_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 588)) // token='yield' && - (_keyword_1 = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='from' && (a = expression_rule(p)) // expression ) @@ -12685,7 +12707,7 @@ inversion_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 719)) // token='not' + (_keyword = _PyPegen_expect_token(p, 721)) // token='not' && (a = inversion_rule(p)) // inversion ) @@ -13339,9 +13361,9 @@ notin_bitwise_or_rule(Parser *p) Token * _keyword_1; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 719)) // token='not' + (_keyword = _PyPegen_expect_token(p, 721)) // token='not' && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13387,7 +13409,7 @@ in_bitwise_or_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword = _PyPegen_expect_token(p, 713)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13436,7 +13458,7 @@ isnot_bitwise_or_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 597)) // token='is' && - (_keyword_1 = _PyPegen_expect_token(p, 719)) // token='not' + (_keyword_1 = _PyPegen_expect_token(p, 721)) // token='not' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -18133,13 +18155,13 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 712)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -18178,11 +18200,11 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (_cut_var = 1) && @@ -21509,11 +21531,11 @@ expression_without_invalid_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (c = expression_rule(p)) // expression ) @@ -21813,7 +21835,7 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && @@ -21846,11 +21868,11 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && _PyPegen_lookahead_for_expr(0, expression_rule, p) ) @@ -21882,11 +21904,11 @@ invalid_expression_rule(Parser *p) if ( (a = (stmt_ty)_tmp_118_rule(p)) // pass_stmt | break_stmt | continue_stmt && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (c = simple_stmt_rule(p)) // simple_stmt ) @@ -22005,11 +22027,11 @@ invalid_if_expression_rule(Parser *p) if ( (disjunction_var = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (a = _PyPegen_expect_token(p, 16)) // token='*' ) @@ -22041,11 +22063,11 @@ invalid_if_expression_rule(Parser *p) if ( (disjunction_var = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='else' && (a = _PyPegen_expect_token(p, 35)) // token='**' ) @@ -22514,7 +22536,7 @@ invalid_raise_stmt_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 632)) // token='raise' && - (b = _PyPegen_expect_token(p, 646)) // token='from' + (b = _PyPegen_expect_token(p, 650)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' 'from'")); @@ -22544,7 +22566,7 @@ invalid_raise_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (a = _PyPegen_expect_token(p, 646)) // token='from' + (a = _PyPegen_expect_token(p, 650)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression 'from'")); @@ -24173,7 +24195,7 @@ invalid_with_item_rule(Parser *p) if ( (expression_var = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression && @@ -24223,13 +24245,13 @@ invalid_for_if_clause_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_tmp_136_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (_tmp_136_var = _tmp_136_rule(p)) // bitwise_or ((',' bitwise_or))* ','? && - _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 711) // token='in' + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 713) // token='in' ) { D(fprintf(stderr, "%*c+ invalid_for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'? 'for' (bitwise_or ((',' bitwise_or))* ','?) !'in'")); @@ -24275,9 +24297,9 @@ invalid_for_target_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings expr_ty a; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (a = star_expressions_rule(p)) // star_expressions ) @@ -24407,11 +24429,11 @@ invalid_import_rule(Parser *p) Token * a; expr_ty dotted_name_var; if ( - (a = _PyPegen_expect_token(p, 647)) // token='import' + (a = _PyPegen_expect_token(p, 651)) // token='import' && (_gather_138_var = _gather_138_rule(p)) // ','.dotted_name+ && - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' && (dotted_name_var = dotted_name_rule(p)) // dotted_name ) @@ -24438,7 +24460,7 @@ invalid_import_rule(Parser *p) Token * _keyword; Token * token; if ( - (_keyword = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword = _PyPegen_expect_token(p, 651)) // token='import' && (token = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24487,7 +24509,7 @@ invalid_dotted_as_name_rule(Parser *p) if ( (dotted_name_var = dotted_name_rule(p)) // dotted_name && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && _PyPegen_lookahead(0, _tmp_139_rule, p) && @@ -24538,7 +24560,7 @@ invalid_import_from_as_name_rule(Parser *p) if ( (name_var = _PyPegen_name_token(p)) // NAME && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && _PyPegen_lookahead(0, _tmp_139_rule, p) && @@ -24564,6 +24586,65 @@ invalid_import_from_as_name_rule(Parser *p) return _res; } +// invalid_import_from: +// | 'from' (('.' | '...'))* dotted_name "lazy" 'import' import_from_targets +static void * +invalid_import_from_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // 'from' (('.' | '...'))* dotted_name "lazy" 'import' import_from_targets + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_import_from[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' (('.' | '...'))* dotted_name \"lazy\" 'import' import_from_targets")); + Token * _keyword; + Token * _keyword_1; + asdl_seq * _loop0_17_var; + expr_ty a; + expr_ty dotted_name_var; + asdl_alias_seq* import_from_targets_var; + if ( + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' + && + (_loop0_17_var = _loop0_17_rule(p)) // (('.' | '...'))* + && + (dotted_name_var = dotted_name_rule(p)) // dotted_name + && + (a = _PyPegen_expect_soft_keyword(p, "lazy")) // soft_keyword='"lazy"' + && + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='import' + && + (import_from_targets_var = import_from_targets_rule(p)) // import_from_targets + ) + { + D(fprintf(stderr, "%*c+ invalid_import_from[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' (('.' | '...'))* dotted_name \"lazy\" 'import' import_from_targets")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "use 'lazy from ... ' instead of 'from ... lazy import'" ); + if ((_res == NULL || p->error_indicator) && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_import_from[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from' (('.' | '...'))* dotted_name \"lazy\" 'import' import_from_targets")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // invalid_import_from_targets: import_from_as_names ',' NEWLINE | NEWLINE static void * invalid_import_from_targets_rule(Parser *p) @@ -24666,9 +24747,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * trailing; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24702,9 +24783,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24740,9 +24821,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var_1); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -24802,9 +24883,9 @@ invalid_with_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 663)) // token='with' + (a = _PyPegen_expect_token(p, 665)) // token='with' && (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24845,9 +24926,9 @@ invalid_with_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 663)) // token='with' + (a = _PyPegen_expect_token(p, 665)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -24910,7 +24991,7 @@ invalid_try_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 672)) // token='try' + (a = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24942,7 +25023,7 @@ invalid_try_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24981,7 +25062,7 @@ invalid_try_stmt_rule(Parser *p) Token * b; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24989,7 +25070,7 @@ invalid_try_stmt_rule(Parser *p) && (_loop1_36_var = _loop1_36_rule(p)) // except_block+ && - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (b = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25028,7 +25109,7 @@ invalid_try_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * a; if ( - (_keyword = _PyPegen_expect_token(p, 672)) // token='try' + (_keyword = _PyPegen_expect_token(p, 674)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25036,7 +25117,7 @@ invalid_try_stmt_rule(Parser *p) && (_loop1_37_var = _loop1_37_rule(p)) // except_star_block+ && - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_opt_var = _tmp_146_rule(p), !p->error_indicator) // [expression ['as' NAME]] && @@ -25093,7 +25174,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (a = expression_rule(p)) // expression && @@ -25101,7 +25182,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -25133,7 +25214,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -25164,7 +25245,7 @@ invalid_except_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -25195,11 +25276,11 @@ invalid_except_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression && @@ -25259,7 +25340,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25269,7 +25350,7 @@ invalid_except_star_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -25302,7 +25383,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25336,7 +25417,7 @@ invalid_except_star_stmt_rule(Parser *p) void *_tmp_147_var; Token * a; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25370,13 +25451,13 @@ invalid_except_star_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression && @@ -25427,7 +25508,7 @@ invalid_finally_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 689)) // token='finally' + (a = _PyPegen_expect_token(p, 691)) // token='finally' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25483,7 +25564,7 @@ invalid_except_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -25519,7 +25600,7 @@ invalid_except_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25575,7 +25656,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 693)) // token='except' + (a = _PyPegen_expect_token(p, 695)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25852,7 +25933,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (a = _PyPegen_expect_soft_keyword(p, "_")) // soft_keyword='"_"' ) @@ -25882,7 +25963,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (a = expression_rule(p)) // expression ) @@ -26098,7 +26179,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26129,7 +26210,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty a_1; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 698)) // token='if' + (a = _PyPegen_expect_token(p, 700)) // token='if' && (a_1 = named_expression_rule(p)) // named_expression && @@ -26184,7 +26265,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 705)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26215,7 +26296,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 703)) // token='elif' + (a = _PyPegen_expect_token(p, 705)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26268,7 +26349,7 @@ invalid_else_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 702)) // token='else' + (a = _PyPegen_expect_token(p, 704)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -26301,13 +26382,13 @@ invalid_else_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword = _PyPegen_expect_token(p, 704)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (block_var = block_rule(p)) // block && - (_keyword_1 = _PyPegen_expect_token(p, 703)) // token='elif' + (_keyword_1 = _PyPegen_expect_token(p, 705)) // token='elif' ) { D(fprintf(stderr, "%*c+ invalid_else_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else' ':' block 'elif'")); @@ -26354,7 +26435,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 705)) // token='while' + (_keyword = _PyPegen_expect_token(p, 707)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26385,7 +26466,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 705)) // token='while' + (a = _PyPegen_expect_token(p, 707)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -26444,13 +26525,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 713)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -26485,13 +26566,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 710)) // token='for' + (a = _PyPegen_expect_token(p, 712)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword = _PyPegen_expect_token(p, 711)) // token='in' + (_keyword = _PyPegen_expect_token(p, 713)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -26557,9 +26638,9 @@ invalid_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 715)) // token='def' + (a = _PyPegen_expect_token(p, 717)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26616,9 +26697,9 @@ invalid_def_raw_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty name_var; if ( - (_opt_var = _PyPegen_expect_token(p, 714), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 716), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword = _PyPegen_expect_token(p, 717)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26682,7 +26763,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 717)) // token='class' + (_keyword = _PyPegen_expect_token(p, 719)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26721,7 +26802,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 717)) // token='class' + (a = _PyPegen_expect_token(p, 719)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -28357,7 +28438,7 @@ invalid_arithmetic_rule(Parser *p) && (_tmp_157_var = _tmp_157_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' && - (a = _PyPegen_expect_token(p, 719)) // token='not' + (a = _PyPegen_expect_token(p, 721)) // token='not' && (b = inversion_rule(p)) // inversion ) @@ -28406,7 +28487,7 @@ invalid_factor_rule(Parser *p) if ( (_tmp_158_var = _tmp_158_rule(p)) // '+' | '-' | '~' && - (a = _PyPegen_expect_token(p, 719)) // token='not' + (a = _PyPegen_expect_token(p, 721)) // token='not' && (b = factor_rule(p)) // factor ) @@ -28853,7 +28934,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 647)) // token='import' + (_keyword = _PyPegen_expect_token(p, 651)) // token='import' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); @@ -28872,7 +28953,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 646)) // token='from' + (_keyword = _PyPegen_expect_token(p, 650)) // token='from' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); @@ -28929,7 +29010,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 715)) // token='def' + (_keyword = _PyPegen_expect_token(p, 717)) // token='def' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); @@ -28967,7 +29048,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -29005,7 +29086,7 @@ _tmp_7_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 717)) // token='class' + (_keyword = _PyPegen_expect_token(p, 719)) // token='class' ) { D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); @@ -29062,7 +29143,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 663)) // token='with' + (_keyword = _PyPegen_expect_token(p, 665)) // token='with' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); @@ -29081,7 +29162,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -29119,7 +29200,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='for' + (_keyword = _PyPegen_expect_token(p, 712)) // token='for' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); @@ -29138,7 +29219,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 714)) // token='async' + (_keyword = _PyPegen_expect_token(p, 716)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -29839,7 +29920,7 @@ _tmp_21_rule(Parser *p) Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) @@ -35811,7 +35892,7 @@ _tmp_117_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 702)) // token='else' + (_keyword = _PyPegen_expect_token(p, 704)) // token='else' ) { D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); @@ -37474,7 +37555,7 @@ _tmp_144_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 693)) // token='except' + (_keyword = _PyPegen_expect_token(p, 695)) // token='except' ) { D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); @@ -37493,7 +37574,7 @@ _tmp_144_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 689)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 691)) // token='finally' ) { D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); @@ -38795,7 +38876,7 @@ _tmp_166_rule(Parser *p) Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='if' + (_keyword = _PyPegen_expect_token(p, 700)) // token='if' && (z = disjunction_rule(p)) // disjunction ) @@ -39531,7 +39612,7 @@ _tmp_180_rule(Parser *p) Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 696)) // token='as' + (_keyword = _PyPegen_expect_token(p, 698)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) diff --git a/Parser/pegen.h b/Parser/pegen.h index 4a4f7536db2da79..cbf44ba474fa395 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -371,8 +371,10 @@ mod_ty _PyPegen_make_module(Parser *, asdl_stmt_seq *); void *_PyPegen_arguments_parsing_error(Parser *, expr_ty); expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension); void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq *comprehensions); -stmt_ty _PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq *, - int, expr_ty, int, int, int, int, PyArena *); +stmt_ty _PyPegen_checked_from_import(Parser *p, asdl_seq *dots, expr_ty module_name, + asdl_alias_seq *names, expr_ty lazy_token, int lineno, + int col_offset, int end_lineno, int end_col_offset, + PyArena *arena); asdl_stmt_seq* _PyPegen_register_stmts(Parser *p, asdl_stmt_seq* stmts); stmt_ty _PyPegen_register_stmt(Parser *p, stmt_ty s); From f806c777017ac73a3e011bcbcddfef23c1526bb6 Mon Sep 17 00:00:00 2001 From: Harjoth Khara Date: Sat, 4 Jul 2026 08:03:08 -0700 Subject: [PATCH 07/61] gh-151945: Fix all reference warnings and various solecisms in the `http.cookiejar` docs (#152816) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Stan Ulbrych --- Doc/library/http.cookiejar.rst | 106 ++++++++++++++++++--------------- Doc/tools/.nitignore | 1 - 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 5ee783b7fae950f..ce65bc961a98a68 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -26,7 +26,7 @@ introduced with RFC 2965. .. note:: The various named parameters found in :mailheader:`Set-Cookie` and - :mailheader:`Set-Cookie2` headers (eg. ``domain`` and ``expires``) are + :mailheader:`Set-Cookie2` headers (for example, ``domain`` and ``expires``) are conventionally referred to as :dfn:`attributes`. To distinguish them from Python attributes, the documentation for this module uses the term :dfn:`cookie-attribute` instead. @@ -85,7 +85,7 @@ The following classes are provided: Constructor arguments should be passed as keyword arguments only. *blocked_domains* is a sequence of domain names that we never accept cookies - from, nor return cookies to. *allowed_domains* if not :const:`None`, this is a + from, nor return cookies to. *allowed_domains* if not ``None``, this is a sequence of the only domains for which we accept and return cookies. *secure_protocols* is a sequence of protocols for which secure cookies can be added to. By default *https* and *wss* (secure websocket) are considered @@ -93,12 +93,12 @@ The following classes are provided: :class:`CookiePolicy` and :class:`DefaultCookiePolicy` objects. :class:`DefaultCookiePolicy` implements the standard accept / reject rules for - Netscape and :rfc:`2965` cookies. By default, :rfc:`2109` cookies (ie. cookies + Netscape and :rfc:`2965` cookies. By default, :rfc:`2109` cookies (that is, cookies received in a :mailheader:`Set-Cookie` header with a version cookie-attribute of 1) are treated according to the RFC 2965 rules. However, if RFC 2965 handling is turned off or :attr:`rfc2109_as_netscape` is ``True``, RFC 2109 cookies are 'downgraded' by the :class:`CookieJar` instance to Netscape cookies, by - setting the :attr:`version` attribute of the :class:`Cookie` instance to 0. + setting the :attr:`~Cookie.version` attribute of the :class:`Cookie` instance to 0. :class:`DefaultCookiePolicy` also provides some parameters to allow some fine-tuning of policy. @@ -107,7 +107,7 @@ The following classes are provided: This class represents Netscape, :rfc:`2109` and :rfc:`2965` cookies. It is not expected that users of :mod:`!http.cookiejar` construct their own :class:`Cookie` - instances. Instead, if necessary, call :meth:`make_cookies` on a + instances. Instead, if necessary, call :meth:`~CookieJar.make_cookies` on a :class:`CookieJar` instance. @@ -141,7 +141,7 @@ The following classes are provided: .. _cookie-jar-objects: -CookieJar and FileCookieJar Objects +CookieJar and FileCookieJar objects ----------------------------------- :class:`CookieJar` objects support the :term:`iterator` protocol for iterating over @@ -154,20 +154,27 @@ contained :class:`Cookie` objects. Add correct :mailheader:`Cookie` header to *request*. - If policy allows (ie. the :attr:`rfc2965` and :attr:`hide_cookie2` attributes of + If policy allows (that is, the :attr:`~CookiePolicy.rfc2965` and + :attr:`~CookiePolicy.hide_cookie2` attributes of the :class:`CookieJar`'s :class:`CookiePolicy` instance are true and false respectively), the :mailheader:`Cookie2` header is also added when appropriate. The *request* object (usually a :class:`urllib.request.Request` instance) - must support the methods :meth:`get_full_url`, :meth:`has_header`, - :meth:`get_header`, :meth:`header_items`, :meth:`add_unredirected_header` - and the attributes :attr:`host`, :attr:`!type`, :attr:`unverifiable` - and :attr:`origin_req_host` as documented by :mod:`urllib.request`. + must support the methods :meth:`~urllib.request.Request.get_full_url`, + :meth:`~urllib.request.Request.has_header`, + :meth:`~urllib.request.Request.get_header`, + :meth:`~urllib.request.Request.header_items`, + :meth:`~urllib.request.Request.add_unredirected_header` + and the attributes :attr:`~urllib.request.Request.host`, + :attr:`~urllib.request.Request.type`, :attr:`~urllib.request.Request.unverifiable` + and :attr:`~urllib.request.Request.origin_req_host` as documented by + :mod:`urllib.request`. .. versionchanged:: 3.3 - *request* object needs :attr:`origin_req_host` attribute. Dependency on a - deprecated method :meth:`get_origin_req_host` has been removed. + *request* object needs :attr:`~urllib.request.Request.origin_req_host` + attribute. Dependency on a deprecated method + :meth:`!get_origin_req_host` has been removed. .. method:: CookieJar.extract_cookies(response, request) @@ -180,20 +187,24 @@ contained :class:`Cookie` objects. as appropriate (subject to the :meth:`CookiePolicy.set_ok` method's approval). The *response* object (usually the result of a call to - :meth:`urllib.request.urlopen`, or similar) should support an :meth:`info` - method, which returns an :class:`email.message.Message` instance. + :meth:`urllib.request.urlopen`, or similar) should support an + :meth:`~http.client.HTTPResponse.info` method, which returns an + :class:`email.message.Message` instance. The *request* object (usually a :class:`urllib.request.Request` instance) - must support the method :meth:`get_full_url` and the attributes - :attr:`host`, :attr:`unverifiable` and :attr:`origin_req_host`, + must support the method :meth:`~urllib.request.Request.get_full_url` and + the attributes :attr:`~urllib.request.Request.host`, + :attr:`~urllib.request.Request.unverifiable` + and :attr:`~urllib.request.Request.origin_req_host`, as documented by :mod:`urllib.request`. The request is used to set default values for cookie-attributes as well as for checking that the cookie is allowed to be set. .. versionchanged:: 3.3 - *request* object needs :attr:`origin_req_host` attribute. Dependency on a - deprecated method :meth:`get_origin_req_host` has been removed. + *request* object needs :attr:`~urllib.request.Request.origin_req_host` + attribute. Dependency on a deprecated method + :meth:`!get_origin_req_host` has been removed. .. method:: CookieJar.set_policy(policy) @@ -236,13 +247,13 @@ contained :class:`Cookie` objects. Discard all session cookies. - Discards all contained cookies that have a true :attr:`discard` attribute + Discards all contained cookies that have a true :attr:`~Cookie.discard` attribute (usually because they had either no ``max-age`` or ``expires`` cookie-attribute, or an explicit ``discard`` cookie-attribute). For interactive browsers, the end of a session usually corresponds to closing the browser window. - Note that the :meth:`save` method won't save session cookies anyway, unless you - ask otherwise by passing a true *ignore_discard* argument. + Note that the :meth:`~FileCookieJar.save` method won't save session cookies + anyway, unless you ask otherwise by passing a true *ignore_discard* argument. :class:`FileCookieJar` implements the following additional methods: @@ -255,8 +266,9 @@ contained :class:`Cookie` objects. method unimplemented. *filename* is the name of file in which to save cookies. If *filename* is not - specified, :attr:`self.filename` is used (whose default is the value passed to - the constructor, if any); if :attr:`self.filename` is :const:`None`, + specified, :attr:`self.filename ` is used (whose + default is the value passed to the constructor, if any); if + :attr:`self.filename ` is ``None``, :exc:`ValueError` is raised. *ignore_discard*: save even cookies set to be discarded. *ignore_expires*: save @@ -349,7 +361,7 @@ writing. .. _cookie-policy-objects: -CookiePolicy Objects +CookiePolicy objects -------------------- Objects implementing the :class:`CookiePolicy` interface have the following @@ -433,7 +445,7 @@ setting and receiving any and all cookies (this is unlikely to be useful). .. _default-cookie-policy-objects: -DefaultCookiePolicy Objects +DefaultCookiePolicy objects --------------------------- Implements the standard rules for accepting and returning cookies. @@ -463,10 +475,10 @@ blocking some benign cookies). A domain blocklist and allowlist is provided (both off by default). Only domains not in the blocklist and present in the allowlist (if the allowlist is active) participate in cookie setting and returning. Use the *blocked_domains* -constructor argument, and :meth:`blocked_domains` and -:meth:`set_blocked_domains` methods (and the corresponding argument and methods -for *allowed_domains*). If you set an allowlist, you can turn it off again by -setting it to :const:`None`. +constructor argument, and :meth:`~DefaultCookiePolicy.blocked_domains` and +:meth:`~DefaultCookiePolicy.set_blocked_domains` methods (and the corresponding +argument and methods for *allowed_domains*). If you set an allowlist, you can +turn it off again by setting it to ``None``. Domains in block or allow lists that do not start with a dot must equal the cookie domain to be matched. For example, ``"example.com"`` matches a blocklist @@ -498,12 +510,12 @@ and ``".168.1.2"``, 192.168.1.2 is blocked, but 193.168.1.2 is not. .. method:: DefaultCookiePolicy.allowed_domains() - Return :const:`None`, or the sequence of allowed domains (as a tuple). + Return ``None``, or the sequence of allowed domains (as a tuple). .. method:: DefaultCookiePolicy.set_allowed_domains(allowed_domains) - Set the sequence of allowed domains, or :const:`None`. + Set the sequence of allowed domains, or ``None``. .. method:: DefaultCookiePolicy.is_not_allowed(domain) @@ -519,9 +531,9 @@ all be assigned to. .. attribute:: DefaultCookiePolicy.rfc2109_as_netscape If true, request that the :class:`CookieJar` instance downgrade :rfc:`2109` cookies - (ie. cookies received in a :mailheader:`Set-Cookie` header with a version + (that is, cookies received in a :mailheader:`Set-Cookie` header with a version cookie-attribute of 1) to Netscape cookies by setting the version attribute of - the :class:`Cookie` instance to 0. The default value is :const:`None`, in which + the :class:`Cookie` instance to 0. The default value is ``None``, in which case RFC 2109 cookies are downgraded if and only if :rfc:`2965` handling is turned off. Therefore, RFC 2109 cookies are downgraded by default. @@ -574,7 +586,7 @@ both flags are set). .. attribute:: DefaultCookiePolicy.DomainStrictNoDots - When setting cookies, the 'host prefix' must not contain a dot (eg. + When setting cookies, the 'host prefix' must not contain a dot (for example, ``www.foo.bar.com`` can't set a cookie for ``.bar.com``, because ``www.foo`` contains a dot). @@ -582,7 +594,7 @@ both flags are set). .. attribute:: DefaultCookiePolicy.DomainStrictNonDomain Cookies that did not explicitly specify a ``domain`` cookie-attribute can only - be returned to a domain equal to the domain that set the cookie (eg. + be returned to a domain equal to the domain that set the cookie (for example, ``spam.example.com`` won't be returned cookies from ``example.com`` that had no ``domain`` cookie-attribute). @@ -597,7 +609,7 @@ combinations of the above flags: .. attribute:: DefaultCookiePolicy.DomainLiberal - Equivalent to 0 (ie. all of the above Netscape domain strictness flags switched + Equivalent to 0 (that is, all of the above Netscape domain strictness flags switched off). @@ -606,7 +618,7 @@ combinations of the above flags: Equivalent to ``DomainStrictNoDots|DomainStrictNonDomain``. -Cookie Objects +Cookie objects -------------- :class:`Cookie` instances have Python attributes roughly corresponding to the @@ -624,7 +636,7 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.version - Integer or :const:`None`. Netscape cookies have :attr:`version` 0. :rfc:`2965` and + Integer or ``None``. Netscape cookies have :attr:`version` 0. :rfc:`2965` and :rfc:`2109` cookies have a ``version`` cookie-attribute of 1. However, note that :mod:`!http.cookiejar` may 'downgrade' RFC 2109 cookies to Netscape cookies, in which case :attr:`version` is 0. @@ -637,13 +649,13 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.value - Cookie value (a string), or :const:`None`. + Cookie value (a string), or ``None``. .. attribute:: Cookie.port - String representing a port or a set of ports (eg. '80', or '80,8080'), or - :const:`None`. + String representing a port or a set of ports (for example, '80', or '80,8080'), or + ``None``. .. attribute:: Cookie.domain @@ -653,7 +665,7 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.path - Cookie path (a string, eg. ``'/acme/rocket_launchers'``). + Cookie path (a string, for example, ``'/acme/rocket_launchers'``). .. attribute:: Cookie.secure @@ -663,7 +675,7 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.expires - Integer expiry date in seconds since epoch, or :const:`None`. See also the + Integer expiry date in seconds since epoch, or ``None``. See also the :meth:`is_expired` method. @@ -675,18 +687,18 @@ internal consistency, so you should know what you're doing if you do that. .. attribute:: Cookie.comment String comment from the server explaining the function of this cookie, or - :const:`None`. + ``None``. .. attribute:: Cookie.comment_url URL linking to a comment from the server explaining the function of this cookie, - or :const:`None`. + or ``None``. .. attribute:: Cookie.rfc2109 - ``True`` if this cookie was received as an :rfc:`2109` cookie (ie. the cookie + ``True`` if this cookie was received as an :rfc:`2109` cookie (that is, the cookie arrived in a :mailheader:`Set-Cookie` header, and the value of the Version cookie-attribute in that header was 1). This attribute is provided because :mod:`!http.cookiejar` may 'downgrade' RFC 2109 cookies to Netscape cookies, in diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 2255c745c003838..7b956f0ef0eb2c4 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -9,7 +9,6 @@ Doc/library/ast.rst Doc/library/asyncio-extending.rst Doc/library/email.charset.rst Doc/library/email.parser.rst -Doc/library/http.cookiejar.rst Doc/library/http.server.rst Doc/library/importlib.rst Doc/library/logging.config.rst From 00a98ea4589bf017f1e2e338ad1cd2fc2b8105e9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 4 Jul 2026 20:40:22 +0300 Subject: [PATCH 08/61] gh-153030: Fix quadratic complexity in incremental parsing in HTMLParser (GH-153031) When an unterminated construct (e.g. a tag or comment) spanned many feed() calls, rescanning the growing buffer and concatenating new data onto it were both quadratic. New data is now accumulated in a list and only joined and parsed once enough has piled up. Co-Authored-By: Claude Opus 4.8 --- Lib/html/parser.py | 32 +++++++++++++++++-- Lib/test/test_htmlparser.py | 20 ++++++++++++ ...-07-04-17-00-00.gh-issue-153030.RovkP6.rst | 3 ++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst diff --git a/Lib/html/parser.py b/Lib/html/parser.py index 38ddf9ef442d368..fbe0d3665e073cc 100644 --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -157,6 +157,9 @@ def reset(self): self.cdata_elem = None self._support_cdata = True self._escapable = True + self._pending = [] + self._pending_len = 0 + self._parse_threshold = 1 super().reset() def feed(self, data): @@ -165,11 +168,36 @@ def feed(self, data): Call this as often as you want, with as little or as much text as you want (may include '\n'). """ - self.rawdata = self.rawdata + data - self.goahead(0) + # Accumulate new data in a list and only join and parse it once + # enough has piled up. Rescanning an unparsed buffer (e.g. an + # unterminated tag) and concatenating onto it on every call would + # both be quadratic in the input size. + self._pending_len += len(data) + if self._pending_len < self._parse_threshold: + self._pending.append(data) + else: + if not self._pending: + self.rawdata += data + else: + self._pending.append(data) + self.rawdata += ''.join(self._pending) + self._pending.clear() + self._pending_len = 0 + n = len(self.rawdata) + self.goahead(0) + if len(self.rawdata) < n: + # Some data was parsed; resume on the next call. + self._parse_threshold = 1 + else: + # Nothing was parsed; wait until the buffer doubles. + self._parse_threshold = len(self.rawdata) def close(self): """Handle any buffered data.""" + if self._pending: + self.rawdata += ''.join(self._pending) + self._pending.clear() + self._pending_len = 0 self.goahead(1) __starttag_text = None diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py index 6b7624f11505d92..3fdaed4ff46b9d0 100644 --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -1041,6 +1041,26 @@ def check(source): check("") # comment + check("") # processing instruction + check("") # doctype + check("") # CDATA section + check("") # start tag + check("") # RAWTEXT element + class AttributesTestCase(TestCaseBase): diff --git a/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst b/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst new file mode 100644 index 000000000000000..d1d60593f4ba7d2 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst @@ -0,0 +1,3 @@ +Fixed quadratic complexity in incremental parsing of long unterminated +constructs (such as tags or comments) in :class:`html.parser.HTMLParser`, +which could be exploited for a denial of service. From 6355129b3deb0456f36a26a09019ac031a27fb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurycy=20Paw=C5=82owski-Wiero=C5=84ski?= Date: Sat, 4 Jul 2026 21:03:01 +0200 Subject: [PATCH 09/61] gh-151378: Fix unbounded memory growth when recording binary and the thread is sleeping (#152089) --- .../test_binary_format.py | 23 +++++ ...-06-24-16-40-15.gh-issue-151378.iYWa_6.rst | 3 + Modules/_remote_debugging/binary_io.h | 16 +--- Modules/_remote_debugging/binary_io_writer.c | 93 +++++++------------ Modules/_remote_debugging/module.c | 6 +- 5 files changed, 68 insertions(+), 73 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index 5efc60a92111754..56dac2cf86a7647 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -932,6 +932,29 @@ def test_writer_total_samples_after_finalize_matches_reader(self): self.assertEqual(writer_collector.total_samples, len(samples)) self.assertEqual(writer_collector.total_samples, replayed) + def test_rle_buffer_flushes_before_finalize(self): + """RLE buffer flushes before the writer is destroyed during finalize().""" + with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: + filename = f.name + self.temp_files.append(filename) + + frame = make_frame("rle_boundary.py", 1, "hot") + sample = [make_interpreter(0, [make_thread(1, [frame])])] + + writer = _remote_debugging.BinaryWriter(filename, 1000, 0, compression=0) + for i in range(10_000): + writer.write_sample(sample, i * 1000) + self.assertGreater(writer.get_stats()["repeat_records"], 0) + + writer.finalize() + + reader_collector = RawCollector() + with BinaryReader(filename) as reader: + replayed = reader.replay_samples(reader_collector) + + self.assertEqual(replayed, 10_000) + self.assertEqual(writer.total_samples, 10_000) + def test_writer_total_samples_after_context_manager_matches_reader(self): """total_samples after `with BinaryWriter(...)` matches the reader's count. diff --git a/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst b/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst new file mode 100644 index 000000000000000..0b3eb860ba8d329 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-24-16-40-15.gh-issue-151378.iYWa_6.rst @@ -0,0 +1,3 @@ +Fix a bug in the binary collector in Tachyon that caused unbounded memory +growth while profiling a thread that stayed asleep. Patch by Maurycy +Pawłowski-Wieroński. diff --git a/Modules/_remote_debugging/binary_io.h b/Modules/_remote_debugging/binary_io.h index d4188335c0b6d0a..b8ea9a0e2cc41c4 100644 --- a/Modules/_remote_debugging/binary_io.h +++ b/Modules/_remote_debugging/binary_io.h @@ -109,9 +109,6 @@ static_assert(FILE_FOOTER_SIZE == 32, /* Maximum stack depth we'll buffer for delta encoding */ #define MAX_STACK_DEPTH 256 -/* Initial capacity for RLE pending buffer */ -#define INITIAL_RLE_CAPACITY 64 - /* Initial capacities for dynamic arrays - sized to reduce reallocations */ #define INITIAL_STRING_CAPACITY 4096 #define INITIAL_FRAME_CAPACITY 4096 @@ -226,12 +223,6 @@ typedef struct { uint8_t opcode; } FrameKey; -/* Pending RLE sample - buffered for run-length encoding */ -typedef struct { - uint64_t timestamp_delta; - uint8_t status; -} PendingRLESample; - /* Thread entry - tracks per-thread state for delta encoding */ typedef struct { uint64_t thread_id; @@ -244,10 +235,9 @@ typedef struct { size_t prev_stack_capacity; /* RLE pending buffer - samples waiting to be written as a repeat group */ - PendingRLESample *pending_rle; - size_t pending_rle_count; - size_t pending_rle_capacity; - int has_pending_rle; /* Flag: do we have buffered repeats? */ + uint8_t *pending_rle; + size_t pending_rle_bytes; + size_t pending_rle_samples; } ThreadEntry; /* Main binary writer structure */ diff --git a/Modules/_remote_debugging/binary_io_writer.c b/Modules/_remote_debugging/binary_io_writer.c index 341f9f7dc8ac457..5d300103ff16f8b 100644 --- a/Modules/_remote_debugging/binary_io_writer.c +++ b/Modules/_remote_debugging/binary_io_writer.c @@ -29,6 +29,10 @@ /* Frame buffer: depth varint (max 2 bytes for 256) + 256 frames * 5 bytes/varint + margin */ #define MAX_FRAME_BUFFER_SIZE ((MAX_STACK_DEPTH * MAX_VARINT_SIZE_U32) + MAX_VARINT_SIZE_U32 + 16) +/* RLE pending buffer (per thread): one entry is a u64 delta varint + status byte */ +#define MAX_RLE_BUF_SIZE (16 * 1024) +#define MAX_RLE_ENTRY_SIZE (MAX_VARINT_SIZE + sizeof(uint8_t)) + /* Helper macro: convert PyLong to int32, using default_val if conversion fails */ #define PYLONG_TO_INT32_OR_DEFAULT(obj, var, default_val) \ do { \ @@ -134,15 +138,6 @@ writer_write_varint_u32(BinaryWriter *writer, uint32_t value) return writer_write_bytes(writer, buf, len); } -/* Encode and write a varint u64 - returns 0 on success, -1 on error */ -static inline int -writer_write_varint_u64(BinaryWriter *writer, uint64_t value) -{ - uint8_t buf[MAX_VARINT_SIZE]; - size_t len = encode_varint_u64(buf, value); - return writer_write_bytes(writer, buf, len); -} - /* ============================================================================ * UTILITY FUNCTIONS @@ -511,7 +506,6 @@ writer_get_or_create_thread_entry(BinaryWriter *writer, uint64_t thread_id, entry->interpreter_id = interpreter_id; entry->prev_timestamp = writer->start_time_us; entry->prev_stack_capacity = MAX_STACK_DEPTH; - entry->pending_rle_capacity = INITIAL_RLE_CAPACITY; entry->prev_stack = PyMem_Calloc(entry->prev_stack_capacity, sizeof(uint32_t)); if (!entry->prev_stack) { @@ -519,13 +513,6 @@ writer_get_or_create_thread_entry(BinaryWriter *writer, uint64_t thread_id, return NULL; } - entry->pending_rle = PyMem_Malloc(entry->pending_rle_capacity * sizeof(PendingRLESample)); - if (!entry->pending_rle) { - PyMem_Free(entry->prev_stack); - PyErr_NoMemory(); - return NULL; - } - writer->thread_count++; if (is_new) { *is_new = 1; @@ -626,14 +613,9 @@ write_sample_header(BinaryWriter *writer, ThreadEntry *entry, uint8_t encoding) static int flush_pending_rle(BinaryWriter *writer, ThreadEntry *entry) { - if (!entry->has_pending_rle || entry->pending_rle_count == 0) { + if (entry->pending_rle_samples == 0) { return 0; } - if (entry->pending_rle_count > UINT32_MAX - writer->total_samples) { - PyErr_SetString(PyExc_OverflowError, - "too many samples for binary format"); - return -1; - } /* Write RLE record: * [thread_id: 8] [interpreter_id: 4] [STACK_REPEAT: 1] [count: varint] @@ -644,27 +626,21 @@ flush_pending_rle(BinaryWriter *writer, ThreadEntry *entry) return -1; } - if (writer_write_varint_u32(writer, (uint32_t)entry->pending_rle_count) < 0) { + if (writer_write_varint_u32(writer, (uint32_t)entry->pending_rle_samples) < 0) { return -1; } - for (size_t i = 0; i < entry->pending_rle_count; i++) { - if (writer_write_varint_u64(writer, entry->pending_rle[i].timestamp_delta) < 0) { - return -1; - } - if (writer_write_bytes(writer, &entry->pending_rle[i].status, 1) < 0) { - return -1; - } - writer->total_samples++; + if (writer_write_bytes(writer, entry->pending_rle, entry->pending_rle_bytes) < 0) { + return -1; } writer->stats.repeat_records++; - writer->stats.repeat_samples += entry->pending_rle_count; + writer->stats.repeat_samples += entry->pending_rle_samples; /* Each RLE sample saves writing the entire stack */ - writer->stats.frames_saved += entry->pending_rle_count * entry->prev_stack_depth; + writer->stats.frames_saved += entry->pending_rle_samples * entry->prev_stack_depth; - entry->pending_rle_count = 0; - entry->has_pending_rle = 0; + entry->pending_rle_bytes = 0; + entry->pending_rle_samples = 0; return 0; } @@ -678,12 +654,6 @@ write_sample_with_encoding(BinaryWriter *writer, ThreadEntry *entry, const uint32_t *frame_indices, size_t stack_depth, size_t shared_count, size_t pop_count, size_t push_count) { - if (writer->total_samples == UINT32_MAX) { - PyErr_SetString(PyExc_OverflowError, - "too many samples for binary format"); - return -1; - } - /* Header: thread_id(8) + interpreter_id(4) + encoding(1) + delta(varint) + status(1) */ uint8_t header_buf[SAMPLE_HEADER_MAX_SIZE]; memcpy(header_buf + SMP_OFF_THREAD_ID, &entry->thread_id, SMP_SIZE_THREAD_ID); @@ -752,7 +722,6 @@ write_sample_with_encoding(BinaryWriter *writer, ThreadEntry *entry, } writer->stats.total_frames_written += frames_written; - writer->total_samples++; return 0; } @@ -955,6 +924,12 @@ static int process_thread_sample(BinaryWriter *writer, PyObject *thread_info, uint32_t interpreter_id, uint64_t timestamp_us) { + if (writer->total_samples >= UINT32_MAX) { + PyErr_SetString(PyExc_OverflowError, + "too many samples for binary format"); + return -1; + } + PyObject *thread_id_obj = PyStructSequence_GET_ITEM(thread_info, 0); PyObject *status_obj = PyStructSequence_GET_ITEM(thread_info, 1); PyObject *frame_list = PyStructSequence_GET_ITEM(thread_info, 2); @@ -1002,20 +977,25 @@ process_thread_sample(BinaryWriter *writer, PyObject *thread_info, * STACK_REPEAT against an empty curr_stack (depth 0). Buffering * it here is correct; the RLE flush path emits it as a normal * STACK_REPEAT record. */ - if (GROW_ARRAY(entry->pending_rle, entry->pending_rle_count, - entry->pending_rle_capacity, PendingRLESample) < 0) { + if (entry->pending_rle == NULL) { + entry->pending_rle = PyMem_Malloc(MAX_RLE_BUF_SIZE); + if (!entry->pending_rle) { + PyErr_NoMemory(); + return -1; + } + } + if (entry->pending_rle_bytes + MAX_RLE_ENTRY_SIZE > MAX_RLE_BUF_SIZE + && flush_pending_rle(writer, entry) < 0) { return -1; } - entry->pending_rle[entry->pending_rle_count].timestamp_delta = delta; - entry->pending_rle[entry->pending_rle_count].status = status; - entry->pending_rle_count++; - entry->has_pending_rle = 1; + entry->pending_rle_bytes += encode_varint_u64( + entry->pending_rle + entry->pending_rle_bytes, delta); + entry->pending_rle[entry->pending_rle_bytes++] = status; + entry->pending_rle_samples++; } else { /* Stack changed - flush any pending RLE first */ - if (entry->has_pending_rle) { - if (flush_pending_rle(writer, entry) < 0) { - return -1; - } + if (flush_pending_rle(writer, entry) < 0) { + return -1; } if (write_sample_with_encoding(writer, entry, delta, status, encoding, @@ -1028,6 +1008,7 @@ process_thread_sample(BinaryWriter *writer, PyObject *thread_info, entry->prev_stack_depth = curr_depth; } + writer->total_samples++; return 0; } @@ -1075,10 +1056,8 @@ int binary_writer_finalize(BinaryWriter *writer) { for (size_t i = 0; i < writer->thread_count; i++) { - if (writer->thread_entries[i].has_pending_rle) { - if (flush_pending_rle(writer, &writer->thread_entries[i]) < 0) { - return -1; - } + if (flush_pending_rle(writer, &writer->thread_entries[i]) < 0) { + return -1; } } diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 7979cd43c6a1274..62d5315f361fa8a 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -1784,9 +1784,9 @@ _remote_debugging_BinaryWriter_write_sample_impl(BinaryWriterObject *self, /* Finalize the writer, cache total_samples, and destroy it. * * The cache assignment must happen AFTER binary_writer_finalize(): finalize - * flushes pending RLE samples via flush_pending_rle(), which increments - * writer->total_samples for each one. Caching before finalize would lose - * those trailing samples. */ + * flushes pending RLE records and updates the file header before the writer is + * destroyed. Caching before finalize would preserve a count for a file that + * might still fail to finish. */ static int binary_writer_finalize_and_cache(BinaryWriterObject *self) { From 8063bb10a53b39aee4a898d6406805c6c493cab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?tonghuaroot=20=28=E7=AB=A5=E8=AF=9D=29?= Date: Sun, 5 Jul 2026 06:56:09 +0800 Subject: [PATCH 10/61] gh-152718: Reject oversized table counts in the profiling binary reader (#152719) --- .../test_binary_format.py | 85 +++++++++++++++++++ ...-07-01-12-00-00.gh-issue-152718.pr0f1l.rst | 2 + Modules/_remote_debugging/binary_io.h | 4 + Modules/_remote_debugging/binary_io_reader.c | 42 +++++++-- 4 files changed, 124 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index 56dac2cf86a7647..5dff58498a4a15c 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -1003,6 +1003,9 @@ class TestBinaryFormatValidation(BinaryFormatTestBase): HDR_OFF_STR_TABLE = 36 HDR_OFF_FRAME_TABLE = 44 FILE_HEADER_PLACEHOLDER_SIZE = 64 + FILE_FOOTER_SIZE = 32 + FTR_OFF_STRINGS = 0 + FTR_OFF_FRAMES = 4 def test_replay_rejects_more_threads_than_declared(self): """Replay rejects files with more unique threads than the header declares.""" @@ -1064,6 +1067,88 @@ def test_replay_rejects_trailing_partial_sample_header(self): reader.replay_samples(RawCollector()) self.assertEqual(str(cm.exception), "Truncated sample data: 1 trailing bytes") + # Minimum on-disk size of one table entry (see binary_io.h). + MIN_STRING_ENTRY_SIZE = 1 + MIN_FRAME_ENTRY_SIZE = 7 + + def _read_offset(self, filename, hdr_off): + with open(filename, "rb") as raw: + raw.seek(hdr_off) + return struct.unpack("=Q", raw.read(8))[0] + + def _patch_footer_count(self, filename, ftr_off, value): + size = os.path.getsize(filename) + with open(filename, "r+b") as raw: + raw.seek(size - self.FILE_FOOTER_SIZE + ftr_off) + raw.write(struct.pack("=I", value)) + + def test_open_rejects_string_count_larger_than_file(self): + """Open rejects a footer string count larger than the file.""" + samples = [[make_interpreter(0, [ + make_thread(1, [make_frame("s.py", 10, "s")]) + ])]] + filename = self.create_binary_file(samples, compression="none") + size = os.path.getsize(filename) + str_off = self._read_offset(filename, self.HDR_OFF_STR_TABLE) + max_strings = (size - str_off) // self.MIN_STRING_ENTRY_SIZE + self._patch_footer_count(filename, self.FTR_OFF_STRINGS, 0xFFFFFFFF) + + with self.assertRaises(ValueError) as cm: + with BinaryReader(filename): + pass + self.assertEqual( + str(cm.exception), + f"Invalid string count 4294967295 exceeds maximum " + f"possible {max_strings}", + ) + + def test_open_rejects_frame_count_larger_than_file(self): + """Open rejects a footer frame count larger than the file.""" + samples = [[make_interpreter(0, [ + make_thread(1, [make_frame("f.py", 10, "f")]) + ])]] + filename = self.create_binary_file(samples, compression="none") + size = os.path.getsize(filename) + frame_off = self._read_offset(filename, self.HDR_OFF_FRAME_TABLE) + max_frames = (size - frame_off) // self.MIN_FRAME_ENTRY_SIZE + self._patch_footer_count(filename, self.FTR_OFF_FRAMES, 0xFFFFFFFF) + + # On a 32-bit build this count overflows the allocation size, so the + # size_t overflow guard (OverflowError) fires before the count check. + with self.assertRaises((ValueError, OverflowError)) as cm: + with BinaryReader(filename): + pass + if isinstance(cm.exception, ValueError): + self.assertEqual( + str(cm.exception), + f"Invalid frame count 4294967295 exceeds maximum " + f"possible {max_frames}", + ) + + def test_open_accepts_frame_count_at_capacity_boundary(self): + """A frame count at the file-size cap opens; one more is rejected.""" + samples = [[make_interpreter(0, [ + make_thread(1, [make_frame("f.py", 10, "f")]) + ])]] + filename = self.create_binary_file(samples, compression="none") + size = os.path.getsize(filename) + frame_off = self._read_offset(filename, self.HDR_OFF_FRAME_TABLE) + max_frames = (size - frame_off) // self.MIN_FRAME_ENTRY_SIZE + + self._patch_footer_count(filename, self.FTR_OFF_FRAMES, max_frames) + with BinaryReader(filename): + pass + + self._patch_footer_count(filename, self.FTR_OFF_FRAMES, max_frames + 1) + with self.assertRaises(ValueError) as cm: + with BinaryReader(filename): + pass + self.assertEqual( + str(cm.exception), + f"Invalid frame count {max_frames + 1} exceeds maximum " + f"possible {max_frames}", + ) + class TestBinaryEncodings(BinaryFormatTestBase): """Tests specifically targeting different stack encodings.""" diff --git a/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst new file mode 100644 index 000000000000000..63d9d7f878cb07d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-01-12-00-00.gh-issue-152718.pr0f1l.rst @@ -0,0 +1,2 @@ +Fix unbounded memory allocation in the :mod:`profiling.sampling` binary profile +reader when a file declares more string or frame entries than it contains. diff --git a/Modules/_remote_debugging/binary_io.h b/Modules/_remote_debugging/binary_io.h index b8ea9a0e2cc41c4..9696bea1cabd86b 100644 --- a/Modules/_remote_debugging/binary_io.h +++ b/Modules/_remote_debugging/binary_io.h @@ -91,6 +91,10 @@ static_assert(SAMPLE_HEADER_FIXED_SIZE == 13, static_assert(FILE_FOOTER_SIZE == 32, "FILE_FOOTER_SIZE must remain 32"); +/* Minimum on-disk bytes of a string (1) and frame (7) table entry. */ +#define MIN_STRING_ENTRY_SIZE 1 +#define MIN_FRAME_ENTRY_SIZE 7 + /* Buffer sizes: 512KB balances syscall amortization against memory use, * and aligns well with filesystem block sizes and zstd dictionary windows */ #define WRITE_BUFFER_SIZE (512 * 1024) diff --git a/Modules/_remote_debugging/binary_io_reader.c b/Modules/_remote_debugging/binary_io_reader.c index ce1c3d232c94e0f..73c4f5b6250d89b 100644 --- a/Modules/_remote_debugging/binary_io_reader.c +++ b/Modules/_remote_debugging/binary_io_reader.c @@ -237,9 +237,32 @@ reader_decompress_samples(BinaryReader *reader, const uint8_t *data) } #endif +/* Reject a table/run count whose entries cannot fit in the bytes still + * available; a malicious file could otherwise drive a huge allocation. + * Each entry occupies at least min_entry_size bytes. */ +static int +reader_validate_count(const char *what, uint32_t count, + size_t available_bytes, size_t min_entry_size) +{ + size_t max_possible = available_bytes / min_entry_size; + if (count > max_possible) { + PyErr_Format(PyExc_ValueError, + "Invalid %s count %u exceeds maximum possible %zu", + what, count, max_possible); + return -1; + } + return 0; +} + static inline int reader_parse_string_table(BinaryReader *reader, const uint8_t *data, size_t file_size) { + if (reader_validate_count("string", reader->strings_count, + file_size - reader->string_table_offset, + MIN_STRING_ENTRY_SIZE) < 0) { + return -1; + } + reader->strings = PyMem_Calloc(reader->strings_count, sizeof(PyObject *)); if (!reader->strings && reader->strings_count > 0) { PyErr_NoMemory(); @@ -280,6 +303,12 @@ reader_parse_frame_table(BinaryReader *reader, const uint8_t *data, size_t file_ } #endif + if (reader_validate_count("frame", reader->frames_count, + file_size - reader->frame_table_offset, + MIN_FRAME_ENTRY_SIZE) < 0) { + return -1; + } + size_t alloc_size = (size_t)reader->frames_count * sizeof(FrameEntry); reader->frames = PyMem_Malloc(alloc_size); if (!reader->frames && reader->frames_count > 0) { @@ -1053,15 +1082,10 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre return -1; } - /* Validate RLE count to prevent DoS from malicious files. - * Each RLE sample needs at least 2 bytes (1 byte min varint + 1 status byte). - * Also reject absurdly large counts that would exhaust memory. */ - size_t remaining_data = reader->sample_data_size - offset; - size_t max_possible_samples = remaining_data / 2; - if (count > max_possible_samples) { - PyErr_Format(PyExc_ValueError, - "Invalid RLE count %u exceeds maximum possible %zu for remaining data", - count, max_possible_samples); + /* Reject a count larger than the remaining bytes can hold; each + * RLE sample needs at least 2 bytes (1-byte min varint + status). */ + if (reader_validate_count("RLE", count, + reader->sample_data_size - offset, 2) < 0) { return -1; } if ((uint64_t)count > (uint64_t)PY_SSIZE_T_MAX - (uint64_t)replayed) { From 644ba171376b276aaf9d2fa8fa530c59bd654a2a Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 4 Jul 2026 19:39:11 -0400 Subject: [PATCH 11/61] Add "new in 3.16" to idlelib line (GH-152788) (#153049) util (line 27): root.tk_scaling method is new in 3.16. This should have been included in PR-#152788. --- Lib/idlelib/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/util.py b/Lib/idlelib/util.py index bdf02892de68ea9..e884e38bef90bf1 100644 --- a/Lib/idlelib/util.py +++ b/Lib/idlelib/util.py @@ -24,7 +24,7 @@ def fix_scaling(root): # Called in filelist _test, pyshell, and run. """Scale fonts on HiDPI displays, once per process.""" import tkinter.font - scaling = root.tk_scaling() + scaling = root.tk_scaling() # tkinter method new in 3.16 if scaling > 1.4: for name in tkinter.font.names(root): font = tkinter.font.Font(root=root, name=name, exists=True) From 45b73e0ace4e031a359cea8f8803d55aea3c9206 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 4 Jul 2026 21:56:20 -0400 Subject: [PATCH 12/61] Add "new in 3.15" comments to idlelib (#153052) Lazy keyword added to colorizer and test in PR-#142351. Tested NameError hint expanded in PR-#144299. --- Lib/idlelib/colorizer.py | 2 +- Lib/idlelib/idle_test/test_colorizer.py | 2 +- Lib/idlelib/idle_test/test_run.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index 6db38de3aa6cb9c..ac12d8ace3575f3 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -42,7 +42,7 @@ def make_pat(): ]) + r"))" ) - lazy_softkw = ( + lazy_softkw = ( # lazy new in 3.15 (+ 2 lines below). r"^[ \t]*" + # at beginning of line + possible indentation r"(?Plazy)" + r"(?=[ \t]+(?:import|from)\b)" # followed by 'import' or 'from' diff --git a/Lib/idlelib/idle_test/test_colorizer.py b/Lib/idlelib/idle_test/test_colorizer.py index 4d9e6bd887c5b87..8a6ab527f9387f4 100644 --- a/Lib/idlelib/idle_test/test_colorizer.py +++ b/Lib/idlelib/idle_test/test_colorizer.py @@ -542,7 +542,7 @@ def test_case_soft_keyword(self): self._assert_highlighting('case _:', {'KEYWORD': [('1.0', '1.4'), ('1.5', '1.6')]}) - def test_lazy_soft_keyword(self): + def test_lazy_soft_keyword(self): # lazy new in 3.15. # lazy followed by import self._assert_highlighting('lazy import foo', {'KEYWORD': [('1.0', '1.4'), diff --git a/Lib/idlelib/idle_test/test_run.py b/Lib/idlelib/idle_test/test_run.py index 57bf5559c0fa88a..f35c3168a446fef 100644 --- a/Lib/idlelib/idle_test/test_run.py +++ b/Lib/idlelib/idle_test/test_run.py @@ -44,7 +44,7 @@ def __eq__(self, other): "Or did you forget to import 'abc'?\n"), ('int.reel', AttributeError, "type object 'int' has no attribute 'reel'. " - "Did you mean '.real' instead of '.reel'?\n"), + "Did you mean '.real' instead of '.reel'?\n"), # More in 3.15. ) @force_not_colorized From 1bea11ac75681349056da9b3c1f6e16447d97bf0 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Sun, 5 Jul 2026 07:43:32 +0200 Subject: [PATCH 13/61] Remove PDF images (#145977) Co-authored-by: Maciej Olko --- Doc/c-api/lifecycle.dot.pdf | Bin 19328 -> 0 bytes Doc/c-api/lifecycle.rst | 11 ++--------- Doc/library/turtle-star.pdf | Bin 4418 -> 0 bytes Doc/library/turtle-star.ps | Bin 13803 -> 0 bytes Doc/library/turtle.rst | 2 +- 5 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 Doc/c-api/lifecycle.dot.pdf delete mode 100644 Doc/library/turtle-star.pdf delete mode 100644 Doc/library/turtle-star.ps diff --git a/Doc/c-api/lifecycle.dot.pdf b/Doc/c-api/lifecycle.dot.pdf deleted file mode 100644 index ed5b5039c83e2c4a36d77e713c430c8f14901bed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19328 zcmc({1yo$iw(pHYfZ(o;ORz>83GNo$AvEsp8r+@W5+Jxc1b2eFC3ukFmf-Lp*?XUT z?m6$=d&l>U@n}Y~)-36&S*vT+{H=dMr64NK2xQ_yq^duxxJ6`T1+V~Y4J;7(_yEkZ z#x|x-W&l>UCz}!?003YXH@9*!c6j=01$HtPH8!+0GDhU*M|5;@Fa}#Ax@GifeU2s? zKyRB@pRvDT>HCWN?gMzp9|DqRA&pQB!6_lHk1bbLY3}TY4>NgfiAQl(PAft$J8unJ z4XdFyx~2>Jm8d2KxmC2of z6Tf_QFz`KH^d(#BFqS`YCS!u555tR&rL+Q_T8!JtZP4}1U|0WC>XmBJm*M%)%IdM{ zJWWQbULPOi&)^jiL%xM|pSv33qh+qm^YpGyE*>H9fuCnp9EfVu9e#EtpKklOIe1!E zjG7Ike_8LF4Oy-~R~H!CnLoP@@M@16&vs?D^kqWFIy~qe<0QrtGl-NcYFm!Z(-@Am0d1J^DN4er?3R=&8T^e zS@NDu%ForU!X58n85~7sS`8f=u|L!sID_4Fy zxA}3c#(zoU;K(mWJ${6{uVSe*rOKN+;d9RUrk;V2I+NIkGTk+5tc1Eo?8f1xz@Ae8uWSHBQg9#4?RzS-wA){k@ z#q!SHgdUlst0Fg8DN=AE3{@Hxf%7CSs4=1D!iT!tcD?8{tw}F+rZaSgltEzpi^WLD zmv+1aeJ`Pd0VRnT&JV|GIZ_?I3&?VI85o=N(TO~ZSSA=ISP|NTEcgf;4pzbt-6ram zT6q*Qb|v2WFXY+g9k-#kWSlxO#IyTdZJ8wLM-_*YDActV-*R#FQru`L=H0rOT1F`O z7J{eNRx;v}6?;B3Q__U=w4dS;-l;fX6Y#)gQrqTEP*Y8Skd+qQQxyR^F|~MhPP*GX zh&uw$FKKP{Y5y4j{)5vq&Hps@6@dP*~o8Tgi2Pr>BC5>az46k23iu9Y@~308Q632 zD@cQD58zX+VI$Hkh2uqfa5ei0E`RyzYD5CEaCVfYEz7md%sZy?(|RN0B-cKlAtHx` z6ncPY0A={kS%jJW4mb%3L)nPZx2cA6UvX; zi3n&*4&b{!8&DUBe3Kph=ArfRWV*B^ovXtOFMFlExs7A6^s02c-*mix$M;$^+vtZ> z@VYtGNMS$T?ZNi#`ZO~?_Yww)2^qiXHa%5@j<2#Nbkb1&gA<&a_6GxI2pTDIm2C8E z2SK3dHV1H%9D;Bv-0V{fFg)#D(=Jg4>cZD+=|a0AMIs$=)@ok)x#k3%ecR;)s^n6w z6S6Xg%><*OrcmLlP{E{-2-YHKSy0JTm<;a>i>whzdx`>#wULjSEGSAsr66oY#-S+q z-AF);J4ya!BBT0QJU7*O_KCFzaMBI}&fXMbYYSmCM-|e(r6qdLolp_IGl?d8Yy#V) z#KKBe&4u*EuFgKQn}5R|3@}!(A36okggW22?_O5p9m$8gF}TIC{jiK38b$MSPJ(%l z1l&%sFk&51Tr=Ak7~Dpht*%dVGpDPZU9biW!%5xuGCPndm3V_F%_I$c!iyYz_#L^F zI@)&}@u9ApYxFtFc(nuyf$CaW*he@W zBF7qE6+^@RJ9vk{*HZq+(1WHbNPfsNtmor({Q4cp z00AuJTc|UoWqqi4?o%(Xx~u{~vMO?DKFn1Ca|eo%HCsqmacyf9 zddyCIUPFz#v$=?`$O;i6UzWAa4&C*5B6GiJLTqqir(J5Kr4DEiqRQ$SBm}mqh`jEyvDB%BG1{fI-7iY+Z799Cq^Q4wP-2S_w7{)> z5vgv|53xa&>a=9BIVg50Kr`@eOH23TjNZ*iYb>Tm>~_}I6^`xHq`pfw;vBJNb@K!C zCSOe*+U7*_aT|fg%+V2e-i}1kB%~>$DG8mS19dvXOzD+OYbH@VdqG8w-o`q~;PV9r zb*KZxlR0V#UdYqI#gB0mV_Ts?*2KN;7`#ofShtpwIEQ+T-+_%LFlPRIQwO^55??vR zGVBIxI&n)ScvD!jbZg1dTagY|I9d{g&>5KnPkFFu!bjd#=sptFS~nu%f$2SAW26Z> z$b~d+~Z9f;Kpt9D)--wsnkQjY$m# zv=m$<4tAk$IJNGOiMQqKw*4R9YEyEE{ap7~sf+cj$xzxc@*HX)?os;QMALr;5cjc) zFpgqNPKFG|nc$=!eN;NW(0I=*o`}UP(Vo%`BF&jyqkeICz!(7}6avrNo@%hXoulI4_I<+Wq#W|0A zq1`gWbwxk&egbj0ch?bnnoK16yH~BZSs>S)VTTQxamFi}dojJ-o-em*``Ead%sucq+IysTa%?fOM;f>{VidOmazQ}2_Li}j2TSD=(Oq^i-?&5 zl_?rm1jAZ=hC77|z_FMONVvoW^Gz?BKJ#znXF!wkvjo+nX3MQxQPc{$?)6+Q4Vg@B z4^vYQT1VCC7{nRYfIw)aBHwYn-f5t3e}9E?^I@1Q5;j?oTnlarxiwuZbSoyzUGuo6 zmPd!)Bi)N;crW6WnpTKb08zEIX#zV%ORvctbkvRjqFHU**p%PR;Ms~_-CE{e09A^P z59A`$&G*^**@G1=123U5*0$-9JS>wjvuOsl4{lQyYjt7?jTqR;WGWkFfa_(-t|JZM zv%5?ucmxpZRBihwh^VKl%2JfG;zx5k%bCC@M1a=@A*fI4Rk?EO4vL3rw^GH4r=|GG zt)Axy$jlrU4kh1dM@cK`>o^R`N8S5=(vy z#@N_dK+idT*@1tBZNK6)F*hd(Wv8bY4Zz3uY1|Wc{m=e}aKR8>E{we0Xb zbR6Rkas0`j(Q`S#J<;`sA4XAVhQdEQEfo|-5bQ6CW1gCd0q$ADMN1MhQ2CZ29*!>{-jdQa`VC+~TwE?Q2Pl zKovM>#0a@D#H?4>>Ua>rTfNRs)_r#;L29q-wxUng%M7^{*u8a$!;E(H=#QpN620Vo z3|)%E+}609KWjg-mP-|Zn49!woJO<@XrzM9iI)yTGlWmOs-|)`Xy|$vm#)Ah?7jy* ze1?nea5+HBmCKjsHfcDV`X=L@1M^VD7Amu5){Ri99~ws_ng}hrBzh%w#6qcAxt}Nr zfZSPMB8(@kDDFKHd6cBZ zsI~$_#eZU)(onPtshQLXVJe!ZS4(lG$$^qTE|jBeIW4WP)b)hX(NRcxxxQIiKN97j zqVg-TDb#j`iOe6{ElM$(%{)*G68@CQtkZP%?K+{w4W77PZ^N3y`(+ICO3h|dth&fR z-aX?TlYO*?FcyY*d@DE-BwSJ!O>Y=cA5G%lU^i=%g%Mg3^m$$SjjMq{WkXs;MMaj) zR&K$3o_ML$*eN^RWCcA`NdbjnZXRVJ1%S>TOSj(FS4X$&wDR!`3?^=?Yd2UfklUx9 zQ@1)~wi+tfS+UsWiOo!yG-E(-Srv3L&qw z4!JIp?ja3!AM#OOYkohET4>&gnhz>yHy55he{<-WXWN$2$j1E0w}&bDIjXXkXl6&W zm9-5>2~nhDUXlcrrcg=h&D=E9(O1bt6v)zt1&AwSX<=0rsc5{dvY7uVD}?zeG2-f{ zPF-OU-BQ}kB*9_blo_rfw!c2X2CbGUnxjVt&y|V1<*9cF&dL5AgR?G=<17t-TaG~^ zIYS2XAukWL@oE*AJ?KUm>BpG>(c*)LVOucS#uU>wI+AKzstF{_A|>>;iKbC*7*G+B z9q%QBf{}Qh5CTk>zb&<7LfFah+UW*vf0M8YX7uXzVL z+c{|a{XWhv0?SY-U99wGNYZ7cDjJ8ZFh=7j9CFhgirY!X6kzHimHNNn|OV_ zsN$ZZhDVA+3ri3miaTQg;}J4Pnwp=fxM#JhG{saA2sb`CZc-w&PJ^spWJkNf7)Cj?Sf>(tz z7A=`-&;%eS6inaJGUd$Dy4Qf?sT)iB5+k6z#^|$MSiIw%!q>~5HazwclCqE%50Cn) zNhk@quC~TPO1B2SxyXZ+ zosprX>gL~;)FjYH1gCzs8HQ+a^ok{+yg$v+k^R6mpUKB+G6B(uP-1`^UczZxQL@t7 zeA7MqYE`Gn0k$3FS&&y-yE(Gx@$ll2LSX#Oqy~W$g;~ZJYSDavM}Sl-SFh6d`I6Y7 zwYhin3MI0P3b-4#jcDc$p;L~a(*lPTN5y6@V3#8s!E$IN+fm11;BM;A4Xc%5-r|sO zSDWbE>#uSN8Iy?%+dSCT3acE5!vS`pwIb#850E1MonY#R@pI^eJ@SE(3 zJC?3}#ZY1FSuvfNeCk-3w2zcUdK>u(Sd}~xBe}JSnkBE3e~O%7zJ&|lGMqO$v=NRL z(8xO7rPUzjx~RqUF6?a`Q#Dp>{Bf%cxuhJ)M;S-8LiWyy0?|)JUkg%l0>c3%ZVDD) zEo&gjE;~Y=3U>jUY4r)?Hcb4Qdm2!SjKOYFO%Uow&_x?Adx8Mf-{2cBg>>K_z@8w_ zKS=t3bD9d>Qpxp!k$4vg!+fX22uUo#h{3&pfW_GDbyB_tXtX?Di7d4;RQZRk9=T#vMOHUJk~ zzN}M(-B=btPN}-^R{i%&MqR6dva)BjslGnxyV5gvjFS~&9O89Y^7Xu8bvW~B#v31g z-hKI=&^l76OReWC<1n-AZtEjw%U3r)a?!Tfu{xkwNzNoLFn${B=hBY{eR?4!5n?Ms z0)*0ws|ih{v%GqVX6X9n@=Z(G@ev+HezV>VEuP^>pm~3Dtf3B+Ow=oIl;YSAS6+^u z_~P4Fp@*-qhdk4R&f0f+`*=OaXOE!9%N>`Z_veo|UW9gzddg+i2em`oM42G2Si_BN zi!xGvvemUHN@MS=C)ip`nn+g(Eb8>ie$z6ebG6+=^`*&LL`=-sSga4u443+TK{xYt zGC8r*`{=CUQPZ(3-sMSdyHdz|l?F7$lrUo$Ex2Ckp~07Fa=4QNyO)z`bulnDw zNjo39NGvzyEOVb~q{yA0cz*A6^}Wk-*uNFiS~BBWmL>uYoHRUPOjpCFN~$G>sF%eBWQu;JZ>0f>okG8>Eo=EH&q6rDPaN&7nl5%eejBHmrdk{60m(H4X{1 zV{ip&%%!DPS(y^s)@{X^Fxtz3YoOhhHGi=aFU;?68G1VnRjAzenFX>VF_djkt%g_v zMc4>I6Yg`7H$EMB_MUk$$d;irSS#bLL;&@RP07~}3#Fo#m4LKiKtQB8@%jOI@dwXI z8v|OZR~qnSC^h2~zIik~y3%=TpXtpmR#G>4c*co&?|eg<`qnHcYYFbvTD-VyMuyNu z7F)$}<`75>^LE4dA7l8lVu<;@)uM+bpxM~q3PwkUJNpla$}BKA4LwbQALOQ&2Kla% z-_P$3F*{f*af%h%C?$RD->YV3xbS`~rIA=MlxdMAkNPz1>t6nP%f#JVgw&X^UnLh9 zGVwSpG5oTRPv`cflXuTccuRb<$M4mf(O6*mftg%)$^wxTX}CS?6ap4&BC}PBhUt6_ z9Q{2!Gv10Hq$##=1!^jM@Y7nd$rC5#l8(BdF9U&9T`2@7B?0+$_~nk^r6_7cQp}n( z^U|M>h|AI~c7*uiM-u&*vB!Jt{6>z&{qY+_|S#c)qOcSh| z1)tnz@CMoIQJ3%bfxrtF^|5aqBcy|>TMXVy8)@0hfGfmiHOl4qAdAlY;KDdYa{Fcn5N(Uzl31 zpO0r8IHF{$rZ1YxU)5oaeH4aABrdi~>nVO?KfmD2NBj-D4E?lDXqh(cqr z?v@`yymLYpVwi82*aJ_rvSVkIPRcv7juyg+a%^wbcdbQiHvz?X%vpyOYpp1 zYb0`Ubn8KB0kyVI59z%L%v8G?MR|X3!g8RnUaxMrXqkUv!El$>i^W|#6k^*2Yt;(km3HC zj373@wqip2ttwCiGUTogogur&Ah)Uyy((0MB*YWMkYQ_rR357h;Yu0=OUq!_>BaUz zVh5zp6w(5^BWF*!Cr9758{B3|@5#((iRd9lN%_3)LNIKz!;*(zfEsMBDP*-|Hkf8) zswu?6!4@jF#R8j82g`z=|9LbP9|nIR7DzyyUuqRkOnnVgIZs*ermorvd&(P1$UJv` zhM%?Tc$o(@0FXk6QeXH12tzC6sFhAJ|o(IBVGt~WDA@*Q9nws3JM*9oit=5 zK6-b*Y{(>$cpuLKEz0Lst@`I6#weM||S;!~9?I$1kYy2mWAZWn=pbfIL6df42YaNk1F=e*_>; zVCSzV{kn1EHUTWi{m1Tzq%9(1A6^w<2&a8Q3b~(LAOXk`;g|=~PC(msfGT**;ZK;~ z@@rS?X58+qv|xu{g7zWRtH#nphrOZ**8TI&bIUqGZ7cHEl{DC*aq%J6n)Z8bnPOjr zPve-9Ic%ytSa zO=|w75xUTZ{t-G#epb@Yt5qFjZANXBb0cXf`!mgBe%FFt2KL1TMDMz%f99N!O_n?)Y{7@l9qMuw(6JyZM=1ii&d1w{BMTj+0B0p z3ELA#`h%9SJ;Sy?N8~pxdxmnN#*T&#=5|iD4!?QWlSv+I{e;pqG?m5G#b1dUTY%M^ zmBBWSa<(?Mf8`MeTbo{bZ0iQl1~77PfB=ka zTmfe1hz6a6tXe3G6t~xvIsdE8b2XJZdTB*)8}SBpEI(u{RVd; zU^_`;b5k>?U)B7|qwHjCtp))7F8_QY`RB=VN1wzc#;kx}U{2}p5b@u;<#&b722Q`Q zqKbpF@w3Z*S%txl#=mgpe{#_?ViYk0JN)ScS@0j{K-PbFIS!ok7?dIp{Ux0Aow|NY@}AO4o| zFQ*;1xaOT|R zTTF}$X@q5M&9|zz=EK>{7`gq@4QjJxC0`x$oiTpC?Y0$HQ%~d_wdLdULz4rJ8LMrI z+6AuS5!rUz>o{9)4*iIsd)o!9po!veju?L7-X#<|_ipoj{no4fKI(O4qT_+;oQLZ0 zo2^o;OS=QAKt=#m@i%J&DqjC7`WKVthIIva*0TAMBn$!TsQl~JLu$;*O%4M#8WPf@{qmA)%JWAZzD*OO}XN?dfl z!F3!*3rD7G$U+l`1^Pa~AY!`IPdq`grQRc-d5hVjJ!? zM^+=aO#Hq<{9eKB0J3`aemTTfPu6;7t$!0h<<;P(?i7p0iZPie5^iMjF?}TXAC+GvGLf62`8(7adCac*RaGn#+9 zX^8ucfg{@2XgMPT`lyh2+QXdZ@$9ek|mRC^&z``C_m*7#mQF{9I*DR$+!jB8t~Gt5gS?q}O&>NP<7 z>Tntjrt%9_ z3-a2$gud+Ew;Az#I;am~NWn5fHB38v9$KRW@x;|V$dHh9mPe|Q)NSv8by4!~rl65>4Yd>bCj18bVXw0W6MwhenP+J?m z&GNWb*^Y}fnZ7&=vhSo%Kor@y`F2NQ1SF=my%cS4>}OjkE9WIY#Z{9|OPOUHFia-9 zZmYFSQj09j0F_?W$k?fFMMZo*<_oF-t`Ua7jeiRP+(#F&Pd$FCl3oJv8b%yMB01DS zkC~k)wH2%y-j4TDip)PqxbjI0T=_M&^Y<=8ev_Y5z6{Vfp?K~3qn5hVJcd+>%|%rv z#2%ldw^U$iDrMDKYffoS`Df2;XwK<%?+2z}NH!!wc9EWU+rlR+GIKJ zQA*^*I<={6#wx~=9WTA8vSBPRBa<`9UPrp3pLKxocq2yya^Y+o(T}^7&peQI2*V!k zU=MBH=R6){A@=m2&nTE11e=ZrRo5_&M@D%gW;lZmt*h2vW3yN$@6;zH?`cdVwgaOJTZp$`~}h`>+#JRnxSvyqXu=h zeZ?Xq)v&tCj*4sw8EN-e_awKydrk2RYuHq7@sO|Y8NaHo&X98TBG$E`aT5&sL4&=i zX&-5WC}z9_H@L2E2O?VU=?=294nTY{OnkRlZTf3GV4FxFd5}m^c0Nk%5W7OA-aZTbg_5 zx|Lp~7;Sc@XgH@qmUOuPOU`+%)h4tGl9lFOf1^peZ;#o=C4VFP;&>Y_N2~pzA+gj} z@sFUOJnNv5g!sEJwV7`Oc-6=6H_@*IWO2o+#@h zcDn3p=J^L5hhbTOG%!|8z9A7@ z0|O@sk4cAy^Vo{Bk9t)@3=b0Sgc;kUaFuD=G+PGy=1+02(A&p?JY_|0OGLOi0(+7E0yB%3YcNCx1LSvj_FU&jGqc;bHZR{^!LE<`aG%&9 zP6i>EXqzD*^nT>EA6*~xQM!Z-?|Hj{i_^U8!IPad^`kSaS(yE z@L2uH+Dn)pC(E5cR!wsG4?aK~Ao7CFl5?t~581p=9M{(}rnT(7?*sLo*OndMXxthp zVtj;l>J%D!$by|Sw@sTuI=bIPlE}@sc&=u0Mzu@gPKjOM8rEKedl~mydfLUl4*GqC zmU~d$s{o69o`XnqW5rC8{+N3`mF`yy1#e8;v;`|@%z0A!4LJRdXFWlxm_KF zqoaKHtBulk=P|T}mCe`W9x3n+=@BIRF=>L|M)+exg~=Ke-8=;SKl8}CnM^o*im%A` z3>@xe6lo=!W$8arlC^r9o#B|^!jqY_e!J~=$>WvHaq&<{8jjbvE94PM(m%zoz+~ti zabvY6vEL)vySjWF62m@$LTVOr&(%)sm1yRTxDj)=7d8@!=qnORI!VrKLB2r?p@|_` zlrgQJgd}8sC!Jzn5^!*#j1ltGyT^ihs=Fi{ik1?3# zI-UJ>Xjd{9+JkR3PM2w#+A#(WQwl#HAB)6P5(ScgVbMR}dG@t4FNNXuhm&7isIRKq zCfI*Wa2oWU6Irrbc5;9ohWYAE|DBr4{1vxwWr9gfCPP9@il`EHOLR@sAi2x3`ceEf zzmfY`Uxi_!1r5_oEupKxl)xLzT_@TAX)S*O#5(9RdlzW?^;Hq$+(mUF{`(tev_R@! z(uw2?g!3SnNm*VriT>TLd)`4%Vj~9C=m7oTS6_6`BW?>XRcRMzWgm`J0DN8~T3iJ(y>-7pYHh(5r``frsWKw z(4K!hZsvHW8_IUnG5RiO@1P^rOdxytYr8LpW!1fl^l{1ubDu^#XUnBR)1l`Q54d#XhTUq{aAZF=g4@{`(h@_LzbRISjo>h&hg2nu^ft#WsCBg% z(XegeOC(5CFVpGuar8)~)V#dq`Yby+cbN}*{}totNBO|z7eLwwE?2BM+VW*qw^Tg# z9qoW;7A7+z@}HN^e<#aI}4Cm!OY>5y~WJ!R0{*j ze($}(C-X^>y=e=$)}o&iFVib)szkgkiP?J0ztRZ9x|1SbJT{aPIXHV8YydHKi$3|P zZo&4EB4n7S$q5*(>(EWr;s!)nLH6fjN?9b7Z_*Dw&p+{CbAlIChj7YD&?tl*lUl3q zd_^?oaD^Q*O(bs*`kp!>zXCsQbVU_{IeNkxlI*|kCIR4O5|RMi1;9pgulLb{4E%7j zTx)Pae8+)1Oa64F{CWNSD5W z7s17ouKEqSYq9>kyS=F{+m}UH-Z}UxVyy)*Zlj^?E#5*yeT4O9m9q@pmnB$j?Ow)o zIV%}DtLlh!#fnktg*wGyPO&a(+f{eZ>?TDdLNt#6%q+>EIfW}t!ZOr%IE4xIb{gt= z;C*s^YeyDsOTTS>jp>gjmQE8NgJ-R)q>)~!R&CfrYul5Oyyf?QZS!u6;sd&XMWnwm z5y|F+0%Vy z^UFRVm1y^tNMn}L2hq1^nENB@sMwQc$ZM2^h!G8OCo;;K7!%=8_ducK6K&&mwwk02 zgQKCPpP8%+?#Kp9&x>g)w_d0|F$=Y?$YK_>BlU0Ig+S|5Y=RMT0<+WLL|08Vgb zp@TVt!5)r)7!W0PYyxkGFQh095|kTjlCfwZH2?;`#l|sJBcps*BbG_-v`_?=qA-|0 zjO0SeJYIji7O{{9$v6v2*JR}fiVV2}xuyH!f5d(zr@rRZR3eO&PFyI0k`$%FppvYM zK+V}jkI{0 z$dg(o2=G1bK!UE^dbDM7@nXOblQ;o5kRW)Vt1485(+W;>tpdFmZHx?As0S2iA;>Hx zdkiO4Xc!L@uRHS{05c!th&tl z+A+Ty()~;4IH$RPL*bsuz#kNjorRtAFAVp0(b}IB;U5~c|85JEZv3!K4**T<(hGLj z34O7jjxyf3Sei@kBInaR1hR-laX$ht(xW#%wRAqy0XOm`N>3ihbv%<)U9WXu@uJFs z%YzV{S~&?py2k3E_QFP@c18T!mYP^2Zsfk9jKz6nw9MS?G>-a-jCx%f?Ld;??XtOV7z|7W0HW{W4STeDl*`!r`0KX4p0Im{%5` zM{trpyc9iT?o6w(a^KV$?)>8GxFMO;m1;|@Nui*XL{}wF%vuLC)`*Vk>4aF_{~+_uWA#v4^?t`}z9B#zE-QcLZ_- znN8HTQF?Sz6pA9AicPpeuMrM};>2^r6~>`F`HP;AYXJ$$LIAlfqT5)H{~MV4-}vZ%3sip%(fr$&k6!Q3qYS=T$~(#R``d38^i>9&hQMQ|F98bOZyOsNCGbT4Dh>HWj#`TmJ$OQyFPe`2X>`W}|tlXSW zT?BGJwS}GaskhH`m4k_!gNx+}oBz$u%?@IE&hb?AZw3F3U;oh#763aJh>3-ji;bNf zzyV}q0)p6{8^z87WCC$;us?m`-|FDtWM|@L|J4^300$=<6E`P2=(*rO>>R9|e-`{# zX8YWiztes8f1|@?|DWq{S=qS%nc0r2SSzT^AEaN_#-lOhkGUHLW$39F1HL1~$-fpzA)1?ctR#y0B*7 zt(Uf~=lD(+vkg*?Prv5<;j+Zi!^x7iZLLq(B`+~=BYtz^+zf&rO2aVk!n$OwNzLnS z7kP>Chn|Lm@8gRm$l$}3HbcVf4#V4dFY2FGykB2w&zfa;cTcytnjZU6Bz08Z=cCn$ z73Gd1f9Cu&a|NKadk2K@>)Cg?VPJU zyRNc8>uH4v%G<}A2-F$@PXYVn4hG^)-Evp{G`7pE_yZkIfyWE6&B<{2NCBnQmIiP8 zS%7O@nD+=5IlswuU_D2!@&WolAHqJW*xM0bWv#sKEKjV_dr{FuzA@#z+{6>Ck}K}b zEAF4M=U)~`(7za-(#iH4;U(;m<>bcI_iOZphUyn5rerKum&Ek3+KWVrJEvihjcGIU z8yABwW({<{D(hh-zi%N2!1eNf2FFz_>@qoi$NKW!M)rY{bAU&}JJTuI)fz=?%no+Ko(adBZTh^gG)so@ zrxJav+h6)+)lb#(?oK6u{-P!+;#_@uO|wa&eHgfCgrFt(4pu8E+;Z}FFC(j>y`c>< z&*)sy)0#}kUZ|o6k(g@ym?H$=7n_Vrq}PNaK8{|1Hu=Dlcnzedq6LM7>03HWSOxB2 zw{r0JQJ<4+f7Eb9LW1u+ag`NhjE%Z=YEvz01FEFV;sGH&2f-jp?n`rIC5MV3pc z`eLWf?UqN}DtBm}jh~m^RK7a2EWdOQ-{sBi#kk_C7?8#7ez>jNdwgKK)dC|lUd`uA zw*!|z-WS!nc=w#9H^ry9g2;Un8Nx9>BCKRLREYSB0XO%ka$alwnP0e_20Dp#SH`-S z51X9Xl5OytQX|4}?#SPr!bDQ7^*cw|T-oW0^oC?Vb#;S=dWGvWE39<=y^}NI`unTu zFjwfSxG-0uCe}1bb@oW=4Qo;#v$b+$ouBKYT*w~Ny@YUjsNB2G%;G3t%z7h8+1EH| z+TTXX(6H{thpC5TURdx1XEuSpeTdLQwqJ>b7WvfL8HCHOgD?~eO{VKJ9&yh6e##xQ z68Y12Y-YIeMe~WMuF%~5)3dLdgqgLQI-=+vZG4tJi!aT@EmrV>!MU~ zDugB94(u9Z-WO^W`6Ay7x$k{Umakt+WO~C|nV^>eI?Bbw2cf5CO%!g~<3`)>8^Y<) z_eIp6ETctJ1I+NS*iVHU6Z9l|&LQDnAB%MQ?cBuga&z6ppI9MC=zy$xaso(r*nAQAT=vn3l5rys3YtElgV$zNYp#+@0Mzg2?)=DL?L%W6J%h1*7;&*wKdrY0+dR z-e%(+EEngz2Tm9<<>2Nl-G)N?X%dQn?`RULDzqxQ(qPIs6$DnL ze~^`(fvGa;rlM@A^W^IlbqOrgn~EEdURh++bw{P`!IaqNYQ+@p!R($+V!Z_UO$hkW?Nj_DvidIDY1{S@P*yliou_{G-#PEO`+LaHvXoyJc^j3n9 zsEQwQ1e332U#|+TbSn*&_6t)tRADuHeM{3&cv1QKeJkVOXZeB*Y9mKY7uFhQ?$vOH zH}uB!oeAH`-_Y}6vL>V(e~QIV#OE~HWqnO}9?!xB?>HrGE{{2d$5D<|Ol{&gy-01s z9hYmKI0ZX;NG%soAk#?rIU|`54)<;4a9{$e>C5;OUnK;TXl~gB{LU=I7A8zN%Br{z z%t!uFj#iMpgjM~`gC%5Rut?W~7!dZv*8qH396upd!bEBWOleVI^h;XU$3~gE$`^O@ zeUEdG5H{u%zk-Z^-qQ2yX7|Se7Rbr{*9H~#f1}TMy3hWn4J!Yn&xjqj=y}#>_#hI0 z5wV|kM2I|!?|GQ8LS0*MFflXA1BJBS8*w?Y_%Tv?3!H1-EOq?EV%>cc?b3}CC8U1@(C{8>Cih81UVBCzDO zjMIcim^@jt?|CLc+dWWcR!%V{KHTFNx5Depe5hh%qtGUofDQ+0-BFXSKzQ~XNjc7L z@L$7#U!M8Hi>$1FiCozKy>{RqkM;jr-v5?VsAwpNi2i>H1K9tn@lQp?|NAK5*Ba}e z7F~aTQ2vkT=%1qi5h>BS0 zXZvrd%Kxt?`UC@Njs=1|g{hF=^9@i4 zX*415Kk5tX?}IQAv2guf1eEvH6VZ~LkU(l%ruJ831)CGS%1?#Ke-920a9GI7?D}>C z#s{;?*=~kIc7BuNf7^8o@asY5XP**lX0kv#SgiHyJI|%v-#(kYDX{t2=zc0uIy1{t zT4;_<$Q$pYS$J-qip#;s6e%NoGNx(QPqUlL8unr+_qauPf)-hhAji8-b7ap&DESF~o9wqN<{{8p5~Uq&UZ7xS52kK$JFy6mka1Pv z`);6U5(4+}XJ3r;#|!EY+B%9&W?8hQtuvl5*lAabY3$v3SBjK*_)uFnX7A3(D^W)! zj?e7*(U-12bmGNPo6z zKF}WtUQL|4@y%F(a3v^M)VR_RT7i5xDR124n9h#j;SDd1k{hJZNHXnN5&42U zH-Hf0uJ!ZF_8y8M9AG)h%fVyFKn`jRDQyyDdaaU(d=+ZYX_e^DCl)v*=~niQ_y7lqeB$D7kiArh9RuE(lmxd zsgUa3?ajH5cMSievj@?Vm=fu*+3I`!8>Xay_ENG7UBsaFm>@&L&^}|s??B`mpU#ah zKLjG*N+Uh=k+0N_ZI1G$`rF`Mt*!}J+C`mmzG|tnm=2-r6cM`Iqp>w}{X(RgHet3| z{4$>@{1e2UK_OB)lR?8NYx&SMPXu;`k-6S`0EXWx5Y$|{zqR+>XsW1D^;7F`t*Vk* zV`1UpWKlRB)vU3W1gP1Ip4*0uYGA_zgeqWvPO(#HxVl>eE8sMc`w&@YzpIuvSd%<|{rgyl&t_=i-Hi7Jq zp=50GYp(kPnF2X}W2%40OP{B4WpfW>00-NzB2N?d(;i{~>+k7M$=3F1^Y8P-_j^uz zzKsCbe-qfhFL9{Gxlx3`ctPvOTyN(2*o8x>@Gvrqn?0+LkUlg(z3+u86B5gtms)ri z{-Jq{a5SNjm)isfhRiZW2zzP`08MrRK-LTuM9GZ}!NUTeh)D{*h#%uk;~sutJFcZW zyAswVBKww{H>4%Sy13D7WsO1$Nh4xR)2Sm@9qS%ir`L{7{MAC}>5B@3vpZ4-5kz_g p$M!7V4%?s5Zqr0H|LRLeC$NK)o5PcrfFN#e5F! -.. only:: epub or not (html or latex) +.. only:: not builder_html .. image:: lifecycle.dot.svg :align: center :class: invert-in-dark-mode :alt: Diagram showing events in an object's life. Explained in detail below. -.. only:: latex - - .. image:: lifecycle.dot.pdf - :align: center - :class: invert-in-dark-mode - :alt: Diagram showing events in an object's life. Explained in detail below. - .. container:: :name: life-events-graph-description diff --git a/Doc/library/turtle-star.pdf b/Doc/library/turtle-star.pdf deleted file mode 100644 index e354073dd42f5e6ea48118d7e2363247b190528b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4418 zcmai22{=@5`yN6WyTp(_erH2p(WR zwkzf@qqf5ZpH3<+r{nIN=$P=3VvA^06u<5uAXZA8 z6cd(K)dN8Gs!mZ?1KUcB(q+^(c^zR>SiI)zt#^)tG}Ok*4t_~ zI2^3ftm<`iDsmc(jm$}i@aBW{?V?2RO{Uja3VWp15JRUQyFZf_RoesAG(rJVKrf0@g zH;9nV%d~3;4+>V=`3<>BHjkLsI=`o;c*a6BTYcc+EftWC#Lrs1|2)cocs>o<9pQsq zxz*$D>!d#C1&x>-alf?!jX*UDG#FOW(~3~5x>#J{EQa~fEp8=);}pEPbz@?K^;?)51B@BAo&33 z9{`T*No9`v04%yOxn)2ix)3zUetlU zfs+6fM|LMu%)AH=B!Ic5xt?>S+G&t(TGHYcA3)#u#dHhnAj9k|DjXc*L2jT%mhK4*YVOUH^C& zN$f60i&G}*{1(gI^7hZ1<%JbfIPz-n`?VQdyrQr^D5Rzxv|s9Aax`UUJ`>yLV2#Qzz;E`Q+xy-eQg0=W^+Z@q&rbvmD>(iRA3U zEZJt!>~CBoe{|Mm9#DkLD_OdyT4R^ISzUX)d*V3zq3qnidIh_ZaJ!Iq+@SqBrCR%R z^^;*SkLB>&ot#9GAz4}V$-4V$RQvI_?Nh}tcvgA#ER9opAn<2nTIcCLi>_?peGEKK!pmWXzNO6h5c;K)&e0P2B4|m zH9&89*qofZH+fe9NLQI>U*Z=#c#u5RgLo6 z+P?{RN<@9r1`d_E<|i+HG%Wm*$O-PGA zHk{oxI>VNWlJsqr+yd3D!wMV#F+6kv5Z%H<*hSD~Pl!4ne?=E=dZAOsKzDOTjEzpj zCGNLMT#?rZDG;8EigF;NbZz~Wkh>(B zFD*`~#?pSWM5%|TC#}ciqnji@+?yNE)=xq`$%&3j2>iJLR$>@{}l(Cc?iuW65j*JRfu${4h3 z!|`zI67$b@M@jX2j{3>sWbI@#O|NyZ<;@-4r4oKa$Kh33DXmnkkF!sHhYluZa|d!l zc7A4}VqT9VO9~i+jIobNjF~m!c*6><&bZZT=z7rMKzshc*h$Ih^ifsDyZ(Pd zPWM=2tujrk}B z-sZSnWI13dU9_X{e&J-{Os{+|M{nVS_ji{Dx;m5GtQ`VsV_nCc9yJyZOrNW`dSECh zZq;LRD(+@2SEOO2K&)Y`JwuM+y(ciAn19kRY@eE9x(O;% zDKE*zqQzH>BTr^Ep;BLFSz~J zt+|8H0QQvIvs2lQ0OsyaFT`^N=Oe~eFj?&0GPOmM^DgJHxw}O8`M?9B{=u2m>LX7d z!URPj50yS1E;Csi{Up81OK3z0B^0;ILnc}0v`%|YLJq%9MeIVXa&#qT$gh$b4Rw%{2}$0`H0AE&m5xiFz<0K-SZOMnS)MNLu(l|3r9N2ufOFGzLv(*D z?eh0n>a&`(@1}{kiWVzN9-pbIEYU62wNWXnrqvF{q{N(!sYv^Xp6Z`3NwK2m)s^So zdmE_mXuc7H9x@L^K2fFlkgq!QW-65_)hIoB=nZC4rsS6lns($R*>mApPs*JvW?U!BW$YTb7LNwcJ$9<}Lv z9N&`L5-|RzWoRO5;zNZXeWc?^RrL6iit<()$`k7By_aKKt&Ums6|32LOnFbZEWH@X zPqJkUc4_2SF1WRHt1XW&WJ!I3V0{P1m+QBOVu}aTeebVzeY1YFdF$p#&pFS7k1x~4 z>j$1bL4LIyVhloqvOi_dUTdiB%Q6V^l%hzgp*|w}=j1=MR|ri%zi&qgK6CKIV#;zE z1s_m2a$)N7PDFO{gZRlH;kY-^_wXKK4X%c)$L||RUngS;`VpuYNL)HFr0Y3lM^=LQ( zz^EeD1v`!D4&VS(--YPI6!I(^!OZu&QvTan;0RQLJK5=n#qjy*Eq)1c_(m7<1_TGd z$P75f>{A)7tOA(O2o$P6z%&c%zQd2Iu+cbt!|uv!sUcu+7#t2$g=66ul*$PhY!CDG zEAqETWEv16&4KBK*Gn?(3yx`lsV-zsEtYU!&&l#MWa97Ne>LhyAvuC!0CS3A|9=2z z6bgv~9D$!05{qS89@YVPZeTDJmT49K#E@td(}4Vm!C(mHmH&YKT?2_#`7IxnLU3^>QP%&MFmv%| z&NB*tnv%&(8Zoo6Or)NtBbmvmAJG=2RKm$ gsS0z@0RQihAFTADGAXpaa7a}&94sq)#7Grgvqhw+`BY9?aH~Rn*O%fvzpaD=4?ec%m zIk&q3kYgoIDwUcCd&Uyb=)QgX-g7?zpZ&wTo6cpN&rN60?WtGqZeH^uI6J#4OjPB? zg}S{{S5bB!mFnjtUYQEdUUU31HIGpin?k)XX}-p{6TexgK#wK zjfVZ9ri0r!{>zJem&Hl8dXYa~s7^TPtInve zCex9c4o8@9@Vr0kDgGVxD#_jzd77^ReYGnJJb0BYaL^hZv z^lSa+K!2~V^}pzU)j#Ne({J?KK)=)fu7A`w`c}W!Kk1(X{fqvK{;QrB(c;bk*Erc6 zm%^|g^`~4U$s#ELHVx=PI*Yu3NLEDz?jt?d3mt2mNCQP{o#V2$ue0WiG~+gt4Q z9?+Q=`JKt;z+`C_R=;s#3R5P;*miH_lo#<5;1H~=c1fC=O>Wf)YfctXn&p)TV*xwo zUMAL?Xi*R`u>p#V02f4nULdpF32F?)%-J0d@V(zk1eZk~Ze1DqxX2N5A& zF9U;{s9fxDK%;989rGEHToA-qvX0WF-O~-0HMA+KKwny@U0O~qEf$w>()!XO<+2vg zWkGpfzS38Yr$E25t6$mGuUe~L)yuB!oNGJhx;5w8&jF!ot>4%U-`e?a?fkc``ET6> zzYKy)t7Mz*1O3(-*L%D6ykb6-1HQ4Rbp`xAXHB&D>4! z%XFOFCow!nZUwQkD|dF~uC;PkFWK9Nl?Y<*hl9VX*eru!)KhV?sMMT+EI3oQ>!eip zKT>4{iA6=Mwi4ddGA|Ga%c@)y$+l7}lbHfeG*PQ8mZMjQDP7U$r-5@}$ zC=D%JK?Bf)Mj+ZI8{{T_U@fuC-%&)#a_?`s@&}Wxs7PF4 z%VlXQf4e`ttu|Y7qp}@zAuxf1aun83*QY??&!^xd-fdO2-x>w(Nnftbhv4LsDmn49 z`lMDV;<>#GPLicbOC!ra%TK5X3J*T3IdVd`SG^g4g!9?mdeGZ~hvl!Y*0Pkg$h=Zswj@t z!A;HWlgB*+Ou^0d&0FEe$SrUtmRLhvE!I(nyj2ipe1-`-iR|)ak#FP~)D^*Bf1rmnx+DC7gGq%V0`Lpl^z zW)?^)qhhZhSokP)3OcY%kqaF_MR%H+2S*kHGGV1PHQ@aJSIKJi?IPmw zN&usUQ4qoorq~t+KTE_H*kn=UxP*%*;Do9XUg+3k)CE8%9bw6hmck0ey^gk9gU|xL zpnzRLmX>xp;u^e61${*;gaAUV5r=nc%|4&8XAWX9ecdyWRLiKg;0mmg(-LfKl4`Lw zi#wG=fJ;QR5;!s0bM;SHOLw{jtE&UH|D-JYh?wvlfPp0$LpEu`cn1rO;;xYR+uz~) zU~)WmOBBSo=%0Ey(sYc37s=&K^3kYQsE*zxkMO?GU|yo^;jlvhH+G>ETreO*j1qDw z=$dy(`Ohe~Y?RBP?F|BCDP*YiNX0M^1VQEwJTAya6(p2#kSOtZ0_j36a^$y3hS2C- z5rZo#KsaBEeaENlfaMWrQ-6SWgoMQECtDMfBg>8D1l|zG^?O4` zT~Qc)T2E~vn8l-)jJu1`ZOBTf)EPEmWS@LVjyiCuO(qvoA@kQ*`$TtIa>dK=|7m&OaXp=WCjQpoN+ zQmE3(df>3ero>33u4McOqc*a-R0ozvk>6PKyrxlfI)YJ)yU2Q?D24k$uwep&9cj|m zFKxM+r5fB&lb^cSlfd(eJ8rNpX1C-vf=*aan*zbmV41kGXa=ZG;We<=Da3*%5$qK6 zK$d#8DI82s(q!ilK_2Tp1iV#{@lz4NsT|_eis4kPU}cC9@O%k6O(hd$Y>M)0-J&AK zhK=cY0bLtMqB-D;z+>Q@;c{83mdNK1%nvjg4Yv)@TT3G#;1EvM1_P8D+jX)iaSYh3 zb)916q9<<mq@)aKi`PYLrh%xK<2YgAKV$5 z9Wt*Z2@-9UNK&{(NhrcM$e9UTIXF&ybjH$=Xn-u{PsP)P(P&A+>!>!R{l{ zHTcdU9y$Q-Asmr5wde&JC-9K$dm?3&jK^%8CVA#LgdvO$RbNtMxfubH%-iS_tRJM) z2;r*cbQ)@LpC~_v&Ti=PYgs)0ip72o7Z3c-PGC0`x^&dQ1uIq9_@VdNhiczfkD+?( zy9I1vOGspd+s)H`2Pp?DUkW$Pk!(T-2?8BsnKL=@G)$8m4FVDtS^9A0aprviF?g<4 z(AkPU4IRtf#^o@Mf+JiYu|NumuBd34=3d9!j-%EgwHTgo0q2e8tBPzsi`o}H1js0* z`nDkUq7o;KJg4u(>*YUi_jqIh_jU49`@k+(m1vmQOK;J#mBct!#`c-t&i}3oya90W z(0c^&t!RneIm!e)8>uIf;Rh$k`9)avmfX5Zp#A$O0ChU*GG=jog?4cv@y2C2h$%93 zAEjWW9dxL72%cr4GjCQ*47ibyViF=w$u0#tA_e!k7uTV%c#~&2x*Mbmv=?aQSwJ~z zS3iJ&Z+_6zwmGz(_UZ?qnnqJsE!-eD!8l6f4;<(DyCa#@Ls2B*SgLP`3rXV%!l$g^ zJQ-;h;b-bmA;LZLC{Q}>V@MwNnL=U&-v9e;6gt-YOagIm=Ie8O+ailgL zFk!+#gW97k3wuW;~wb(4CX3IyD8u71DTmZD^59S`NXSmrdv75-D#1>GNQ2^jv}oaUvGS zBE=t@C#1L7Am2SXfnPux4DW6Wch_I>1@&V%uvRzPof@SCAMV|Aeptn`TcamZR zT%&;twNXB(daP1iK|yH}DpL12(*T5#N`VQ0`x@O%0ReLj9*XLn&%sii7@QWq~It?2% zI?9e~co=%A+WM`Fl8z>;K%4#}i=(H}UQdUk9zchq9@~eb-YAYnov*4#UEF+~6ikcI zod&bWU{*-#8z&@+fIXmVBQAp}0n;d&mrqD}eb8&=IlTGP0o!YvOfUvXU$nJq1wXA@ z_nt-Ds-o|;ei@A-=1fftqk`Qre5FZ&*R5k`=2REQQ5UmkEzZ&=HSP#KR+{Kb;GoZL zf7!1-y!-2O01~ZO_7#hIQ(lOxU{cm}s6D^Jirg@+$^|kurCkE$r!m^fRDT|Kgj-g% zjQBvAul>;)wEA&rJdXi4hL;hpPUXN3J(!|HgLagV#N+Kl+oPfx*UrDY>PNFNd_xVv zz=b<^N60!7J_({RBTu6x5*4;ml91qJ*W@WwdrONRoGfbFh;WTc$!2Q@&P3FSiIuyD zJBOPM9BXfoZK8S+mDZ}Jj;-l9Zw9-?X^ktg*4lYuZ^|v9@IW~`&QD&RWMn{BAGD#}pL0xK;^BPRxFu zcwv*Sz`bj*FS~x@>7`<2R}!qELSt@7vlE{ywXn_H&~V@5C@G{;cSK?a1p0BQBB6DX z;heJFGwFH)?+K7<#}-?MlrE{QsjM#IIxH9_65#7LoUNY^T}Tg8FqH1+J4=kgXvo-Lj0votGylp{{Vu>?8PRESpokv)1S2|MnE4RUxlO&;4Xc*F==!;VX#R#TAz z#d}ZN7H@^^_UgJ!IV8}I8nyAZ)>((`2AX#m$ljkmyS!|Zw+3ztiby z*Nv5E(YzS>!n?4;`EB8dVEn7HuM!BpnQ%251?m5M;bq&gL~3a?;gYKxx$w?YhXq1P ztyh-KA~exmCVl9g4u~C8LTC8q>z)0?%YE>5W2)U2-+QqJV|VI|Q|utF`F$BaFT)3B zQuz*gW8}+&8Gkm1>UC$c*$4@#{IWfzq3R5Wv(}`}a5_-a+0@7G;RK(!;g+5fj)S*7 zewx@=}k=r8Z_w23RBEaW8wAQ;e);Y zK#iW92!hkzWEu|p;dnSzgDGCXkEgvUxarM?Lr-zo?+*LeYBrn>2SYU)j1Cy_`yNdj zj6to%h^ICgc6;HhKj=;Ivp4Rm(Wuv*guP)np5YQ3c!IrYcQTw##}EZJ@2kORa5(VP zL`d$76OXnYg5tP4nNIMLxF7C3A^|X zax$8QqaKy+2~Lh=J?fL5eAj$q>gJjmJ-_?O@tyHddoUAT%8IVH2>W@hrs8+0)3Hh21_3axj4A zhrklh|7ENmO`JWA{==O1mCwfYVL z0VzJ|<9-9NC!8jb3n&9*qw#3khoM>IHimiNi_!CdbGAQwa*ZOqSj}z8-f9sBCg)47 z;G3TZ(w{)lk+c2g=fC;+Z+^a&&A8b5&Cmb8_<8h-@Gl6E-Qjc5puYJPZv&e`-@Xol{{&?w BwL<^^ diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 20c659756fe1c19..d7839e2f81172c5 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -46,7 +46,7 @@ direction it is facing, drawing a line as it moves. Give it the command Turtle can draw intricate shapes using programs that repeat simple moves. - .. image:: turtle-star.* + .. image:: turtle-star.png :align: center In Python, turtle graphics provides a representation of a physical "turtle" From 338520c9572adb691d838aceca37a12edfd8bea4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 09:12:58 +0300 Subject: [PATCH 14/61] gh-40038: Quote imaplib command arguments when necessary (GH-152703) Argument quoting was inadvertently disabled when imaplib was ported to Python 3 (bpo-1210 commented out the ``_checkquote()`` call, bpo-9638 then removed it), so since Python 3.0 commands failed for arguments containing protocol-sensitive characters, such as a space in a mailbox name. Quoting is restored and reimplemented per the RFC 3501 grammar, so that arguments that need quoting are escaped and quoted, while flags, sequence sets and list wildcards are left intact. For backward compatibility, an argument already enclosed in double quotes is left unchanged, so code that quotes arguments itself keeps working. Co-Authored-By: Claude Opus 4.8 (1M context) --- Doc/library/imaplib.rst | 7 +- Lib/imaplib.py | 170 ++++++++--- Lib/test/test_imaplib.py | 273 +++++++++++++++++- ...6-06-30-12-00-00.gh-issue-40038.qK7mGv.rst | 6 + 4 files changed, 404 insertions(+), 52 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index db17f6b79a7c50d..dbf4560ab5e53b3 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -186,6 +186,9 @@ enclosed with either parentheses or double quotes) each string is quoted. However, the *password* argument to the ``LOGIN`` command is always quoted. If you want to avoid having an argument string quoted (eg: the *flags* argument to ``STORE``) then enclose the string in parentheses (eg: ``r'(\Deleted)'``). +In general, pass arguments unquoted and let the module quote them as needed. +An argument that is already enclosed in double quotes is left unchanged, +so that code which quotes arguments itself keeps working. Most commands return a tuple: ``(type, [data, ...])`` where *type* is usually ``'OK'`` or ``'NO'``, and *data* is either the text from the command response, @@ -410,7 +413,7 @@ An :class:`IMAP4` instance has the following methods: .. versionadded:: 3.14 -.. method:: IMAP4.list([directory[, pattern]]) +.. method:: IMAP4.list(directory='', pattern='*') List mailbox names in *directory* matching *pattern*. *directory* defaults to the top-level mail folder, and *pattern* defaults to match anything. Returned @@ -440,7 +443,7 @@ An :class:`IMAP4` instance has the following methods: The method no longer ignores silently arbitrary exceptions. -.. method:: IMAP4.lsub(directory='""', pattern='*') +.. method:: IMAP4.lsub(directory='', pattern='*') List subscribed mailbox names in directory matching pattern. *directory* defaults to the top level directory and *pattern* defaults to match any mailbox. diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 70abfa741444c30..a871e509b0d82c6 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -130,6 +130,9 @@ _Literal = br'.*{(?P\d+)}$' _Untagged_status = br'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?' _control_chars = re.compile(b'[\x00-\x1F\x7F]') +_non_astring_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff%*\\"]') +_non_list_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff\\"]') +_quoted = re.compile(br'"(?:[^"\\]|\\.)*+"') class IMAP4: @@ -503,8 +506,7 @@ def append(self, mailbox, flags, date_time, message, *, if not mailbox: mailbox = 'INBOX' if flags: - if (flags[0],flags[-1]) != ('(',')'): - flags = '(%s)' % flags + flags = self._set_quote(flags) else: flags = None if date_time: @@ -514,7 +516,7 @@ def append(self, mailbox, flags, date_time, message, *, if translate_line_endings: message = MapCRLF.sub(CRLF, message) self.literal = message - return self._simple_command(name, mailbox, flags, date_time) + return self._simple_command(name, self._astring(mailbox), flags, date_time) def authenticate(self, mechanism, authobject): @@ -539,7 +541,7 @@ def authenticate(self, mechanism, authobject): #if not cap in self.capabilities: # Let the server decide! # raise self.error("Server doesn't allow %s authentication." % mech) self.literal = _Authenticator(authobject).process - typ, dat = self._simple_command('AUTHENTICATE', mech) + typ, dat = self._simple_command('AUTHENTICATE', self._atom(mech)) if typ != 'OK': raise self.error(dat[-1].decode('utf-8', 'replace')) self.state = 'AUTH' @@ -584,7 +586,8 @@ def copy(self, message_set, new_mailbox): (typ, [data]) = .copy(message_set, new_mailbox) """ - return self._simple_command('COPY', message_set, new_mailbox) + return self._simple_command('COPY', self._sequence_set(message_set), + self._astring(new_mailbox)) def create(self, mailbox): @@ -592,7 +595,7 @@ def create(self, mailbox): (typ, [data]) = .create(mailbox) """ - return self._simple_command('CREATE', mailbox) + return self._simple_command('CREATE', self._astring(mailbox)) def delete(self, mailbox): @@ -600,14 +603,15 @@ def delete(self, mailbox): (typ, [data]) = .delete(mailbox) """ - return self._simple_command('DELETE', mailbox) + return self._simple_command('DELETE', self._astring(mailbox)) def deleteacl(self, mailbox, who): """Delete the ACLs (remove any rights) set for who on mailbox. (typ, [data]) = .deleteacl(mailbox, who) """ - return self._simple_command('DELETEACL', mailbox, who) + return self._simple_command('DELETEACL', self._astring(mailbox), + self._astring(who)) def enable(self, capability): """Send an RFC5161 enable string to the server. @@ -646,7 +650,8 @@ def fetch(self, message_set, message_parts): 'data' are tuples of message part envelope and data. """ name = 'FETCH' - typ, dat = self._simple_command(name, message_set, message_parts) + typ, dat = self._simple_command(name, self._sequence_set(message_set), + self._fetch_parts(message_parts)) return self._untagged_response(typ, dat, name) @@ -655,7 +660,7 @@ def getacl(self, mailbox): (typ, [data]) = .getacl(mailbox) """ - typ, dat = self._simple_command('GETACL', mailbox) + typ, dat = self._simple_command('GETACL', self._astring(mailbox)) return self._untagged_response(typ, dat, 'ACL') @@ -663,7 +668,8 @@ def getannotation(self, mailbox, entry, attribute): """(typ, [data]) = .getannotation(mailbox, entry, attribute) Retrieve ANNOTATIONs.""" - typ, dat = self._simple_command('GETANNOTATION', mailbox, entry, attribute) + typ, dat = self._simple_command('GETANNOTATION', self._astring(mailbox), + entry, attribute) return self._untagged_response(typ, dat, 'ANNOTATION') @@ -674,7 +680,7 @@ def getquota(self, root): (typ, [data]) = .getquota(root) """ - typ, dat = self._simple_command('GETQUOTA', root) + typ, dat = self._simple_command('GETQUOTA', self._astring(root)) return self._untagged_response(typ, dat, 'QUOTA') @@ -683,7 +689,7 @@ def getquotaroot(self, mailbox): (typ, [[QUOTAROOT responses...], [QUOTA responses]]) = .getquotaroot(mailbox) """ - typ, dat = self._simple_command('GETQUOTAROOT', mailbox) + typ, dat = self._simple_command('GETQUOTAROOT', self._astring(mailbox)) typ, quota = self._untagged_response(typ, dat, 'QUOTA') typ, quotaroot = self._untagged_response(typ, dat, 'QUOTAROOT') return typ, [quotaroot, quota] @@ -702,15 +708,16 @@ def idle(self, duration=None): return Idler(self, duration) - def list(self, directory='""', pattern='*'): + def list(self, directory='', pattern='*'): """List mailbox names in directory matching pattern. - (typ, [data]) = .list(directory='""', pattern='*') + (typ, [data]) = .list(directory='', pattern='*') 'data' is list of LIST responses. """ name = 'LIST' - typ, dat = self._simple_command(name, directory, pattern) + typ, dat = self._simple_command(name, self._astring(directory), + self._list_mailbox(pattern)) return self._untagged_response(typ, dat, name) @@ -721,7 +728,8 @@ def login(self, user, password): NB: 'password' will be quoted. """ - typ, dat = self._simple_command('LOGIN', user, self._quote(password)) + typ, dat = self._simple_command('LOGIN', self._astring(user), + self._quote(password)) if typ != 'OK': raise self.error(dat[-1].decode('UTF-8', 'replace')) self.state = 'AUTH' @@ -767,15 +775,16 @@ def logout(self): return typ, dat - def lsub(self, directory='""', pattern='*'): + def lsub(self, directory='', pattern='*'): """List 'subscribed' mailbox names in directory matching pattern. - (typ, [data, ...]) = .lsub(directory='""', pattern='*') + (typ, [data, ...]) = .lsub(directory='', pattern='*') 'data' are tuples of message part envelope and data. """ name = 'LSUB' - typ, dat = self._simple_command(name, directory, pattern) + typ, dat = self._simple_command(name, self._astring(directory), + self._list_mailbox(pattern)) return self._untagged_response(typ, dat, name) def myrights(self, mailbox): @@ -783,7 +792,7 @@ def myrights(self, mailbox): (typ, [data]) = .myrights(mailbox) """ - typ,dat = self._simple_command('MYRIGHTS', mailbox) + typ,dat = self._simple_command('MYRIGHTS', self._astring(mailbox)) return self._untagged_response(typ, dat, 'MYRIGHTS') def namespace(self): @@ -829,7 +838,7 @@ def proxyauth(self, user): """ name = 'PROXYAUTH' - return self._simple_command(name, user) + return self._simple_command(name, self._astring(user)) def rename(self, oldmailbox, newmailbox): @@ -837,7 +846,8 @@ def rename(self, oldmailbox, newmailbox): (typ, [data]) = .rename(oldmailbox, newmailbox) """ - return self._simple_command('RENAME', oldmailbox, newmailbox) + return self._simple_command('RENAME', self._astring(oldmailbox), + self._astring(newmailbox)) def search(self, charset, *criteria): @@ -849,10 +859,11 @@ def search(self, charset, *criteria): If UTF8 is enabled, charset MUST be None. """ name = 'SEARCH' - if charset: + if charset is not None: if self.utf8_enabled: raise IMAP4.error("Non-None charset not valid in UTF8 mode") - typ, dat = self._simple_command(name, 'CHARSET', charset, *criteria) + typ, dat = self._simple_command(name, + 'CHARSET', self._astring(charset), *criteria) else: typ, dat = self._simple_command(name, *criteria) return self._untagged_response(typ, dat, name) @@ -876,7 +887,7 @@ def select(self, mailbox='INBOX', readonly=False): name = 'EXAMINE' else: name = 'SELECT' - typ, dat = self._simple_command(name, mailbox) + typ, dat = self._simple_command(name, self._astring(mailbox)) if typ != 'OK': self.state = 'AUTH' # Might have been 'SELECTED' return typ, dat @@ -895,14 +906,15 @@ def setacl(self, mailbox, who, what): (typ, [data]) = .setacl(mailbox, who, what) """ - return self._simple_command('SETACL', mailbox, who, what) + return self._simple_command('SETACL', self._astring(mailbox), + self._astring(who), self._astring(what)) - def setannotation(self, *args): + def setannotation(self, mailbox, *args): """(typ, [data]) = .setannotation(mailbox[, entry, attribute]+) Set ANNOTATIONs.""" - typ, dat = self._simple_command('SETANNOTATION', *args) + typ, dat = self._simple_command('SETANNOTATION', self._astring(mailbox), *args) return self._untagged_response(typ, dat, 'ANNOTATION') @@ -911,7 +923,8 @@ def setquota(self, root, limits): (typ, [data]) = .setquota(root, limits) """ - typ, dat = self._simple_command('SETQUOTA', root, limits) + typ, dat = self._simple_command('SETQUOTA', self._astring(root), + self._set_quote(limits)) return self._untagged_response(typ, dat, 'QUOTA') @@ -923,8 +936,9 @@ def sort(self, sort_criteria, charset, *search_criteria): name = 'SORT' #if not name in self.capabilities: # Let the server decide! # raise self.error('unimplemented extension command: %s' % name) - if (sort_criteria[0],sort_criteria[-1]) != ('(',')'): - sort_criteria = '(%s)' % sort_criteria + sort_criteria = self._set_quote(sort_criteria) + if charset is not None: + charset = self._astring(charset) typ, dat = self._simple_command(name, sort_criteria, charset, *search_criteria) return self._untagged_response(typ, dat, name) @@ -961,7 +975,8 @@ def status(self, mailbox, names): name = 'STATUS' #if self.PROTOCOL_VERSION == 'IMAP4': # Let the server decide! # raise self.error('%s unimplemented in IMAP4 (obtain IMAP4rev1 server, or re-code)' % name) - typ, dat = self._simple_command(name, mailbox, names) + typ, dat = self._simple_command(name, self._astring(mailbox), + self._set_quote(names)) return self._untagged_response(typ, dat, name) @@ -970,9 +985,9 @@ def store(self, message_set, command, flags): (typ, [data]) = .store(message_set, command, flags) """ - if (flags[0],flags[-1]) != ('(',')'): - flags = '(%s)' % flags # Avoid quoting the flags - typ, dat = self._simple_command('STORE', message_set, command, flags) + flags = self._set_quote(flags) + typ, dat = self._simple_command('STORE', self._sequence_set(message_set), + command, flags) return self._untagged_response(typ, dat, 'FETCH') @@ -981,7 +996,7 @@ def subscribe(self, mailbox): (typ, [data]) = .subscribe(mailbox) """ - return self._simple_command('SUBSCRIBE', mailbox) + return self._simple_command('SUBSCRIBE', self._astring(mailbox)) def thread(self, threading_algorithm, charset, *search_criteria): @@ -990,7 +1005,10 @@ def thread(self, threading_algorithm, charset, *search_criteria): (type, [data]) = .thread(threading_algorithm, charset, search_criteria, ...) """ name = 'THREAD' - typ, dat = self._simple_command(name, threading_algorithm, charset, *search_criteria) + if charset is not None: + charset = self._astring(charset) + typ, dat = self._simple_command(name, self._atom(threading_algorithm), + charset, *search_criteria) return self._untagged_response(typ, dat, name) @@ -1011,7 +1029,31 @@ def uid(self, command, *args): (command, self.state, ', '.join(Commands[command]))) name = 'UID' - typ, dat = self._simple_command(name, command, *args) + if command == 'COPY': + message_set, new_mailbox = args + args = (self._sequence_set(message_set), + self._astring(new_mailbox)) + elif command == 'FETCH': + message_set, message_parts = args + args = (self._sequence_set(message_set), + self._fetch_parts(message_parts)) + elif command == 'STORE': + message_set, op, flags = args + args = (self._sequence_set(message_set), op, + self._set_quote(flags)) + elif command == 'SORT': + sort_criteria, charset, *search_criteria = args + if charset is not None: + charset = self._astring(charset) + args = (self._set_quote(sort_criteria), charset, + *search_criteria) + elif command == 'THREAD': + threading_algorithm, charset, *search_criteria = args + if charset is not None: + charset = self._astring(charset) + args = (self._atom(threading_algorithm), charset, + *search_criteria) + typ, dat = self._simple_command(name, self._atom(command), *args) if command in ('SEARCH', 'SORT', 'THREAD'): name = command else: @@ -1024,7 +1066,7 @@ def unsubscribe(self, mailbox): (typ, [data]) = .unsubscribe(mailbox) """ - return self._simple_command('UNSUBSCRIBE', mailbox) + return self._simple_command('UNSUBSCRIBE', self._astring(mailbox)) def unselect(self): @@ -1393,13 +1435,53 @@ def _new_tag(self): return tag - def _quote(self, arg): + def _atom(self, arg): + return arg + + def _sequence_set(self, arg): + return arg - arg = arg.replace('\\', '\\\\') - arg = arg.replace('"', '\\"') + def _set_quote(self, arg): + if arg and arg[0] == '(' and arg[-1] == ')': + return arg + return '(' + arg + ')' - return '"' + arg + '"' + def _fetch_parts(self, arg): + # "ALL", "FULL" and "FAST" are macros, not data item names; + # they cannot be enclosed in parentheses. + if arg.upper() in ('ALL', 'FULL', 'FAST'): + return arg + return self._set_quote(arg) + def _quote(self, arg): + if isinstance(arg, str): + arg = bytes(arg, self._encoding) + arg = arg.replace(b'\\', br'\\') + arg = arg.replace(b'"', br'\"') + return b'"' + arg + b'"' + + # For backward compatibility, an argument already enclosed in double + # quotes is left unquoted, so that code which quotes arguments itself + # keeps working. New code should pass arguments unquoted and let the + # module quote them as needed. + + def _astring(self, arg): + if isinstance(arg, str): + arg = bytes(arg, self._encoding) + if _quoted.fullmatch(arg): + return arg + if arg and _non_astring_char.search(arg) is None: + return arg + return self._quote(arg) + + def _list_mailbox(self, arg): + if isinstance(arg, str): + arg = bytes(arg, self._encoding) + if _quoted.fullmatch(arg): + return arg + if arg and _non_list_char.search(arg) is None: + return arg + return self._quote(arg) def _simple_command(self, name, *args): diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 097056c91a7f89e..5d9ca170ea59fda 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -176,6 +176,65 @@ def test_imap4_host_default_value(self): imaplib.IMAP4() self.assertIn(cm.exception.errno, expected_errnos) + def test_astring(self): + m = imaplib.IMAP4.__new__(imaplib.IMAP4) + m._encoding = 'ascii' + # Plain atoms are left unquoted. + self.assertEqual(m._astring('INBOX'), b'INBOX') + self.assertEqual(m._astring(b'INBOX'), b'INBOX') + # Names with protocol-sensitive characters are quoted. + self.assertEqual(m._astring('New folder'), b'"New folder"') + self.assertEqual(m._astring('a"b'), b'"a\\"b"') + self.assertEqual(m._astring('a\\b'), b'"a\\\\b"') + self.assertEqual(m._astring(''), b'""') + self.assertEqual(m._astring('*'), b'"*"') + # A well-formed quoted string is passed through unchanged. + self.assertEqual(m._astring('"New folder"'), b'"New folder"') + self.assertEqual(m._astring('""'), b'""') + # Including a lenient (non-RFC) backslash escape, which the server + # may accept. + self.assertEqual(m._astring('"a\\b"'), b'"a\\b"') + # A string that only looks quoted but is not a single token is + # quoted as data, closing the argument injection vector. + self.assertEqual(m._astring('"a" SELECT evil "'), + b'"\\"a\\" SELECT evil \\""') + self.assertEqual(m._astring('"'), b'"\\""') + # Non-ASCII names are only allowed in a quoted string or a + # literal, never in an atom (RFC 6855). + m._encoding = 'utf-8' + self.assertEqual(m._astring('Entwürfe'), '"Entwürfe"'.encode()) + self.assertEqual(m._astring(b'Entw\xc3\xbcrfe'), b'"Entw\xc3\xbcrfe"') + + def test_astring_idempotent(self): + # Quoting an already quoted argument should not change it, so that + # quoting twice gives the same result as quoting once. + m = imaplib.IMAP4.__new__(imaplib.IMAP4) + m._encoding = 'ascii' + for arg in ['INBOX', 'New folder', 'a"b', 'a\\b', '', '*', '%', + '"New folder"', '""', '"a\\b"', '"a" SELECT evil "', + '"', 'a\tb', 'a\rb', '\x7f', '(a)', b'Entw\xc3\xbcrfe']: + with self.subTest(arg=arg): + once = m._astring(arg) + self.assertEqual(m._astring(once), once) + twice = m._list_mailbox(arg) + self.assertEqual(m._list_mailbox(twice), twice) + + def test_list_mailbox(self): + m = imaplib.IMAP4.__new__(imaplib.IMAP4) + m._encoding = 'ascii' + # Wildcards are not quoted in a list pattern. + self.assertEqual(m._list_mailbox('*'), b'*') + self.assertEqual(m._list_mailbox('%'), b'%') + self.assertEqual(m._list_mailbox('foo/%'), b'foo/%') + # But spaces still require quoting. + self.assertEqual(m._list_mailbox('New folder'), b'"New folder"') + self.assertEqual(m._list_mailbox('"New folder"'), b'"New folder"') + # As do non-ASCII names; wildcards keep their meaning inside a + # quoted string. + m._encoding = 'utf-8' + self.assertEqual(m._list_mailbox('Entwürfe/%'), + '"Entwürfe/%"'.encode()) + if ssl: class SecureTCPServer(socketserver.TCPServer): @@ -279,7 +338,7 @@ def cmd_LOGOUT(self, tag, args): self._send_tagged(tag, 'OK', 'LOGOUT completed') def cmd_LOGIN(self, tag, args): - self.server.logged = args[0] + self.server.logged = args self._send_tagged(tag, 'OK', 'LOGIN completed') def cmd_SELECT(self, tag, args): @@ -510,6 +569,7 @@ def cmd_APPEND(self, tag, args): code, _ = client.enable('UTF8=ACCEPT') self.assertEqual(code, 'OK') self.assertEqual(client._encoding, 'utf-8') + self.assertEqual(server.args, ['UTF8=ACCEPT']) msg_string = 'Subject: üñí©öðé' typ, data = client.append( None, None, None, (msg_string + '\n').encode('utf-8')) @@ -537,6 +597,26 @@ def cmd_AUTHENTICATE(self, tag, args): with self.assertRaisesRegex(imaplib.IMAP4.error, 'charset.*UTF8'): client.search('foo', 'bar') + def test_utf8_mailbox_name(self): + class UTF8Server(SimpleIMAPHandler): + capabilities = 'AUTH ENABLE UTF8=ACCEPT' + def cmd_ENABLE(self, tag, args): + self._send_tagged(tag, 'OK', 'ENABLE successful') + def cmd_AUTHENTICATE(self, tag, args): + self._send_textline('+') + self.server.response = yield + self._send_tagged(tag, 'OK', 'FAKEAUTH successful') + client, server = self._setup(UTF8Server) + typ, _ = client.authenticate('MYAUTH', lambda x: b'fake') + self.assertEqual(typ, 'OK') + typ, _ = client.enable('UTF8=ACCEPT') + self.assertEqual(typ, 'OK') + # A non-ASCII mailbox name is only allowed in a quoted string + # or a literal, never in an atom (RFC 6855). + typ, _ = client.select('Entwürfe') + self.assertEqual(typ, 'OK') + self.assertEqual(server.is_selected, ['"Entwürfe"']) + def test_bad_auth_name(self): class MyServer(SimpleIMAPHandler): def cmd_AUTHENTICATE(self, tag, args): @@ -669,7 +749,7 @@ def test_with_statement(self): _, server = self._setup(SimpleIMAPHandler, connect=False) with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) self.assertIsNone(server.logged) def test_with_statement_logout(self): @@ -677,7 +757,7 @@ def test_with_statement_logout(self): _, server = self._setup(SimpleIMAPHandler, connect=False) with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) imap.logout() self.assertIsNone(server.logged) self.assertIsNone(server.logged) @@ -752,11 +832,33 @@ def test_idle_delayed_packet(self): self.fail('multi-packet response was corrupted by idle timeout') def test_login(self): - client, _ = self._setup(SimpleIMAPHandler) + client, server = self._setup(SimpleIMAPHandler) typ, data = client.login('user', 'pass') self.assertEqual(typ, 'OK') self.assertEqual(data[0], b'LOGIN completed') self.assertEqual(client.state, 'AUTH') + # The user name is quoted only when necessary, but the password + # is always quoted. + self.assertEqual(server.logged, ['user', '"pass"']) + self.assertRaises(imaplib.IMAP4.error, client.login, 'user', 'pass') + + def test_login_quoted(self): + client, server = self._setup(SimpleIMAPHandler) + typ, data = client.login('us*r', 'p%ss') + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'LOGIN completed') + self.assertEqual(client.state, 'AUTH') + self.assertEqual(server.logged, ['"us*r"', '"p%ss"']) + + def test_login_quoted2(self): + # An already quoted user name is passed through unchanged, rather + # than being quoted a second time; the password is always quoted. + client, server = self._setup(SimpleIMAPHandler) + typ, data = client.login('"user"', '"pass"') + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'LOGIN completed') + self.assertEqual(client.state, 'AUTH') + self.assertEqual(server.logged, ['"user"', r'"\"pass\""']) def test_append_translate_line_endings(self): # By default line endings are normalized to CRLF; False sends the @@ -785,6 +887,11 @@ def cmd_APPEND(self, tag, args): translate_line_endings=False) self.assertEqual(server.response, message) + # The mailbox is quoted and the flags are wrapped in parentheses + # when necessary. + client.append('New folder', r'\Seen', None, b'data') + self.assertEqual(server.args, ['"New folder"', r'(\Seen)', '{4}']) + def test_login_capabilities(self): # A server may advertise new capabilities after login (as an # untagged CAPABILITY response); imaplib must refresh its cached @@ -873,6 +980,12 @@ def test_lsub(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['~/Mail/', '%']) + # The directory is quoted when necessary; wildcards in the pattern + # are preserved. + typ, data = client.lsub('New folder', '%') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '%']) + def test_extra_blank_line_after_literal(self): # Some buggy servers send an extra blank line after the counted # literal data. imaplib should skip it instead of failing. @@ -940,6 +1053,10 @@ def test_select(self): self.assertEqual(server.is_selected, ['INBOX']) self.assertTrue(client.is_readonly) + typ, data = client.select('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.is_selected, ['"New folder"']) + def test_expunge(self): client, server = self._setup(make_simple_handler('EXPUNGE', ['* 3 EXPUNGE', '* 3 EXPUNGE', '* 5 EXPUNGE', '* 8 EXPUNGE'])) @@ -1022,6 +1139,11 @@ def test_create(self): self.assertEqual(data, [b'CREATE completed']) self.assertEqual(server.args, ['owatagusiam/blurdybloop']) + typ, data = client.create('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'CREATE completed']) + self.assertEqual(server.args, ['"New folder"']) + def test_copy(self): client, server = self._setup(make_simple_handler('COPY')) client.login('user', 'pass') @@ -1031,6 +1153,11 @@ def test_copy(self): self.assertEqual(data, [b'COPY completed']) self.assertEqual(server.args, ['2:4', 'MEETING']) + typ, data = client.copy('2:4', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'COPY completed']) + self.assertEqual(server.args, ['2:4', '"New folder"']) + def test_uid_copy(self): client, server = self._setup(make_simple_handler('UID', completed='UID COPY completed')) @@ -1041,6 +1168,11 @@ def test_uid_copy(self): self.assertEqual(data, [None]) self.assertEqual(server.args, ['COPY', '4827313:4828442', 'MEETING']) + typ, data = client.uid('copy', '4827313:4828442', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [None]) + self.assertEqual(server.args, ['COPY', '4827313:4828442', '"New folder"']) + def test_store(self): client, server = self._setup(make_simple_handler('STORE', [ r'* 2 FETCH (FLAGS (\Deleted \Seen))', @@ -1079,6 +1211,10 @@ def test_uid_store(self): ]) self.assertEqual(server.args, ['STORE', '4827313:4828442', '+FLAGS', r'(\Deleted)']) + typ, data = client.uid('store', '4827313:4828442', '+FLAGS', r'\Deleted') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['STORE', '4827313:4828442', '+FLAGS', r'(\Deleted)']) + def test_fetch(self): # The handler expands the requested sequence set and answers for # exactly those messages, so the test exercises the round trip of @@ -1123,6 +1259,19 @@ def cmd_FETCH(self, tag, args): self.assertEqual(data, [br'1 (FLAGS (\Seen))']) self.assertEqual(server.args, ['1', '(BODY[HEADER.FIELDS (DATE FROM)])']) + # message_parts is wrapped in parentheses if it is not already. + typ, data = client.fetch('2:4', 'FLAGS') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['2:4', '(FLAGS)']) + + # But the macros are not, as they are not data item names. + typ, data = client.fetch('2:4', 'ALL') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['2:4', 'ALL']) + typ, data = client.fetch('2:4', 'fast') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['2:4', 'fast']) + def test_uid_fetch(self): client, server = self._setup(make_simple_handler('UID', [ r'* 23 FETCH (FLAGS (\Seen) UID 4827313)', @@ -1140,6 +1289,14 @@ def test_uid_fetch(self): ]) self.assertEqual(server.args, ['FETCH', '4827313:4828442', '(FLAGS)']) + typ, data = client.uid('fetch', '4827313:4828442', 'FLAGS') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['FETCH', '4827313:4828442', '(FLAGS)']) + + typ, data = client.uid('fetch', '4827313:4828442', 'ALL') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['FETCH', '4827313:4828442', 'ALL']) + def test_partial(self): client, server = self._setup(make_simple_handler('PARTIAL', ['* 1 FETCH (RFC822.TEXT<0.10> "0123456789")'])) @@ -1173,6 +1330,10 @@ def test_search(self): self.assertEqual(data, [b'43']) self.assertEqual(server.args, ['CHARSET', 'UTF-8', 'TEXT', 'XXXXXX']) + typ, data = client.search('NF_Z_62-010_(1973)', 'TEXT', 'XXXXXX') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['CHARSET', '"NF_Z_62-010_(1973)"', 'TEXT', 'XXXXXX']) + def test_uid_search(self): response = [] client, server = self._setup(make_simple_handler('UID', response, @@ -1224,6 +1385,10 @@ def test_sort(self): self.assertEqual(data, [br'']) self.assertEqual(server.args, ['(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"']) + typ, data = client.sort('SUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['(SUBJECT)', '"NF_Z_62-010_(1973)"', 'TEXT', '"not in mailbox"']) + def test_uid_sort(self): response = [] client, server = self._setup(make_simple_handler('UID', response, @@ -1248,6 +1413,10 @@ def test_uid_sort(self): self.assertEqual(data, [br'']) self.assertEqual(server.args, ['SORT', '(SUBJECT)', 'US-ASCII', 'TEXT', '"not in mailbox"']) + typ, data = client.uid('sort', 'SUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"not in mailbox"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['SORT', '(SUBJECT)', '"NF_Z_62-010_(1973)"', 'TEXT', '"not in mailbox"']) + def test_thread(self): response = [] client, server = self._setup(make_simple_handler('THREAD', response)) @@ -1285,6 +1454,10 @@ def test_thread(self): b'(199)(200 202)(201)(203)(204)(205 206 207)(208)']) self.assertEqual(server.args, ['ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"']) + typ, data = client.thread('ORDEREDSUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"gewp"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['ORDEREDSUBJECT', '"NF_Z_62-010_(1973)"', 'TEXT', '"gewp"']) + def test_uid_thread(self): response = [] client, server = self._setup(make_simple_handler('UID', response, @@ -1323,6 +1496,10 @@ def test_uid_thread(self): b'(199)(200 202)(201)(203)(204)(205 206 207)(208)']) self.assertEqual(server.args, ['THREAD', 'ORDEREDSUBJECT', 'US-ASCII', 'TEXT', '"gewp"']) + typ, data = client.uid('THREAD', 'ORDEREDSUBJECT', 'NF_Z_62-010_(1973)', 'TEXT', '"gewp"') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['THREAD', 'ORDEREDSUBJECT', '"NF_Z_62-010_(1973)"', 'TEXT', '"gewp"']) + def test_delete(self): client, server = self._setup(make_simple_handler('DELETE')) client.login('user', 'pass') @@ -1335,6 +1512,10 @@ def test_delete(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['foo/bar']) + typ, data = client.delete('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_rename(self): client, server = self._setup(make_simple_handler('RENAME')) client.login('user', 'pass') @@ -1343,6 +1524,10 @@ def test_rename(self): self.assertEqual(data, [b'RENAME completed']) self.assertEqual(server.args, ['blurdybloop', 'sarasoop']) + typ, data = client.rename('Old folder', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"Old folder"', '"New folder"']) + def test_subscribe(self): client, server = self._setup(make_simple_handler('SUBSCRIBE')) client.login('user', 'pass') @@ -1351,6 +1536,10 @@ def test_subscribe(self): self.assertEqual(data, [b'SUBSCRIBE completed']) self.assertEqual(server.args, ['#news.comp.mail.mime']) + typ, data = client.subscribe('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_unsubscribe(self): client, server = self._setup(make_simple_handler('UNSUBSCRIBE')) client.login('user', 'pass') @@ -1359,6 +1548,10 @@ def test_unsubscribe(self): self.assertEqual(data, [b'UNSUBSCRIBE completed']) self.assertEqual(server.args, ['#news.comp.mail.mime']) + typ, data = client.unsubscribe('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_list(self): client, server = self._setup(make_simple_handler('LIST', [r'* LIST (\Noselect) "/" ""', @@ -1374,6 +1567,15 @@ def test_list(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['~/Mail/', '%']) + typ, data = client.list('New folder', '*') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '*']) + + # A pattern without wildcards is quoted when necessary. + typ, data = client.list('~/Mail/', 'My Folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['~/Mail/', '"My Folder"']) + def test_status(self): client, server = self._setup(make_simple_handler('STATUS', ['* STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)'])) @@ -1383,6 +1585,11 @@ def test_status(self): self.assertEqual(data, [b'blurdybloop (MESSAGES 231 UIDNEXT 44292)']) self.assertEqual(server.args, ['blurdybloop', '(UIDNEXT MESSAGES)']) + # The names argument is wrapped in parentheses if it is not already. + typ, data = client.status('New folder', 'UIDNEXT MESSAGES') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '(UIDNEXT MESSAGES)']) + def test_getacl(self): client, server = self._setup(make_simple_handler('GETACL', ['* ACL INBOX Fred rwipslxetad'])) @@ -1392,6 +1599,10 @@ def test_getacl(self): self.assertEqual(data, [b'INBOX Fred rwipslxetad']) self.assertEqual(server.args, ['INBOX']) + typ, data = client.getacl('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_setacl(self): client, server = self._setup(make_simple_handler('SETACL')) client.login('user', 'pass') @@ -1400,6 +1611,15 @@ def test_setacl(self): self.assertEqual(data, [b'SETACL completed']) self.assertEqual(server.args, ['INBOX', 'Fred', 'rwipslxetad']) + typ, data = client.setacl('New folder', 'Fred', '+lr') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', 'Fred', '+lr']) + + # The identifier and the rights are quoted when necessary too. + typ, data = client.setacl('INBOX', 'John Doe', 'a b') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['INBOX', '"John Doe"', '"a b"']) + def test_deleteacl(self): client, server = self._setup(make_simple_handler('DELETEACL')) client.login('user', 'pass') @@ -1408,6 +1628,11 @@ def test_deleteacl(self): self.assertEqual(data, [b'DELETEACL completed']) self.assertEqual(server.args, ['INBOX', 'Fred']) + # The identifier is quoted when necessary too. + typ, data = client.deleteacl('New folder', 'John Doe') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '"John Doe"']) + def test_myrights(self): client, server = self._setup(make_simple_handler('MYRIGHTS', ['* MYRIGHTS INBOX rwiptsldaex'])) @@ -1417,6 +1642,10 @@ def test_myrights(self): self.assertEqual(data, [b'INBOX rwiptsldaex']) self.assertEqual(server.args, ['INBOX']) + typ, data = client.myrights('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_getquota(self): client, server = self._setup(make_simple_handler('GETQUOTA', ['* QUOTA "" (STORAGE 10 512)'])) @@ -1426,6 +1655,10 @@ def test_getquota(self): self.assertEqual(data, [b'"" (STORAGE 10 512)']) self.assertEqual(server.args, ['#news']) + typ, data = client.getquota('') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['""']) + def test_getquotaroot(self): client, server = self._setup(make_simple_handler('GETQUOTAROOT', ['* QUOTAROOT INBOX ""', '* QUOTA "" (STORAGE 10 512)'])) @@ -1435,6 +1668,10 @@ def test_getquotaroot(self): self.assertEqual(data, [[b'INBOX ""'], [b'"" (STORAGE 10 512)']]) self.assertEqual(server.args, ['INBOX']) + typ, data = client.getquotaroot('New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"']) + def test_setquota(self): client, server = self._setup(make_simple_handler('SETQUOTA', ['* QUOTA "" (STORAGE 512)'])) @@ -1444,6 +1681,15 @@ def test_setquota(self): self.assertEqual(data, [b'"" (STORAGE 512)']) self.assertEqual(server.args, ['#news', '(STORAGE 512)']) + typ, data = client.setquota('', '(STORAGE 512)') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['""', '(STORAGE 512)']) + + # The limits argument is wrapped in parentheses if it is not already. + typ, data = client.setquota('', 'STORAGE 512') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['""', '(STORAGE 512)']) + def test_getannotation(self): client, server = self._setup(make_simple_handler('GETANNOTATION', ['* ANNOTATION INBOX "/comment" ("value.shared" "Hello")'])) @@ -1453,6 +1699,10 @@ def test_getannotation(self): self.assertEqual(data, [b'INBOX "/comment" ("value.shared" "Hello")']) self.assertEqual(server.args, ['INBOX', '/comment', 'value.shared']) + typ, data = client.getannotation('New folder', '/comment', 'value.shared') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"New folder"', '/comment', 'value.shared']) + def test_setannotation(self): client, server = self._setup(make_simple_handler('SETANNOTATION')) client.login('user', 'pass') @@ -1462,6 +1712,12 @@ def test_setannotation(self): self.assertEqual(server.args, ['INBOX', '/comment', '("value.shared" "My comment")']) + typ, data = client.setannotation('New folder', '/comment', + '("value.shared" "My comment")') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, + ['"New folder"', '/comment', '("value.shared" "My comment")']) + def test_proxyauth(self): client, server = self._setup(make_simple_handler('PROXYAUTH')) client.login('user', 'pass') @@ -1470,6 +1726,10 @@ def test_proxyauth(self): self.assertEqual(data, [b'PROXYAUTH completed']) self.assertEqual(server.args, ['user']) + typ, data = client.proxyauth('us er') + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['"us er"']) + def test_xatom(self): client, server = self._setup(make_simple_handler('MYCOMMAND', completed='MYCOMMAND completed')) @@ -1753,6 +2013,7 @@ def cmd_APPEND(self, tag, args): code, _ = client.enable('UTF8=ACCEPT') self.assertEqual(code, 'OK') self.assertEqual(client._encoding, 'utf-8') + self.assertEqual(server.args, ['UTF8=ACCEPT']) msg_string = 'Subject: üñí©öðé' typ, data = client.append( None, None, None, (msg_string + '\n').encode('utf-8')) @@ -1908,7 +2169,7 @@ def test_with_statement(self): with self.reaped_server(SimpleIMAPHandler) as server: with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) self.assertIsNone(server.logged) @threading_helper.reap_threads @@ -1917,7 +2178,7 @@ def test_with_statement_logout(self): with self.reaped_server(SimpleIMAPHandler) as server: with self.imap_class(*server.server_address) as imap: imap.login('user', 'pass') - self.assertEqual(server.logged, 'user') + self.assertEqual(server.logged, ['user', '"pass"']) imap.logout() self.assertIsNone(server.logged) self.assertIsNone(server.logged) diff --git a/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst b/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst new file mode 100644 index 000000000000000..1f393d23266bcef --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-30-12-00-00.gh-issue-40038.qK7mGv.rst @@ -0,0 +1,6 @@ +:mod:`imaplib` now again quotes command arguments when necessary, for +example mailbox names containing a space. Such quoting was inadvertently +disabled when the module was ported to Python 3, and the arguments are now +quoted according to the :rfc:`3501` grammar. For backward compatibility, +an argument already enclosed in double quotes is left unchanged, so code +that quotes arguments itself keeps working. From 01ab25b967ee00ce756747ea46c61c3d20835627 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 10:48:02 +0300 Subject: [PATCH 15/61] gh-151819: Clarify the conditional-pattern email example in re docs (GH-153072) The example pattern does not fail to match ' --- Doc/library/re.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 617dc96f479926c..1aefb91e0ceb405 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -531,8 +531,9 @@ The special characters are: *name* exists, and with ``no-pattern`` if it doesn't. ``no-pattern`` is optional and can be omitted. For example, ``(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)`` is a poor email matching pattern, which - will match with ``''`` as well as ``'user@host.com'``, but - not with ``''``. + matches ``''`` as well as ``'user@host.com'``, but does not + match ``''`` in their entirety + (:func:`re.search` finds only ``'user@host.com'`` in the former). .. versionchanged:: 3.12 Group *id* can only contain ASCII digits. From ca35692d1bddd4494742a1ffd4379813148fb9d1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 11:08:15 +0300 Subject: [PATCH 16/61] gh-66335: Test uppercase IMAP4 command names (GH-152876) Co-authored-by: Milan Oberkirch Co-authored-by: Claude Opus 4.8 (1M context) --- Lib/test/test_imaplib.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 5d9ca170ea59fda..cdc2f9c8d852322 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1740,6 +1740,16 @@ def test_xatom(self): self.assertEqual(data, [b'MYCOMMAND completed']) self.assertEqual(server.args, ['arg1', 'arg2']) + def test_uppercase_command_names(self): + client, server = self._setup(SimpleIMAPHandler) + client.login('user', 'pass') + self.assertEqual(client.CAPABILITY, client.capability) + self.assertEqual(client.SELECT, client.select) + typ, data = client.CAPABILITY() + self.assertEqual(typ, 'OK') + with self.assertRaises(AttributeError): + client.NONEXISTENT + def test_control_characters(self): client, _ = self._setup(SimpleIMAPHandler) for c0 in support.control_characters_c0(): From d161d9506a15f3d45f1431b15974b5bd129ac9a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 5 Jul 2026 11:25:30 +0200 Subject: [PATCH 17/61] gh-151945: fix Sphinx reference warnings in `http.server` docs (#153084) --- Doc/library/http.server.rst | 48 ++++++++++++++++++++++++++++++++++--- Doc/tools/.nitignore | 1 - 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index c4b9173f9e34eb2..9c2ce2dffb185e9 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -39,7 +39,17 @@ handler. Code to create and run the server looks like this:: This class builds on the :class:`~socketserver.TCPServer` class by storing the server address as instance variables named :attr:`server_name` and :attr:`server_port`. The server is accessible by the handler, typically - through the handler's :attr:`server` instance variable. + through the handler's :attr:`~socketserver.BaseRequestHandler.server` + instance variable. + + .. attribute:: server_name + + The HTTP server's fully qualified domain name. + + .. attribute:: server_port + + The HTTP server's port number obtained from *server_address*. + .. class:: ThreadingHTTPServer(server_address, RequestHandlerClass) @@ -402,6 +412,14 @@ instantiation, of which this module provides three different variants: .. versionadded:: 3.15 + .. attribute:: index_pages + + Specifies the filenames that are treated as directory index pages. + + Defaults to ``("index.html", "index.htm")``. + + .. versionadded:: 3.12 + .. attribute:: extensions_map A dictionary mapping suffixes into MIME types, contains custom overrides @@ -435,7 +453,7 @@ instantiation, of which this module provides three different variants: path relative to the current working directory. If the request was mapped to a directory, the directory is checked for a - file named ``index.html`` or ``index.htm`` (in that order). If found, the + an index page as specified by :attr:`index_pages`. If found, the file's contents are returned; otherwise a directory listing is generated by calling the :meth:`list_directory` method. This method uses :func:`os.listdir` to scan the directory, and returns a ``404`` error @@ -465,6 +483,30 @@ instantiation, of which this module provides three different variants: .. versionchanged:: 3.7 Support of the ``'If-Modified-Since'`` header. + .. method:: list_directory(path) + + Helper to list the contents of *path* when no index page is present. + + This returns either a :term:`file-like object` (which must be closed + by the caller) or ``None`` to indicate an error, in which case the + caller has nothing further to do. In either case, the headers are sent. + + .. method:: guess_type(path) + + Guess the type of the file at the given *path*. + + This returns a string of the form ``type/subtype``, usable for + a MIME Content-type header. + + The default implementation looks the file's extension up in + :attr:`extensions_map`, falling back to + :func:`mimetypes.guess_file_type` and then to + :attr:`default_content_type`. + + .. versionchanged:: 3.13 + Add :func:`mimetypes.guess_file_type` as a fallback. + + The :class:`SimpleHTTPRequestHandler` class can be used in the following manner in order to create a very basic webserver serving files relative to the current directory:: @@ -483,7 +525,7 @@ the current directory:: :class:`SimpleHTTPRequestHandler` can also be subclassed to enhance behavior, such as using different index file names by overriding the class attribute -:attr:`index_pages`. +:attr:`~SimpleHTTPRequestHandler.index_pages`. .. _http-server-cli: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 7b956f0ef0eb2c4..8ac0e8ffcffc277 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -9,7 +9,6 @@ Doc/library/ast.rst Doc/library/asyncio-extending.rst Doc/library/email.charset.rst Doc/library/email.parser.rst -Doc/library/http.server.rst Doc/library/importlib.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst From bec650ebd3d69318e8dc7e3d79a156bc92a7c3d1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 13:48:23 +0300 Subject: [PATCH 18/61] gh-54930: Send a status line in error responses to malformed request lines (GH-152980) Previously such error responses were sent in the bare HTTP/0.9 style, without a status line and headers. Co-authored-by: Claude Fable 5 --- Lib/http/server.py | 6 +++++- Lib/test/test_httpservers.py | 15 +++++++++++++++ .../2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst | 5 +++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst diff --git a/Lib/http/server.py b/Lib/http/server.py index ebc85052aecb900..095b5744bd12fc6 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -334,10 +334,13 @@ def parse_request(self): raise ValueError("unreasonable length http version") version_number = int(version_number[0]), int(version_number[1]) except (ValueError, IndexError): + # Send the error response with a status line and headers. + self.request_version = '' self.send_error( HTTPStatus.BAD_REQUEST, "Bad request version (%r)" % version) return False + self.request_version = version if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1": self.close_connection = False if version_number >= (2, 0): @@ -345,9 +348,9 @@ def parse_request(self): HTTPStatus.HTTP_VERSION_NOT_SUPPORTED, "Invalid HTTP version (%s)" % base_version_number) return False - self.request_version = version if not 2 <= len(words) <= 3: + self.request_version = '' self.send_error( HTTPStatus.BAD_REQUEST, "Bad request syntax (%r)" % requestline) @@ -356,6 +359,7 @@ def parse_request(self): if len(words) == 2: self.close_connection = True if command != 'GET': + self.request_version = '' self.send_error( HTTPStatus.BAD_REQUEST, "Bad HTTP/0.9 request type (%r)" % command) diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index d4ae032610a91e2..63f65a9c5cf47a9 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -386,6 +386,8 @@ def test_simple_get(self): def test_invalid_request(self): self.sock.send(b'POST /index.html\r\n') res = self.sock.recv(1024) + # The error response is not sent in the bare HTTP/0.9 style. + self.assertStartsWith(res, b'HTTP/1.0 400 ') self.assertIn(b"Bad HTTP/0.9 request type ('POST')", res) def test_single_request(self): @@ -1102,6 +1104,19 @@ def test_http_0_9(self): self.assertEqual(result[0], b'Data\r\n') self.verify_get_called() + @support.subTests('request,code', [ + (b'GET / FUBAR\r\n\r\n', 400), # bad version + (b'GET / HTTP/2.0\r\n\r\n', 505), # unsupported version + (b'GET\r\n', 400), # bad syntax + (b'POST /\r\n', 400), # bad HTTP/0.9 request type + ]) + def test_request_line_error_has_status_line(self, request, code): + self.handler = SocketlessRequestHandler() + result = self.send_typical_request(request) + self.assertStartsWith(result[0], b'HTTP/1.1 %d ' % code) + self.verify_expected_headers(result[1:result.index(b'\r\n')]) + self.assertFalse(self.handler.get_called) + def test_extra_space(self): result = self.send_typical_request( b'GET /spaced out HTTP/1.1\r\n' diff --git a/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst b/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst new file mode 100644 index 000000000000000..1cfc0212c609a69 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst @@ -0,0 +1,5 @@ +Error responses of :class:`http.server.BaseHTTPRequestHandler` to malformed +request lines now include a status line and headers instead of being sent in +the bare HTTP/0.9 style. +Only a valid HTTP/0.9 request (a two-word ``GET`` request line) now receives +an HTTP/0.9 style response. From 12cccf2d4bef466624942ab275a7ef59179968f1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 13:51:34 +0300 Subject: [PATCH 19/61] gh-69134: Wait until mapped in SimpleDialog keyboard tests (GH-152690) The SimpleDialog keyboard tests generate key events after focus_force(), which on Windows are dropped until the toplevel is mapped, so they could fail intermittently (seen on the Windows10 buildbot as test_return_no_default). Wait until the window is mapped in each of these tests, as GH-152599 did for the other keyboard tests. Co-authored-by: Claude Opus 4.8 --- Lib/test/test_tkinter/test_simpledialog.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/test/test_tkinter/test_simpledialog.py b/Lib/test/test_tkinter/test_simpledialog.py index 5c739d9ad6e6422..33a0173ba67adb9 100644 --- a/Lib/test/test_tkinter/test_simpledialog.py +++ b/Lib/test/test_tkinter/test_simpledialog.py @@ -44,6 +44,7 @@ def test_use_ttk(self): self.assertEqual(str(d.root.cget('background')), ttk.Style(d.root).lookup('.', 'background')) # The bindings work with the themed buttons too. + self.require_mapped(d.root) d._buttons[0].focus_force() d.root.update() d.root.event_generate('') @@ -139,6 +140,7 @@ def test_alt_key(self): # Alt + an underlined character (the "underline" button option) invokes # the matching button (cf. tk::AmpWidget in tk::MessageBox). d = self.create(buttons=['Yes', {'text': 'No', 'underline': 0}]) + self.require_mapped(d.root) d._buttons[0].focus_force() d.root.update() d.root.event_generate('') # "No" -> underline 0 -> "N" @@ -149,6 +151,7 @@ def test_return_invokes_focused_button(self): # invokes the button with the focus, even if it is not the # default and the focus was not moved by keyboard traversal. d = self.create(buttons=['Yes', 'No']) # default 0 + self.require_mapped(d.root) d._buttons[1].focus_force() d.root.update() d.root.event_generate('') @@ -158,6 +161,7 @@ def test_return_invokes_focused_button(self): def test_focus_next_then_return(self): # moves the focus to the next button; invokes it. d = self.create(buttons=['Yes', 'No']) + self.require_mapped(d.root) d._buttons[0].focus_force() d.root.update() d._buttons[0].event_generate('') @@ -169,6 +173,7 @@ def test_focus_next_then_return(self): def test_focus_prev_then_return(self): # moves the focus to the previous button. d = self.create(buttons=['Yes', 'No']) + self.require_mapped(d.root) d._buttons[1].focus_force() d.root.update() d._buttons[1].event_generate('') @@ -180,6 +185,7 @@ def test_focus_prev_then_return(self): def test_return_activates_default(self): # with the focus off the buttons invokes the default button. d = self.create() # default 0 + self.require_mapped(d.root) d.root.focus_force() # the dialog, not a button, has the focus d.root.update() d.root.event_generate('') @@ -190,6 +196,7 @@ def test_return_no_default(self): # With no default button, off the buttons rings the bell and # leaves the dialog open instead of activating a button. d = self.create(default=None) + self.require_mapped(d.root) d.root.focus_force() # the dialog, not a button, has the focus d.root.update() bells = [] From 23a09b284e556c9e198626c2b1ef64f9ed55b4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 5 Jul 2026 12:58:53 +0200 Subject: [PATCH 20/61] Fix various typos in the `http.server` docs (#153089) --- Doc/library/http.server.rst | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 9c2ce2dffb185e9..0d427db19c0fcdb 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -70,7 +70,7 @@ handler. Code to create and run the server looks like this:: object fails with a :exc:`RuntimeError`. The *certfile* argument is the path to the SSL certificate chain file, - and the *keyfile* is the path to file containing the private key. + and the *keyfile* is the path to the file containing the private key. A *password* can be specified for files protected and wrapped with PKCS#8, but beware that this could possibly expose hardcoded passwords in clear. @@ -150,7 +150,7 @@ instantiation, of which this module provides three different variants: .. attribute:: path - Contains the request path. If query component of the URL is present, + Contains the request path. If the query component of the URL is present, then ``path`` includes the query. Using the terminology of :rfc:`3986`, ``path`` here includes ``hier-part`` and the ``query``. @@ -200,7 +200,7 @@ instantiation, of which this module provides three different variants: Specifies a format string that should be used by :meth:`send_error` method for building an error response to the client. The string is filled by default with variables from :attr:`responses` based on the status code - that passed to :meth:`send_error`. + passed to :meth:`send_error`. .. attribute:: error_content_type @@ -248,8 +248,8 @@ instantiation, of which this module provides three different variants: .. method:: handle_expect_100() When an HTTP/1.1 conformant server receives an ``Expect: 100-continue`` - request header it responds back with a ``100 Continue`` followed by ``200 - OK`` headers. + request header it responds with a ``100 Continue`` followed by ``200 OK`` + headers. This method can be overridden to raise an error if the server does not want the client to continue. For example, the server can choose to send ``417 Expectation Failed`` as a response header and ``return False``. @@ -305,8 +305,8 @@ instantiation, of which this module provides three different variants: .. method:: send_response_only(code, message=None) Sends the response header only, used for the purposes when ``100 - Continue`` response is sent by the server to the client. The headers not - buffered and sent directly the output stream.If the *message* is not + Continue`` response is sent by the server to the client. The headers are + not buffered and sent directly the output stream. If the *message* is not specified, the HTTP message corresponding the response *code* is sent. This method does not reject *message* containing CRLF sequences. @@ -348,7 +348,7 @@ instantiation, of which this module provides three different variants: to create custom error logging mechanisms. The *format* argument is a standard printf-style format string, where the additional arguments to :meth:`log_message` are applied as inputs to the formatting. The client - ip address and current date and time are prefixed to every message logged. + IP address and current date and time are prefixed to every message logged. .. method:: version_string() @@ -452,7 +452,7 @@ instantiation, of which this module provides three different variants: The request is mapped to a local file by interpreting the request as a path relative to the current working directory. - If the request was mapped to a directory, the directory is checked for a + If the request was mapped to a directory, the directory is checked for an index page as specified by :attr:`index_pages`. If found, the file's contents are returned; otherwise a directory listing is generated by calling the :meth:`list_directory` method. This method uses @@ -507,9 +507,8 @@ instantiation, of which this module provides three different variants: Add :func:`mimetypes.guess_file_type` as a fallback. -The :class:`SimpleHTTPRequestHandler` class can be used in the following -manner in order to create a very basic webserver serving files relative to -the current directory:: +The :class:`SimpleHTTPRequestHandler` class can be used to create a very basic +webserver serving files relative to the current directory as follows:: import http.server import socketserver @@ -641,8 +640,8 @@ The following options are accepted: .. option:: -H, --header
- Specify an additional extra HTTP Response Header to send on successful HTTP - 200 responses. Can be used multiple times to send additional custom response + Specify an additional HTTP Response Header to send on successful HTTP 200 + responses. Can be used multiple times to send additional custom response headers. Headers that are sent automatically by the server (for instance Content-Type) will not be overwritten by the server. @@ -657,13 +656,13 @@ Security considerations .. index:: pair: http.server; security :class:`SimpleHTTPRequestHandler` will follow symbolic links when handling -requests, this makes it possible for files outside of the specified directory +requests which makes it possible for files outside of the specified directory to be served. Methods :meth:`BaseHTTPRequestHandler.send_header` and :meth:`BaseHTTPRequestHandler.send_response_only` assume sanitized input and do not perform input validation such as checking for the presence of CRLF -sequences. Untrusted input may result in HTTP Header injection attacks. +sequences. Untrusted input may result in HTTP header injection attacks. Earlier versions of Python did not scrub control characters from the log messages emitted to stderr from ``python -m http.server`` or the From 071138368d9da0532eecde30257b3b4102d02714 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 14:07:12 +0300 Subject: [PATCH 21/61] gh-123193: Document tkinter Variable lifetime (GH-152625) A Tk variable wrapper unsets its Tcl variable when garbage collected, so a reference must be kept while a widget uses it. Otherwise Tk recreates the Tcl variable but never unsets it again, leaking it. Co-authored-by: Claude Opus 4.8 --- Doc/library/tkinter.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 8c4678b4b23c778..b84d76b72d2e5b5 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -656,6 +656,9 @@ method on it, and to change its value you call the :meth:`!set` method. If you follow this protocol, the widget will always track the value of the variable, with no further intervention on your part. +Keep a reference to the variable for as long as a widget uses it, for example +by storing it as an attribute (see :class:`Variable`). + For example:: import tkinter as tk @@ -5916,6 +5919,14 @@ Variable classes :class:`StringVar`, :class:`IntVar`, :class:`DoubleVar` or :class:`BooleanVar` -- rather than :class:`!Variable` directly. + .. note:: + + When a :class:`!Variable` is garbage collected, its Tcl variable is unset. + Keep a reference to it for as long as a widget is linked to it, for example + by storing it as an attribute rather than in a local variable. + Otherwise Tk recreates the Tcl variable to keep the widget working, but it + is never unset again, leaking one Tcl variable per dropped wrapper. + .. versionchanged:: 3.10 Two variables now compare equal (``==``) only when they have the same name, are of the same class, and belong to the same Tcl interpreter. From d87decf9a5eee698b60d7c0626acb36951f843fc Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 14:07:49 +0300 Subject: [PATCH 22/61] gh-75952: Document negative offsets in tkinter geometry strings (GH-152531) Tk geometry strings can contain a negative offset (e.g. 200x100+-9+-8) when a window edge is positioned beyond the corresponding screen edge. Note this in the geometry() and winfo_geometry() documentation. Co-authored-by: Claude Opus 4.8 --- Doc/library/tkinter.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index b84d76b72d2e5b5..6c22f9a8020b269 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -2074,6 +2074,7 @@ Base and mixin classes Return the geometry of the widget, in the form ``widthxheight+x+y``. All dimensions are in pixels. + An offset can be negative; see :meth:`~Wm.geometry`. .. method:: winfo_height() @@ -2544,6 +2545,8 @@ Base and mixin classes *width* and *height* are in pixels (or grid units for a gridded window); a position preceded by ``+`` is measured from the left or top edge of the screen and one preceded by ``-`` from the right or bottom edge. + An offset can be negative, as in ``'200x100+-9+-8'``, when the window + edge is positioned beyond the corresponding screen edge. An empty string cancels any user-specified geometry, letting the window revert to its natural size. With no argument, return the current geometry as a string of the form From 4fcfa1f1a2032ec65acad83e8ccec25e7629c081 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 14:13:01 +0300 Subject: [PATCH 23/61] gh-79638: Restore "Treat an unreachable robots.txt as disallow all" (GH-152525) This change was accidentally reverted by f0daba1652c (gh-106693, GH-149514), which only intended to revert the ob_sval change. The tests were already restored by GH-149569. Co-authored-by: Claude Opus 4.8 (1M context) --- Lib/urllib/robotparser.py | 10 +++++++++- .../2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py index e70eae800367840..0c3e5d928909358 100644 --- a/Lib/urllib/robotparser.py +++ b/Lib/urllib/robotparser.py @@ -65,9 +65,17 @@ def read(self): f = urllib.request.urlopen(self.url) except urllib.error.HTTPError as err: if err.code in (401, 403): + # If access to robot.txt has the status Unauthorized/Forbidden, + # then most likely this applies to the entire site. self.disallow_all = True - elif err.code >= 400 and err.code < 500: + elif 400 <= err.code < 500: + # RFC 9309, Section 2.3.1.3: the crawler MAY access any + # resources on the server. self.allow_all = True + elif 500 <= err.code < 600: + # RFC 9309, Section 2.3.1.4: the crawler MUST assume + # complete disallow. + self.disallow_all = True err.close() else: raw = f.read() diff --git a/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst b/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst new file mode 100644 index 000000000000000..bd9fff0bc2e31b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-05-20-50-35.gh-issue-79638.Y-JfaH.rst @@ -0,0 +1,2 @@ +Disallow all access in :mod:`urllib.robotparser` if the ``robots.txt`` file +is unreachable due to server or network errors. From c4f7913e69bae74f9bb356666f1d2d258041c91b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 14:13:52 +0300 Subject: [PATCH 24/61] gh-76607: Improve documentation of the tkinter cursor option (GH-152481) Link to the cursors(3tk) manual page for the available cursor names and note that they are platform-dependent. Co-authored-by: Claude Opus 4.8 --- Doc/library/tkinter.rst | 14 ++++++++++---- Doc/library/tkinter.ttk.rst | 7 ++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 6c22f9a8020b269..ca034fcdc09b439 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -737,6 +737,8 @@ Here are some examples of typical usage:: myapp.mainloop() +.. _Tk-option-data-types: + Tk option data types ^^^^^^^^^^^^^^^^^^^^ @@ -770,12 +772,16 @@ color represent any legal hex digit. See page 160 of Ousterhout's book for details. cursor - The standard X cursor names from :file:`cursorfont.h` can be used, without the - ``XC_`` prefix. For example to get a hand cursor (``XC_hand2``), use the - string ``"hand2"``. You can also specify a bitmap and mask file of your own. + The name of the mouse cursor to display while the pointer is over the widget. + Tk provides a portable set of cursor names available on all platforms + (for example ``"arrow"``, ``"watch"``, ``"cross"``, or ``"hand2"``); + the standard X cursor names from :file:`cursorfont.h` may also be used, + without the ``XC_`` prefix (so ``XC_hand2`` becomes ``"hand2"``). + The full list of names, including the platform-specific ones, + is given in the :manpage:`cursors(3tk)` manual page. + You can also specify a bitmap and mask file of your own. On Windows a cursor file (:file:`.cur` or :file:`.ani`) may be used directly, giving its path preceded with an ``@``, as in ``"@C:/cursors/bart.ani"``. - See page 179 of Ousterhout's book. distance Screen distances can be specified in either pixels or absolute distances. diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index ef7bbd130fb8883..13b374e23558fc3 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -116,9 +116,10 @@ All the :mod:`!ttk` Widgets accept the following options: | | read-only, and may only be specified when the window is | | | created. | +-----------+--------------------------------------------------------------+ -| cursor | Specifies the mouse cursor to be used for the widget. If set | -| | to the empty string (the default), the cursor is inherited | -| | from the parent widget. | +| cursor | Specifies the mouse cursor to be used for the widget. See | +| | the *cursor* option type under :ref:`Tk-option-data-types`. | +| | If set to the empty string (the default), the cursor is | +| | inherited from the parent widget. | +-----------+--------------------------------------------------------------+ | takefocus | Determines whether the window accepts the focus during | | | keyboard traversal. 0, 1 or an empty string is returned. | From 93657e1bb2997ebac5aafe6fd9662bf89d8bd489 Mon Sep 17 00:00:00 2001 From: Jonathan Dung Date: Sun, 5 Jul 2026 19:23:49 +0800 Subject: [PATCH 25/61] Fix minor typos in 'Compound statements' docs (#149666) Co-authored-by: Stan Ulbrych --- Doc/reference/compound_stmts.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index b3168bb85b4765d..e74f3262ed540cd 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -279,12 +279,12 @@ and the exception occurs in the :keyword:`!try` clause of the inner handler, the outer handler will not handle the exception.) When an exception has been assigned using ``as target``, it is cleared at the -end of the :keyword:`!except` clause. This is as if :: +end of the :keyword:`!except` clause. This is as if:: except E as N: foo -was translated to :: +was translated to:: except E as N: try: @@ -341,7 +341,7 @@ can have either :keyword:`except` or :keyword:`!except*` clauses, but not both. The exception type for matching is mandatory in the case of :keyword:`!except*`, so ``except*:`` is a syntax error. The type is interpreted as in the case of :keyword:`!except`, but matching is performed on the exceptions contained in the -group that is being handled. An :exc:`TypeError` is raised if a matching +group that is being handled. A :exc:`TypeError` is raised if a matching type is a subclass of :exc:`!BaseExceptionGroup`, because that would have ambiguous semantics. @@ -357,7 +357,7 @@ or the last :keyword:`!except*` clause has run. After all :keyword:`!except*` clauses execute, the group of unhandled exceptions is merged with any exceptions that were raised or re-raised from within -:keyword:`!except*` clauses. This merged exception group propagates on.:: +:keyword:`!except*` clauses. This merged exception group propagates on:: >>> try: ... raise ExceptionGroup("eg", @@ -1311,7 +1311,7 @@ mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default parameter value is in effect modified. This is generally not what was intended. A way around this is to use ``None`` as the default, and explicitly test for it in the body of the function, -e.g.:: +for example:: def whats_on_the_telly(penguin=None): if penguin is None: From cb109269f4cd11d9be56fe86d4e62130a8ba95e5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 14:27:51 +0300 Subject: [PATCH 26/61] gh-59396: Use themed widgets in tkinter.filedialog (GH-152036) The FileDialog, LoadFileDialog and SaveFileDialog dialogs are now built from the themed tkinter.ttk widgets by default instead of the classic tkinter widgets, and gained a use_ttk parameter that selects between the classic Tk widgets and the themed ttk widgets. They were also brought closer to the native Tk file dialog: the buttons and field labels gained Alt key accelerators, the default ring follows the keyboard focus, the Escape key cancels the dialog, the focus traverses the widgets in their visual order, and the directory and file lists gained a horizontal scrollbar and type-ahead selection. The dialog is now transient and centered over its parent, and the SaveFileDialog overwrite confirmation uses a themed message box. Co-Authored-By: Claude Opus 4.8 --- Doc/library/dialog.rst | 22 +- Doc/whatsnew/3.16.rst | 8 + Lib/idlelib/run.py | 10 +- Lib/test/test_tkinter/test_filedialog.py | 100 +++++ Lib/tkinter/filedialog.py | 355 +++++++++++++----- ...6-06-21-23-17-12.gh-issue-59396.Fd9Tk2.rst | 14 + 6 files changed, 400 insertions(+), 109 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-21-23-17-12.gh-issue-59396.Fd9Tk2.rst diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst index a576cdcfaa2b1e9..06f2d6ddbf4f48b 100644 --- a/Doc/library/dialog.rst +++ b/Doc/library/dialog.rst @@ -217,9 +217,19 @@ These do not emulate the native look-and-feel of the platform. .. note:: The *FileDialog* class should be subclassed for custom event handling and behaviour. -.. class:: FileDialog(master, title=None) +.. class:: FileDialog(master, title=None, *, use_ttk=True) Create a basic file selection dialog. + Its layout -- a filter entry, side-by-side directory and file lists, and a + selection entry -- follows the classic Motif file selection dialog. + When *use_ttk* is true (the default), the dialog is built from the themed + :mod:`tkinter.ttk` widgets; when false, from the classic :mod:`tkinter` + widgets. + + .. versionchanged:: next + The dialog is now built from the themed :mod:`tkinter.ttk` widgets by + default, instead of the classic :mod:`tkinter` widgets. + Added the *use_ttk* parameter. .. method:: cancel_command(event=None) @@ -281,21 +291,27 @@ These do not emulate the native look-and-feel of the platform. Update the current file selection to *file*. -.. class:: LoadFileDialog(master, title=None) +.. class:: LoadFileDialog(master, title=None, *, use_ttk=True) A subclass of FileDialog that creates a dialog window for selecting an existing file. + .. versionchanged:: next + Added the *use_ttk* parameter. + .. method:: ok_command() Test that a file is provided and that the selection indicates an already existing file. -.. class:: SaveFileDialog(master, title=None) +.. class:: SaveFileDialog(master, title=None, *, use_ttk=True) A subclass of FileDialog that creates a dialog window for selecting a destination file. + .. versionchanged:: next + Added the *use_ttk* parameter. + .. method:: ok_command() Test whether or not the selection points to a valid file that is not a diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 1a73a79a58b78b1..8219700cc1e8385 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -383,6 +383,14 @@ tkinter ttk version, and accepts mappings of button options as *buttons* entries. (Contributed by Serhiy Storchaka in :gh:`59396`.) +* The :class:`!tkinter.filedialog.FileDialog` dialog and its + :class:`!tkinter.filedialog.LoadFileDialog` and + :class:`!tkinter.filedialog.SaveFileDialog` subclasses are now built from the + themed :mod:`tkinter.ttk` widgets by default instead of the classic + :mod:`tkinter` widgets, and gained a *use_ttk* parameter to select between + them. + (Contributed by Serhiy Storchaka in :gh:`59396`.) + xml --- diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index f5564ccf90f7f46..802f0248e4e4594 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -31,11 +31,17 @@ import tkinter # Use tcl and, if startup fails, messagebox. if not hasattr(sys.modules['idlelib.run'], 'firstrun'): # Undo modifications of tkinter by idlelib imports; see bpo-25507. + # Which of these submodules got imported (and thus added as a tkinter + # attribute) depends on what idlelib pulled in, so tolerate missing + # ones rather than assuming a fixed set; see gh-59396. for mod in ('simpledialog', 'messagebox', 'font', 'dialog', 'filedialog', 'commondialog', 'ttk'): - delattr(tkinter, mod) - del sys.modules['tkinter.' + mod] + try: + delattr(tkinter, mod) + del sys.modules['tkinter.' + mod] + except (AttributeError, KeyError): + pass # Avoid AttributeError if run again; see bpo-37038. sys.modules['idlelib.run'].firstrun = False diff --git a/Lib/test/test_tkinter/test_filedialog.py b/Lib/test/test_tkinter/test_filedialog.py index 758ef1479ef2cfa..b89862d3fcdcb2b 100644 --- a/Lib/test/test_tkinter/test_filedialog.py +++ b/Lib/test/test_tkinter/test_filedialog.py @@ -1,6 +1,8 @@ import os import unittest +import tkinter from tkinter import filedialog +from tkinter import ttk from tkinter.commondialog import Dialog from test.support import requires, swap_attr from test.test_tkinter.support import setUpModule # noqa: F401 @@ -101,6 +103,104 @@ def test_subclasses(self): self.assertIsInstance(d, filedialog.FileDialog) self.assertEqual(d.top.title(), cls.title) + # --- Themed widgets and keyboard (modernization) --- + + def open(self, **kw): + d = filedialog.FileDialog(self.root, **kw) + self.addCleanup(lambda: d.top.winfo_exists() and d.top.destroy()) + d.top.deiconify() # __init__ leaves the dialog withdrawn until go() + d.top.update() + return d + + def test_use_ttk(self): + # The dialog uses the themed (ttk) widgets by default. + d = self.open() + self.assertEqual(d.ok_button.winfo_class(), 'TButton') + self.assertEqual(d.selection.winfo_class(), 'TEntry') + + def test_use_classic(self): + # use_ttk=False uses the classic Tk widgets. + d = self.open(use_ttk=False) + self.assertEqual(d.ok_button.winfo_class(), 'Button') + self.assertEqual(d.selection.winfo_class(), 'Entry') + if d.top._windowingsystem == 'x11': + self.assertEqual(str(d.botframe.cget('relief')), 'raised') + + def test_background(self): + # The ttk dialog adopts the ttk background, even a customized one, while + # the classic dialog keeps the default Toplevel background. + style = ttk.Style(self.root) + old = style.lookup('.', 'background') + style.configure('.', background='#123456') + self.addCleanup(style.configure, '.', background=old) + d = self.open() + self.assertEqual(str(d.top.cget('background')), '#123456') + d = self.open(use_ttk=False) + ref = tkinter.Toplevel(self.root) + self.addCleanup(ref.destroy) + self.assertEqual(str(d.top.cget('background')), + str(ref.cget('background'))) + + def test_button_accelerator(self): + # The buttons' "&" accelerators are parsed. + d = self.open() + self.assertEqual(str(d.ok_button.cget('text')), 'OK') + self.assertEqual(int(d.ok_button.cget('underline')), 0) + + def test_default_ring(self): + # The default ring follows the keyboard focus among the buttons. + d = self.open() + self.assertEqual(str(d.cancel_button.cget('default')), 'normal') + d.cancel_button.focus_force() + d.top.update() + self.assertEqual(str(d.cancel_button.cget('default')), 'active') + d.ok_button.focus_force() + d.top.update() + self.assertEqual(str(d.cancel_button.cget('default')), 'normal') + + def test_alt_key(self): + # Alt + the underlined letter invokes the matching button. + d = self.open() + invoked = [] + d.cancel_button.configure(command=lambda: invoked.append(True)) + d.top.focus_force() + d.top.update() + d.top.event_generate('') # "&Cancel" + d.top.update() + self.assertTrue(invoked) + + def test_escape_cancels(self): + # The Escape key cancels the dialog. + d = self.open() + d.how = 'spam' + d.top.focus_force() + d.top.update() + d.top.event_generate('') + d.top.update() + self.assertIsNone(d.how) + + def test_horizontal_scrollbars(self): + # Each list has a horizontal scrollbar besides the vertical one. + d = self.open() + self.assertEqual(str(d.dirshbar.cget('orient')), 'horizontal') + self.assertEqual(str(d.fileshbar.cget('orient')), 'horizontal') + self.assertTrue(d.dirs.cget('xscrollcommand')) + self.assertTrue(d.files.cget('xscrollcommand')) + + def test_type_ahead(self): + # Typing characters over a list jumps to a matching entry. + d = self.open() + d.directory = os.getcwd() # browsing the match fills the selection entry + d.files.delete(0, 'end') + for name in ('alpha', 'bravo', 'charlie'): + d.files.insert('end', name) + d.files.focus_force() + d.top.update() + d.files.event_generate('', keysym='c') + d.top.update() + sel = d.files.curselection() + self.assertEqual([d.files.get(i) for i in sel], ['charlie']) + if __name__ == "__main__": unittest.main() diff --git a/Lib/tkinter/filedialog.py b/Lib/tkinter/filedialog.py index 23cb19249a92835..29020475a3cb538 100644 --- a/Lib/tkinter/filedialog.py +++ b/Lib/tkinter/filedialog.py @@ -18,13 +18,16 @@ import fnmatch import os +import tkinter from tkinter import ( - Frame, LEFT, YES, BOTTOM, Entry, TOP, Button, Tk, X, - Toplevel, RIGHT, Y, END, Listbox, BOTH, Scrollbar, + ACTIVE, CENTER, EW, NORMAL, NS, NSEW, RAISED, W, YES, BOTTOM, TOP, Tk, X, + Toplevel, END, Listbox, BOTH, ) -from tkinter.dialog import Dialog +from tkinter import ttk +from tkinter import messagebox from tkinter import commondialog -from tkinter.simpledialog import _setup_dialog +from tkinter.simpledialog import (_setup_dialog, _place_window, _temp_grab_focus, + _underline_ampersand, _find_alt_key_target) dialogstates = {} @@ -34,6 +37,8 @@ class FileDialog: """Standard file selection dialog -- no checks on selected file. + The layout and behavior follow the classic Motif file selection dialog. + Usage: d = FileDialog(master) @@ -55,69 +60,145 @@ class FileDialog: title = "File Selection Dialog" - def __init__(self, master, title=None): + def _widget(self, klass, master, **kw): + # Create a themed (ttk) or classic (tkinter) widget. ttk has no + # Listbox, so the directory and file lists stay classic. + return getattr(ttk if self.use_ttk else tkinter, klass)(master, **kw) + + def _frame(self, master): + # A structural frame. The classic file dialog gives its frames a + # raised border on X11; the themed one does not (cf. tk_dialog). + frame = self._widget('Frame', master) + if not self.use_ttk and self.top._windowingsystem == 'x11': + frame.configure(relief=RAISED, bd=1) + return frame + + def _make_list(self, column, label, browse, activate): + # Create a labelled listbox with vertical and horizontal scrollbars in + # the middle frame, like the Motif file dialog (cf. xmfbox.tcl + # MotifFDialog_MakeSList). + frame = self._widget('Frame', self.midframe) + frame.grid(row=0, column=column, sticky=NSEW, padx='3p', pady='3p') + frame.grid_rowconfigure(1, weight=1) + frame.grid_columnconfigure(0, weight=1) + vbar = self._widget('Scrollbar', frame, takefocus=0) + hbar = self._widget('Scrollbar', frame, orient='horizontal', takefocus=0) + listbox = Listbox(frame, exportselection=0, + xscrollcommand=(hbar, 'set'), + yscrollcommand=(vbar, 'set')) + vbar.configure(command=(listbox, 'yview')) + hbar.configure(command=(listbox, 'xview')) + self._label(frame, label, listbox).grid( + row=0, column=0, columnspan=2, sticky=EW, padx='1.5p', pady='1.5p') + listbox.grid(row=1, column=0, sticky=NSEW) + vbar.grid(row=1, column=1, sticky=NS) + hbar.grid(row=2, column=0, sticky=EW) + # Instance bindings fire after the Listbox class bindings, which have + # already updated the selection. + btags = listbox.bindtags() + listbox.bindtags(btags[1:] + btags[:1]) + listbox.bind('<>', browse) + listbox.bind('', activate) + listbox.bind('', lambda e: (browse(e), activate(e))) + # Type a few characters to jump to a matching entry, like the Motif + # file dialog (cf. xmfbox.tcl ListBoxKeyAccel). + listbox.bind('', self._listbox_keyaccel) + return listbox, vbar, hbar + + def __init__(self, master, title=None, *, use_ttk=True): if title is None: title = self.title self.master = master + self.use_ttk = use_ttk self.directory = None + self._keyaccel = {} # listbox -> recently typed prefix + self._keyaccel_after = {} # listbox -> pending reset callback id self.top = Toplevel(master) + self.top.withdraw() # remain invisible until placed by go() self.top.title(title) self.top.iconname(title) + # Keep the dialog above its parent, like SimpleDialog and Dialog (cf. + # xmfbox.tcl). Skip it when the master is not viewable, or the dialog + # would itself be opened withdrawn. + if master.winfo_viewable(): + self.top.transient(master) _setup_dialog(self.top) - - self.botframe = Frame(self.top) - self.botframe.pack(side=BOTTOM, fill=X) - - self.selection = Entry(self.top) - self.selection.pack(side=BOTTOM, fill=X) - self.selection.bind('', self.ok_event) - - self.filter = Entry(self.top) - self.filter.pack(side=TOP, fill=X) + if self.use_ttk: + # Use a single themed background for the whole dialog so it blends + # with the ttk widgets (cf. tk::MessageBox). + self.top.configure( + background=ttk.Style(self.top).lookup('.', 'background')) + + # Tk traverses focus in widget-creation order, so the widgets are + # created top to bottom -- filter, lists, selection, buttons -- to make + # Tab follow the visual layout, like the Motif file dialog (cf. + # xmfbox.tcl). + self.filter = self._widget('Entry', self.top) self.filter.bind('', self.filter_command) - - self.midframe = Frame(self.top) - self.midframe.pack(expand=YES, fill=BOTH) - - self.filesbar = Scrollbar(self.midframe) - self.filesbar.pack(side=RIGHT, fill=Y) - self.files = Listbox(self.midframe, exportselection=0, - yscrollcommand=(self.filesbar, 'set')) - self.files.pack(side=RIGHT, expand=YES, fill=BOTH) - btags = self.files.bindtags() - self.files.bindtags(btags[1:] + btags[:1]) - self.files.bind('', self.files_select_event) - self.files.bind('', self.files_double_event) - self.filesbar.config(command=(self.files, 'yview')) - - self.dirsbar = Scrollbar(self.midframe) - self.dirsbar.pack(side=LEFT, fill=Y) - self.dirs = Listbox(self.midframe, exportselection=0, - yscrollcommand=(self.dirsbar, 'set')) - self.dirs.pack(side=LEFT, expand=YES, fill=BOTH) - self.dirsbar.config(command=(self.dirs, 'yview')) - btags = self.dirs.bindtags() - self.dirs.bindtags(btags[1:] + btags[:1]) - self.dirs.bind('', self.dirs_select_event) - self.dirs.bind('', self.dirs_double_event) - - self.ok_button = Button(self.botframe, - text="OK", - command=self.ok_command) - self.ok_button.pack(side=LEFT) - self.filter_button = Button(self.botframe, - text="Filter", - command=self.filter_command) - self.filter_button.pack(side=LEFT, expand=YES) - self.cancel_button = Button(self.botframe, - text="Cancel", - command=self.cancel_command) - self.cancel_button.pack(side=RIGHT) + self.filter_label = self._label(self.top, 'Fil&ter:', self.filter) + self.filter_label.pack(side=TOP, fill=X, padx='4.5p', pady='3p') + self.filter.pack(side=TOP, fill=X, padx='3p') + + self.midframe = self._frame(self.top) + self.midframe.pack(side=TOP, expand=YES, fill=BOTH) + + # Directory list (left) and file list (right), each with a label and + # vertical and horizontal scrollbars, like the Motif file dialog (cf. + # xmfbox.tcl). + self.dirs, self.dirsbar, self.dirshbar = self._make_list( + 0, '&Directory:', self.dirs_select_event, self.dirs_double_event) + self.files, self.filesbar, self.fileshbar = self._make_list( + 1, 'Fi&les:', self.files_select_event, self.files_double_event) + + # Give the file list twice the width of the directory list, like the + # Motif file dialog (cf. xmfbox.tcl). + self.midframe.grid_rowconfigure(0, weight=1) + self.midframe.grid_columnconfigure(0, weight=1) + self.midframe.grid_columnconfigure(1, minsize=150, weight=2) + + self.selection = self._widget('Entry', self.top) + self.selection.bind('', self.ok_event) + self.selection_label = self._label(self.top, '&Selection:', self.selection) + self.selection.pack(side=BOTTOM, fill=X, padx='3p', pady='3p') + self.selection_label.pack(side=BOTTOM, fill=X, padx='4.5p') + + # Created last so the buttons traverse last, but packed below the + # selection field. + self.botframe = self._frame(self.top) + self.botframe.pack(side=BOTTOM, fill=X, before=self.selection) + + # tk::MessageBox and tk_dialog space the buttons differently. + padx, pady = ('3m', '2m') if self.use_ttk else ('7.5p', '3p') + for i, (name, label, command) in enumerate(( + ('ok', '&OK', self.ok_command), + ('filter', '&Filter', self.filter_command), + ('cancel', '&Cancel', self.cancel_command))): + # Create a button with an accelerator key marked by "&" in the text, + # like SimpleDialog and Dialog (cf. tk::AmpWidget). + text, underline = _underline_ampersand(label) + button = self._widget('Button', self.botframe, name=name, text=text, + underline=underline, command=command, + default=ACTIVE if name == 'ok' else NORMAL) + button.bind('<>', lambda e: e.widget.invoke()) + button.grid(column=i, row=0, sticky=EW, padx=padx, pady=pady) + # tk::MessageBox makes the buttons equal width; tk_dialog does not. + self.botframe.grid_columnconfigure( + i, uniform='buttons' if self.use_ttk else '') + if self.top._windowingsystem == 'aqua': + self.botframe.grid_columnconfigure(i, minsize=90) + button.grid_configure(pady=7) + setattr(self, name + '_button', button) + self.botframe.grid_anchor(CENTER) self.top.protocol('WM_DELETE_WINDOW', self.cancel_command) - # XXX Are the following okay for a general audience? - self.top.bind('', self.cancel_command) - self.top.bind('', self.cancel_command) + # Alt + an underlined character invokes the matching button (cf. + # ::tk::AltKeyInDialog), like SimpleDialog and Dialog. + self.top.bind('', self._alt_key) + # The default ring follows the keyboard focus among the buttons (cf. + # tk::MessageBox), like SimpleDialog and Dialog. + self.top.bind('', lambda e: self._set_default(e.widget, ACTIVE)) + self.top.bind('', lambda e: self._set_default(e.widget, NORMAL)) + self.top.bind('', self.cancel_command) def go(self, dir_or_file=os.curdir, pattern="*", default="", key=None): if key and key in dialogstates: @@ -131,11 +212,17 @@ def go(self, dir_or_file=os.curdir, pattern="*", default="", key=None): self.set_filter(self.directory, pattern) self.set_selection(default) self.filter_command() - self.selection.focus_set() + # Center the dialog over its parent and make it visible, like + # SimpleDialog and Dialog (cf. xmfbox.tcl). + _place_window(self.top, self.master) + self.selection.select_range(0, END) # so the user can type a new name self.top.wait_visibility() # window needs to be visible for the grab - self.top.grab_set() self.how = None - self.master.mainloop() # Exited by self.quit(how) + # Grab the input and restore the previous focus and grab afterwards, + # like SimpleDialog and Dialog. go() destroys the window itself below, + # so leave it in place here. + with _temp_grab_focus(self.top, self.selection, destroy=False): + self.master.mainloop() # Exited by self.quit(how) if key: directory, pattern = self.get_filter() if self.how: @@ -148,21 +235,91 @@ def quit(self, how=None): self.how = how self.master.quit() # Exit mainloop() + def _alt_key(self, event): + # Invoke the button whose accelerator matches the Alt key (cf. + # SimpleDialog and Dialog). + target = _find_alt_key_target(self.top, event.char) + if target is not None: + target.event_generate('<>') + + def _set_default(self, widget, state): + # Set a button's default ring. + if widget.winfo_class() in ('Button', 'TButton'): + widget.configure(default=state) + + def _label(self, master, label, target): + # Create a field label whose "&" accelerator focuses the target widget, + # like the labels of the Motif file dialog (cf. xmfbox.tcl). + text, underline = _underline_ampersand(label) + widget = self._widget('Label', master, text=text, underline=underline, + anchor=W) + widget.bind('<>', lambda e: target.focus_set()) + return widget + + def _listbox_keyaccel(self, event): + # Append the typed character and jump to a matching entry, resetting + # after a short pause (cf. xmfbox.tcl ListBoxKeyAccel_Key). + char = event.char + if not char or not char.isprintable(): + return + listbox = event.widget + prefix = self._keyaccel.get(listbox, '') + char + self._keyaccel[listbox] = prefix + self._listbox_keyaccel_goto(listbox, prefix) + after_id = self._keyaccel_after.get(listbox) + if after_id is not None: + listbox.after_cancel(after_id) + self._keyaccel_after[listbox] = listbox.after( + 500, lambda: self._keyaccel.pop(listbox, None)) + + def _listbox_keyaccel_goto(self, listbox, prefix): + # Select the first entry not preceding the typed prefix (cf. xmfbox.tcl + # ListBoxKeyAccel_Goto). + prefix = prefix.lower() + index = -1 + for i in range(listbox.size()): + item = listbox.get(i).lower() + if prefix >= item: + index = i + if prefix <= item: + index = i + break + if index >= 0: + listbox.selection_clear(0, END) + listbox.selection_set(index) + listbox.activate(index) + listbox.see(index) + listbox.event_generate('<>') + def dirs_double_event(self, event): self.filter_command() + # Highlight an entry so the directory list stays keyboard-navigable + # after entering a directory, like the Motif file dialog (cf. + # xmfbox.tcl); prefer the first subdirectory over the ".." entry. + index = 1 if self.dirs.size() > 1 else 0 + self.dirs.selection_set(index) + self.dirs.activate(index) def dirs_select_event(self, event): + # Show a selection in only one list at a time (cf. xmfbox.tcl). + self.files.selection_clear(0, END) dir, pat = self.get_filter() subdir = self.dirs.get('active') dir = os.path.normpath(os.path.join(self.directory, subdir)) self.set_filter(dir, pat) + # Show the end of a long path, like the Motif file dialog (cf. + # xmfbox.tcl). + self.filter.xview(END) def files_double_event(self, event): self.ok_command() def files_select_event(self, event): + # Show a selection in only one list at a time (cf. xmfbox.tcl). + self.dirs.selection_clear(0, END) file = self.files.get('active') self.set_selection(file) + self.selection.xview(END) def ok_event(self, event): self.ok_command() @@ -256,13 +413,10 @@ def ok_command(self): if os.path.isdir(file): self.master.bell() return - d = Dialog(self.top, - title="Overwrite Existing File Question", - text="Overwrite existing file %r?" % (file,), - bitmap='questhead', - default=1, - strings=("Yes", "Cancel")) - if d.num != 0: + if not messagebox.askyesno( + "Overwrite Existing File", + "Overwrite existing file %r?" % (file,), + icon=messagebox.WARNING, parent=self.top): return else: head, tail = os.path.split(file) @@ -446,44 +600,37 @@ def askdirectory (**options): def test(): """Simple test program.""" root = Tk() - root.withdraw() - fd = LoadFileDialog(root) - loadfile = fd.go(key="test") - fd = SaveFileDialog(root) - savefile = fd.go(key="test") - print(loadfile, savefile) - - # Since the file name may contain non-ASCII characters, we need - # to find an encoding that likely supports the file name, and - # displays correctly on the terminal. - - # Start off with UTF-8 - enc = "utf-8" - - # See whether CODESET is defined - try: - import locale - locale.setlocale(locale.LC_ALL,'') - enc = locale.nl_langinfo(locale.CODESET) - except (ImportError, AttributeError): - pass - - # dialog for opening files - - openfilename=askopenfilename(filetypes=[("all files", "*")]) - try: - fp=open(openfilename,"r") - fp.close() - except BaseException as exc: - print("Could not open File: ") - print(exc) - - print("open", openfilename.encode(enc)) - - # dialog for saving files - - saveasfilename=asksaveasfilename() - print("saveas", saveasfilename.encode(enc)) + use_ttk = tkinter.BooleanVar(root, value=True) + + def test_load(): + print('load:', LoadFileDialog(root, use_ttk=use_ttk.get()).go(key='test')) + + def test_save(): + print('save:', SaveFileDialog(root, use_ttk=use_ttk.get()).go(key='test')) + + def test_open(): + print('open:', askopenfilename(filetypes=[('all files', '*')])) + + def test_saveas(): + print('saveas:', asksaveasfilename()) + + def test_directory(): + print('directory:', askdirectory()) + + def test_directory_mustexist(): + print('directory (mustexist):', askdirectory(mustexist=True)) + + tkinter.Checkbutton(root, text='Use themed (ttk) widgets', + variable=use_ttk).pack(fill=X) + tkinter.Button(root, text='LoadFileDialog', command=test_load).pack(fill=X) + tkinter.Button(root, text='SaveFileDialog', command=test_save).pack(fill=X) + tkinter.Button(root, text='askopenfilename', command=test_open).pack(fill=X) + tkinter.Button(root, text='asksaveasfilename', command=test_saveas).pack(fill=X) + tkinter.Button(root, text='askdirectory', command=test_directory).pack(fill=X) + tkinter.Button(root, text='askdirectory (mustexist)', + command=test_directory_mustexist).pack(fill=X) + tkinter.Button(root, text='Quit', command=root.quit).pack(fill=X) + root.mainloop() if __name__ == '__main__': diff --git a/Misc/NEWS.d/next/Library/2026-06-21-23-17-12.gh-issue-59396.Fd9Tk2.rst b/Misc/NEWS.d/next/Library/2026-06-21-23-17-12.gh-issue-59396.Fd9Tk2.rst new file mode 100644 index 000000000000000..890a29cb7adf95d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-21-23-17-12.gh-issue-59396.Fd9Tk2.rst @@ -0,0 +1,14 @@ +The :class:`!tkinter.filedialog.FileDialog` dialog and its +:class:`!tkinter.filedialog.LoadFileDialog` and +:class:`!tkinter.filedialog.SaveFileDialog` subclasses, which follow the layout +of the classic Motif file selection dialog, were modernized to match its look +and feel more closely. +They are now built from the themed :mod:`tkinter.ttk` widgets instead of the +classic :mod:`tkinter` widgets, and gained a *use_ttk* parameter that selects +between the classic Tk widgets and the themed ttk widgets. +The buttons and field labels gained :kbd:`Alt` key accelerators, the default +ring follows the keyboard focus, and the :kbd:`Escape` key cancels the dialog. +The directory and file lists gained a horizontal scrollbar and type-ahead +selection. +The dialog is now centered over its parent, and the overwrite confirmation of +:class:`!SaveFileDialog` uses a themed message box. From 51f177244d8ca8ca36fb29f294720e5601769474 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 15:49:43 +0300 Subject: [PATCH 27/61] gh-43699: Defer the drag cursor in tkinter.dnd until the pointer moves (GH-152371) The drag cursor is now changed only once the pointer starts moving past a small threshold rather than on the initial button press, so that a plain click no longer flashes it. Co-authored-by: Claude Opus 4.8 --- Lib/test/test_tkinter/test_dnd.py | 14 +++++++++++--- Lib/tkinter/dnd.py | 18 +++++++++++++++++- ...26-06-27-12-00-00.gh-issue-43699.Zt46MI.rst | 3 +++ 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-27-12-00-00.gh-issue-43699.Zt46MI.rst diff --git a/Lib/test/test_tkinter/test_dnd.py b/Lib/test/test_tkinter/test_dnd.py index fe3685aefe48be9..79c868b68562bce 100644 --- a/Lib/test/test_tkinter/test_dnd.py +++ b/Lib/test/test_tkinter/test_dnd.py @@ -40,10 +40,12 @@ def dnd_end(self, target, event): class FakeEvent: - def __init__(self, widget, num=1): + def __init__(self, widget, num=1, x_root=0, y_root=0): self.num = num self.widget = widget - self.x = self.y = self.x_root = self.y_root = 0 + self.x = self.y = 0 + self.x_root = x_root + self.y_root = y_root class DndTest(AbstractTkTest, unittest.TestCase): @@ -111,10 +113,16 @@ def test_restart_after_finish(self): handler.cancel() def test_drag_cursor(self): + # The drag cursor is not shown on the initial press, only once the + # pointer moves past the threshold, so a plain click does not flash + # it (gh-43699). The original cursor is restored afterwards. self.canvas['cursor'] = 'watch' handler = dnd.dnd_start(self.source, FakeEvent(self.canvas)) - # The drag cursor is shown while dragging, the original restored after. self.assertEqual(handler.save_cursor, 'watch') + self.assertEqual(str(self.canvas['cursor']), 'watch') + handler.on_motion(FakeEvent(self.canvas, x_root=2)) # below threshold + self.assertEqual(str(self.canvas['cursor']), 'watch') + handler.on_motion(FakeEvent(self.canvas, x_root=20)) # past threshold self.assertEqual(str(self.canvas['cursor']), 'hand2') handler.cancel() self.assertEqual(str(self.canvas['cursor']), 'watch') diff --git a/Lib/tkinter/dnd.py b/Lib/tkinter/dnd.py index acec61ba71f1c9f..3a306705c9b1063 100644 --- a/Lib/tkinter/dnd.py +++ b/Lib/tkinter/dnd.py @@ -120,6 +120,10 @@ class DndHandler: root = None + # The drag cursor is shown only once the pointer has moved this many + # pixels from the initial press, so that a plain click does not flash it. + threshold = 3 + def __init__(self, source, event): if event.num > 5: return @@ -134,11 +138,12 @@ def __init__(self, source, event): self.target = None self.initial_button = button = event.num self.initial_widget = widget = event.widget + self.dragging = False + self.x_origin, self.y_origin = event.x_root, event.y_root self.release_pattern = "" % (button, button) self.save_cursor = widget['cursor'] or "" widget.bind(self.release_pattern, self.on_release) widget.bind("", self.on_motion) - widget['cursor'] = "hand2" def __del__(self): root = self.root @@ -175,6 +180,17 @@ def on_motion(self, event): if new_target is not None: new_target.dnd_enter(source, event) self.target = new_target + self.update_cursor(x, y) + + def update_cursor(self, x, y): + # Show the drag cursor only once the pointer has actually started + # moving past the threshold, so that a plain click does not flash it. + if not self.dragging: + if (abs(x - self.x_origin) <= self.threshold and + abs(y - self.y_origin) <= self.threshold): + return + self.dragging = True + self.initial_widget['cursor'] = "hand2" def on_release(self, event): self.finish(event, 1) diff --git a/Misc/NEWS.d/next/Library/2026-06-27-12-00-00.gh-issue-43699.Zt46MI.rst b/Misc/NEWS.d/next/Library/2026-06-27-12-00-00.gh-issue-43699.Zt46MI.rst new file mode 100644 index 000000000000000..93a9864d2445e94 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-27-12-00-00.gh-issue-43699.Zt46MI.rst @@ -0,0 +1,3 @@ +The drag cursor in :mod:`tkinter.dnd` is now changed only once the pointer +starts moving rather than on the initial button press, so that a plain +click no longer flashes it. From 7d8d1a45618d3f99d6d63769ef694329c4619c64 Mon Sep 17 00:00:00 2001 From: Savage Mechanic Date: Sun, 5 Jul 2026 14:16:54 +0100 Subject: [PATCH 28/61] gh-149930: Clarify imaplib response helper types (GH-149963) Co-authored-by: savagemechanic <20458938+savagemechanic@users.noreply.github.com> --- Doc/library/imaplib.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index dbf4560ab5e53b3..c58c957d03c1d84 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -127,11 +127,11 @@ The second subclass allows for connections created by a child process: The following utility functions are defined: -.. function:: Internaldate2tuple(datestr) +.. function:: Internaldate2tuple(resp) - Parse an IMAP4 ``INTERNALDATE`` string and return corresponding local - time. The return value is a :class:`time.struct_time` tuple or - ``None`` if the string has wrong format. + Parse a :term:`bytes-like object` containing an IMAP4 ``INTERNALDATE`` + response and return the corresponding local time. The return value is a + :class:`time.struct_time` tuple or ``None`` if the input has wrong format. .. function:: Int2AP(num) @@ -139,9 +139,11 @@ The following utility functions are defined: [``A`` .. ``P``]. -.. function:: ParseFlags(flagstr) +.. function:: ParseFlags(resp) - Converts an IMAP4 ``FLAGS`` response to a tuple of individual flags. + Converts a :term:`bytes-like object` containing an IMAP4 ``FLAGS`` response + to a tuple of individual flags as :class:`bytes`. The return value is an + empty tuple if the input has wrong format. .. function:: Time2Internaldate(date_time) From 06e9057ef3aae53787b2169176d28bc253265aa2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 17:08:58 +0300 Subject: [PATCH 29/61] gh-68147: Fix RFC references in imaplib (GH-153126) Refer to RFC 3501, which obsoleted RFC 2060. "]" is disallowed in flags, not in tags. Co-authored-by: Claude Fable 5 --- Doc/library/imaplib.rst | 10 +++++----- Lib/imaplib.py | 6 +++--- Lib/test/test_imaplib.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index c58c957d03c1d84..3f46c5146acc6ee 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -16,7 +16,7 @@ This module defines three classes, :class:`IMAP4`, :class:`IMAP4_SSL` and :class:`IMAP4_stream`, which encapsulate a connection to an IMAP4 server and implement a large subset of the IMAP4rev1 client protocol as defined in -:rfc:`2060`. It is backward compatible with IMAP4 (:rfc:`1730`) servers, but +:rfc:`3501`. It is backward compatible with IMAP4 (:rfc:`1730`) servers, but note that the ``STATUS`` command is not supported in IMAP4. .. include:: ../includes/wasm-notavail.rst @@ -632,7 +632,7 @@ An :class:`IMAP4` instance has the following methods: .. method:: IMAP4.store(message_set, command, flag_list) Alters flag dispositions for messages in mailbox. *command* is specified by - section 6.4.6 of :rfc:`2060` as being one of "FLAGS", "+FLAGS", or "-FLAGS", + section 6.4.6 of :rfc:`3501` as being one of "FLAGS", "+FLAGS", or "-FLAGS", optionally with a suffix of ".SILENT". For example, to set the delete flag on all messages:: @@ -646,11 +646,11 @@ An :class:`IMAP4` instance has the following methods: Creating flags containing ']' (for example: "[test]") violates :rfc:`3501` (the IMAP protocol). However, imaplib has historically - allowed creation of such tags, and popular IMAP servers, such as Gmail, + allowed creation of such flags, and popular IMAP servers, such as Gmail, accept and produce such flags. There are non-Python programs which also - create such tags. Although it is an RFC violation and IMAP clients and + create such flags. Although it is an RFC violation and IMAP clients and servers are supposed to be strict, imaplib still continues to allow - such tags to be created for backward compatibility reasons, and as of + such flags to be created for backward compatibility reasons, and as of Python 3.6, handles them if they are sent from the server, since this improves real-world compatibility. diff --git a/Lib/imaplib.py b/Lib/imaplib.py index a871e509b0d82c6..085c8d9a5f224ca 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -1,6 +1,6 @@ """IMAP4 client. -Based on RFC 2060. +Based on RFC 3501. Public class: IMAP4 Public variable: Debug @@ -43,8 +43,8 @@ AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first # Maximal line length when calling readline(). This is to prevent -# reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1) -# don't specify a line length. RFC 2683 suggests limiting client +# reading arbitrary length lines. RFC 3501 (IMAP 4rev1) +# doesn't specify a line length. RFC 2683 suggests limiting client # command lines to 1000 octets and that servers should be prepared # to accept command lines up to 8000 octets, so we used to use 10K here. # In the modern world (eg: gmail) the response to, for example, a diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index cdc2f9c8d852322..b186dca27aaac01 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1895,8 +1895,8 @@ def test_connect(self): @threading_helper.reap_threads def test_bracket_flags(self): - # This violates RFC 3501, which disallows ']' characters in tag names, - # but imaplib has allowed producing such tags forever, other programs + # This violates RFC 3501, which disallows ']' characters in flags, + # but imaplib has allowed producing such flags forever, other programs # also produce them (eg: OtherInbox's Organizer app as of 20140716), # and Gmail, for example, accepts them and produces them. So we # support them. See issue #21815. From 5cd58702abacb68118037e11b16a1d0d314807be Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 18:25:36 +0300 Subject: [PATCH 30/61] gh-143921: Narrow the control character check in imaplib commands (GH-153067) Only NUL, CR and LF are rejected now. Other control characters are valid in quoted strings and can occur in mailbox names returned by the server, so they are now accepted and sent quoted. Co-authored-by: Claude Fable 5 --- Lib/imaplib.py | 6 ++++-- Lib/test/test_imaplib.py | 16 +++++++++++++--- ...026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst | 4 ++++ 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 085c8d9a5f224ca..8e271209a664faa 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -129,7 +129,9 @@ # We compile these in _mode_xxx. _Literal = br'.*{(?P\d+)}$' _Untagged_status = br'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?' -_control_chars = re.compile(b'[\x00-\x1F\x7F]') +# Only NUL, CR and LF are unsafe (they cannot be represented even in +# a quoted string); other control characters are sent quoted. +_control_chars = re.compile(b'[\x00\r\n]') _non_astring_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff%*\\"]') _non_list_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff\\"]') _quoted = re.compile(br'"(?:[^"\\]|\\.)*+"') @@ -1170,7 +1172,7 @@ def _command(self, name, *args): if isinstance(arg, str): arg = bytes(arg, self._encoding) if _control_chars.search(arg): - raise ValueError("Control characters not allowed in commands") + raise ValueError("NUL, CR and LF not allowed in commands") data = data + b' ' + arg literal = self.literal diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index b186dca27aaac01..ef283267ff08ef0 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1751,10 +1751,20 @@ def test_uppercase_command_names(self): client.NONEXISTENT def test_control_characters(self): - client, _ = self._setup(SimpleIMAPHandler) - for c0 in support.control_characters_c0(): + client, server = self._setup(SimpleIMAPHandler) + client.login('user', 'pass') + for c in '\0\r\n': with self.assertRaises(ValueError): - client.login(f'user{c0}', 'pass') + client.select(f'a{c}b') + # Other control characters are valid in a quoted string and can + # occur in mailbox names returned by the server, so the client + # must be able to send them back. + for c in support.control_characters_c0(): + if c in '\0\r\n': + continue + typ, _ = client.select(f'a{c}b') + self.assertEqual(typ, 'OK') + self.assertEqual(server.is_selected, [f'"a{c}b"']) # property tests diff --git a/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst b/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst new file mode 100644 index 000000000000000..04e8bd6d6f9d6cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-10-24-30.gh-issue-143921.wQx3Tn.rst @@ -0,0 +1,4 @@ +Narrow the control character check in :mod:`imaplib` commands: only NUL, CR +and LF are now rejected. Other control characters are valid in quoted +strings and can occur in mailbox names returned by the server, so they are +now accepted and sent quoted. From fd7d48d9f22cdf48bf378bb9d2be9160b52a19bc Mon Sep 17 00:00:00 2001 From: Andrew James Date: Mon, 6 Jul 2026 01:57:09 +1000 Subject: [PATCH 31/61] gh-60055: Allow passing a Request instance for RobotParser URLs (#103753) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow passing a Request instance for the url parameter * 📜🤖 Added by blurb_it. * gh-60055: rebase onto main and document Request support * Fix the lint warnings and CI Errors. * Addressing RobotFileParser review comments. * Update Doc/library/urllib.robotparser.rst Co-authored-by: Serhiy Storchaka * Address additional Review Comments. * Changed versionchanged to next. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Senthil Kumaran Co-authored-by: Serhiy Storchaka --- Doc/library/urllib.robotparser.rst | 25 +++++++++++++-- Lib/test/test_robotparser.py | 31 +++++++++++++++++++ Lib/urllib/robotparser.py | 7 ++++- ...3-04-24-11-12-00.gh-issue-60055.UjP6aX.rst | 1 + 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-04-24-11-12-00.gh-issue-60055.UjP6aX.rst diff --git a/Doc/library/urllib.robotparser.rst b/Doc/library/urllib.robotparser.rst index 1fa7fc13baa539a..3e84f86d4dd383a 100644 --- a/Doc/library/urllib.robotparser.rst +++ b/Doc/library/urllib.robotparser.rst @@ -24,11 +24,18 @@ structure of :file:`robots.txt` files, see :rfc:`9309`. .. class:: RobotFileParser(url='') This class provides methods to read, parse and answer questions about the - :file:`robots.txt` file at *url*. + :file:`robots.txt` file at *url* or a :class:`urllib.request.Request` object. + + .. versionchanged:: next + *url* parameter can be a :class:`urllib.request.Request` object. .. method:: set_url(url) - Sets the URL referring to a :file:`robots.txt` file. + Sets the URL referring to a :file:`robots.txt` file or a + :class:`urllib.request.Request` object. + + .. versionchanged:: next + *url* parameter can be a :class:`urllib.request.Request` object. .. method:: read() @@ -102,3 +109,17 @@ class:: True >>> rp.can_fetch("*", "http://www.pythontest.net/no-robots-here/") False + + +The following example demonstrates use of a :class:`urllib.request.Request` +object with additional user-agent headers populated:: + + >>> import urllib.robotparser + >>> import urllib.request + >>> rp = urllib.robotparser.RobotFileParser() + >>> rp.set_url(urllib.request.Request("http://www.pythontest.net/robots.txt", headers={"User-Agent": "IsraBot"})) + >>> rp.read() + >>> rp.can_fetch("*", "http://www.pythontest.net/") + True + >>> rp.can_fetch("*", "http://www.pythontest.net/no-robots-here/") + False diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py index cd1477037e94b74..725c6e3b09e1d04 100644 --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -773,6 +773,37 @@ def testServiceUnavailable(self): self.assertFalse(parser.can_fetch("*", url + '/path/file.html')) +class UserAgentSiteTestCase(BaseLocalNetworkTestCase, unittest.TestCase): + + class RobotHandler(BaseHTTPRequestHandler): + def do_GET(self): + if self.headers.get('User-Agent').startswith('Python-urllib'): + self.send_error(403, "Forbidden access") + else: + self.send_response(200) + self.end_headers() + self.wfile.write(b"User-agent: *\nDisallow:") + + def log_message(self, format, *args): + pass + + def testUserAgentFilteringSite(self): + addr = self.server.server_address + url = f'http://{socket_helper.HOST}:{addr[1]}' + robots_url = url + "/robots.txt" + file_url = url + "/document" + parser = urllib.robotparser.RobotFileParser() + parser.set_url(robots_url) + parser.read() + self.assertTrue(parser.disallow_all) + self.assertFalse(parser.can_fetch("*", file_url)) + parser = urllib.robotparser.RobotFileParser() + parser.set_url(urllib.request.Request(robots_url, headers={'User-Agent': 'cybermapper'})) + parser.read() + self.assertFalse(parser.disallow_all) + self.assertTrue(parser.can_fetch("*", file_url)) + + @support.requires_working_socket() class NetworkTestCase(unittest.TestCase): diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py index 0c3e5d928909358..61772d90e2d53bf 100644 --- a/Lib/urllib/robotparser.py +++ b/Lib/urllib/robotparser.py @@ -55,8 +55,13 @@ def modified(self): self.last_checked = time.time() def set_url(self, url): - """Sets the URL referring to a robots.txt file.""" + """Sets the URL referring to a robots.txt file. + can be a string or a Request object. + """ self.url = url + + if isinstance(url, urllib.request.Request): + url = url.full_url self.host, self.path = urllib.parse.urlsplit(url)[1:3] def read(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-24-11-12-00.gh-issue-60055.UjP6aX.rst b/Misc/NEWS.d/next/Library/2023-04-24-11-12-00.gh-issue-60055.UjP6aX.rst new file mode 100644 index 000000000000000..58fface7caded53 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-24-11-12-00.gh-issue-60055.UjP6aX.rst @@ -0,0 +1 @@ +Let ``urllib.robotparser.RobotFileParser`` accept a ``urllib.request.Request`` object as well as a url string when setting a robots.txt url. From d6b9cb348037a3e63ba74cba4615bf0aeb4015b4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 20:02:45 +0300 Subject: [PATCH 32/61] gh-77508: Add imaplib.IMAP4.move method (GH-153121) Add a wrapper for the IMAP MOVE command (RFC 6851), analogous to copy(). The arguments of MOVE and UID MOVE are quoted when necessary. Co-authored-by: Claude Opus 4.8 (1M context) --- Doc/library/imaplib.rst | 9 ++++++ Doc/whatsnew/3.16.rst | 8 +++++ Lib/imaplib.py | 10 ++++++- Lib/test/test_imaplib.py | 29 +++++++++++++++++++ ...6-07-01-15-30-00.gh-issue-77508.Bn2kXt.rst | 2 ++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-01-15-30-00.gh-issue-77508.Bn2kXt.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 3f46c5146acc6ee..6b7c02f54e90af2 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -452,6 +452,15 @@ An :class:`IMAP4` instance has the following methods: Returned data are tuples of message part envelope and data. +.. method:: IMAP4.move(message_set, new_mailbox) + + Move *message_set* messages onto end of *new_mailbox*. + + The server must support the ``MOVE`` capability (:rfc:`6851`). + + .. versionadded:: next + + .. method:: IMAP4.myrights(mailbox) Show my ACLs for a mailbox (i.e. the rights that I have on mailbox). diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 8219700cc1e8385..cf105a26d98d45d 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -228,6 +228,14 @@ io (Contributed by Marcel Martin in :gh:`90533`.) +imaplib +------- + +* Add the :meth:`~imaplib.IMAP4.move` method, + a wrapper for the ``MOVE`` command (:rfc:`6851`). + (Contributed by Serhiy Storchaka in :gh:`77508`.) + + logging ------- diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 8e271209a664faa..adfd8afb9c053bb 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -789,6 +789,14 @@ def lsub(self, directory='', pattern='*'): self._list_mailbox(pattern)) return self._untagged_response(typ, dat, name) + def move(self, message_set, new_mailbox): + """Move 'message_set' messages onto end of 'new_mailbox'. + + (typ, [data]) = .move(message_set, new_mailbox) + """ + return self._simple_command('MOVE', self._sequence_set(message_set), + self._astring(new_mailbox)) + def myrights(self, mailbox): """Show my ACLs for a mailbox (i.e. the rights that I have on mailbox). @@ -1031,7 +1039,7 @@ def uid(self, command, *args): (command, self.state, ', '.join(Commands[command]))) name = 'UID' - if command == 'COPY': + if command in ('COPY', 'MOVE'): message_set, new_mailbox = args args = (self._sequence_set(message_set), self._astring(new_mailbox)) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index ef283267ff08ef0..046d28f4d30c8a4 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1173,6 +1173,35 @@ def test_uid_copy(self): self.assertEqual(data, [None]) self.assertEqual(server.args, ['COPY', '4827313:4828442', '"New folder"']) + def test_move(self): + client, server = self._setup(make_simple_handler('MOVE')) + client.login('user', 'pass') + client.select() + typ, data = client.move('2:4', 'MEETING') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'MOVE completed']) + self.assertEqual(server.args, ['2:4', 'MEETING']) + + typ, data = client.move('2:4', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'MOVE completed']) + self.assertEqual(server.args, ['2:4', '"New folder"']) + + def test_uid_move(self): + client, server = self._setup(make_simple_handler('UID', + completed='UID MOVE completed')) + client.login('user', 'pass') + client.select() + typ, data = client.uid('move', '4827313:4828442', 'MEETING') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [None]) + self.assertEqual(server.args, ['MOVE', '4827313:4828442', 'MEETING']) + + typ, data = client.uid('move', '4827313:4828442', 'New folder') + self.assertEqual(typ, 'OK') + self.assertEqual(data, [None]) + self.assertEqual(server.args, ['MOVE', '4827313:4828442', '"New folder"']) + def test_store(self): client, server = self._setup(make_simple_handler('STORE', [ r'* 2 FETCH (FLAGS (\Deleted \Seen))', diff --git a/Misc/NEWS.d/next/Library/2026-07-01-15-30-00.gh-issue-77508.Bn2kXt.rst b/Misc/NEWS.d/next/Library/2026-07-01-15-30-00.gh-issue-77508.Bn2kXt.rst new file mode 100644 index 000000000000000..d6f1bd23be080a3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-01-15-30-00.gh-issue-77508.Bn2kXt.rst @@ -0,0 +1,2 @@ +Add :meth:`imaplib.IMAP4.move`, a wrapper for the IMAP ``MOVE`` command +(:rfc:`6851`), analogous to :meth:`~imaplib.IMAP4.copy`. From b5326b67a06573807aee3c61100a10d3de25de09 Mon Sep 17 00:00:00 2001 From: Chandra Date: Sun, 5 Jul 2026 12:08:28 -0500 Subject: [PATCH 33/61] gh-105708: 'V' could be case insensitive for IPvFuture hostnames (#105709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * gh-105708: 'V' could be case insensitive for IPvFuture hostnames * gh-105708: 'V' could be case insensitive for IPvFuture hostnames & checking empty hostnames * 📜🤖 Added by blurb_it. * Fix the Merge changing \z to \Z. * Fixed the News Entry. * Fix the lint. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Senthil Kumaran --- Lib/test/test_urlparse.py | 15 ++++++++++----- Lib/urllib/parse.py | 4 ++-- ...2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 8e4da0e0f099191..a5b7966c7780e9e 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1653,15 +1653,20 @@ def test_splitting_bracketed_hosts(self): self.assertEqual(p1.username, 'user') self.assertEqual(p1.path, '/path') self.assertEqual(p1.port, 1234) - p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') - self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') + p2 = urllib.parse.urlsplit('scheme://user@[V6a.ip]:1234/path?query') + self.assertEqual(p2.hostname, 'v6a.ip') self.assertEqual(p2.username, 'user') self.assertEqual(p2.path, '/path') - self.assertIs(p2.port, None) - p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') - self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p2.port, 1234) + p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') + self.assertEqual(p3.hostname, '0439:23af:2309::fae7%test') self.assertEqual(p3.username, 'user') self.assertEqual(p3.path, '/path') + self.assertIs(p3.port, None) + p4 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') + self.assertEqual(p4.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p4.username, 'user') + self.assertEqual(p4.path, '/path') def test_port_casting_failure_message(self): message = "Port could not be cast to integer value as 'oracle'" diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 82b95adbdc283ef..4247b9a4b07fa3f 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -544,8 +544,8 @@ def _check_bracketed_netloc(netloc): # Valid bracketed hosts are defined in # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ def _check_bracketed_host(hostname): - if hostname.startswith('v'): - if not re.match(r"\Av[a-fA-F0-9]+\..+\z", hostname): + if hostname.startswith(('v', 'V')): + if not re.match(r"\A[vV][a-fA-F0-9]+\..+\z", hostname): raise ValueError(f"IPvFuture address is invalid") else: ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4 diff --git a/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst b/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst new file mode 100644 index 000000000000000..79289c1f0bd4217 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-12-21-31-02.gh-issue-105708.5fFwP8.rst @@ -0,0 +1 @@ +Accept an uppercase V prefix in IPvFuture addresses in :func:`urllib.parse.urlsplit`. From 78b6db6ec26187404fbff30aa45bae357bbc35d8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 5 Jul 2026 20:32:32 +0300 Subject: [PATCH 34/61] gh-98092: Add imaplib.IMAP4.id method (GH-153136) Add a wrapper for the IMAP ID command (RFC 2971). It takes a mapping of field names to values and returns the server identification information from the untagged ID response. Co-authored-by: Claude Fable 5 --- Doc/library/imaplib.rst | 13 +++++++++++ Doc/whatsnew/3.16.rst | 4 ++++ Lib/imaplib.py | 23 +++++++++++++++++++ Lib/test/test_imaplib.py | 18 +++++++++++++++ ...6-07-05-20-15-00.gh-issue-98092.iDcmd1.rst | 2 ++ 5 files changed, 60 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-20-15-00.gh-issue-98092.iDcmd1.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 6b7c02f54e90af2..0684820ccc6916c 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -328,6 +328,19 @@ An :class:`IMAP4` instance has the following methods: of the IMAP4 QUOTA extension defined in rfc2087. +.. method:: IMAP4.id(fields=None) + + Send client identification information to the server + and return the identification information sent back by the server + (the ``ID`` command, defined in :rfc:`2971`). + *fields* is a mapping of field names to values + (for example, ``{'name': 'myclient', 'version': '1.0'}``); + a value can be ``None``. + The server must support the ``ID`` capability. + + .. versionadded:: next + + .. method:: IMAP4.idle(duration=None) Return an :class:`!Idler`: an iterable context manager implementing the diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index cf105a26d98d45d..e8c530e19d2b53b 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -231,6 +231,10 @@ io imaplib ------- +* Add the :meth:`~imaplib.IMAP4.id` method, + a wrapper for the ``ID`` command (:rfc:`2971`). + (Contributed by Serhiy Storchaka in :gh:`98092`.) + * Add the :meth:`~imaplib.IMAP4.move` method, a wrapper for the ``MOVE`` command (:rfc:`6851`). (Contributed by Serhiy Storchaka in :gh:`77508`.) diff --git a/Lib/imaplib.py b/Lib/imaplib.py index adfd8afb9c053bb..40d2b7a309b640b 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -73,6 +73,7 @@ 'GETANNOTATION':('AUTH', 'SELECTED'), 'GETQUOTA': ('AUTH', 'SELECTED'), 'GETQUOTAROOT': ('AUTH', 'SELECTED'), + 'ID': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'), 'IDLE': ('AUTH', 'SELECTED'), 'MYRIGHTS': ('AUTH', 'SELECTED'), 'LIST': ('AUTH', 'SELECTED'), @@ -697,6 +698,28 @@ def getquotaroot(self, mailbox): return typ, [quotaroot, quota] + def id(self, fields=None): + """Send client identification information to the server. + + (typ, [data]) = .id(fields) + + 'fields' is a mapping of field names to values; a value can be + None. 'data' is the identification information sent back by + the server, in the same parenthesized list form. + """ + name = 'ID' + if fields: + items = [] + for field, value in fields.items(): + items.append(self._quote(field)) + items.append(b'NIL' if value is None else self._quote(value)) + arg = b'(' + b' '.join(items) + b')' + else: + arg = 'NIL' + typ, dat = self._simple_command(name, arg) + return self._untagged_response(typ, dat, name) + + def idle(self, duration=None): """Return an iterable IDLE context manager producing untagged responses. If the argument is not None, limit iteration to 'duration' seconds. diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 046d28f4d30c8a4..aba3f5e44f25668 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -1701,6 +1701,24 @@ def test_getquotaroot(self): self.assertEqual(typ, 'OK') self.assertEqual(server.args, ['"New folder"']) + def test_id(self): + client, server = self._setup(make_simple_handler('ID', + ['* ID ("name" "Cyrus" "version" "1.5")'])) + typ, data = client.id({'name': 'imaplib', 'version': '3.16'}) + self.assertEqual(typ, 'OK') + self.assertEqual(data, [b'("name" "Cyrus" "version" "1.5")']) + self.assertEqual(server.args, ['("name" "imaplib" "version" "3.16")']) + + typ, data = client.id() + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, ['NIL']) + + # Fields and values are quoted strings; a None value is sent + # as NIL. + typ, data = client.id({'name': 'my "client"', 'os': None}) + self.assertEqual(typ, 'OK') + self.assertEqual(server.args, [r'("name" "my \"client\"" "os" NIL)']) + def test_setquota(self): client, server = self._setup(make_simple_handler('SETQUOTA', ['* QUOTA "" (STORAGE 512)'])) diff --git a/Misc/NEWS.d/next/Library/2026-07-05-20-15-00.gh-issue-98092.iDcmd1.rst b/Misc/NEWS.d/next/Library/2026-07-05-20-15-00.gh-issue-98092.iDcmd1.rst new file mode 100644 index 000000000000000..9854e996a942a53 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-20-15-00.gh-issue-98092.iDcmd1.rst @@ -0,0 +1,2 @@ +Add :meth:`imaplib.IMAP4.id`, a wrapper for the IMAP ``ID`` command +(:rfc:`2971`). From 35ea24c8ffdda98197d794ad35525746bec50156 Mon Sep 17 00:00:00 2001 From: Vineet Kumar <108144301+whyvineet@users.noreply.github.com> Date: Mon, 6 Jul 2026 00:32:58 +0530 Subject: [PATCH 35/61] gh-153141: Fix mutable default argument in _SharedMemoryTracker.__init__ (GH-153142) Fix default argument for segment_names in _SharedMemoryTracker constructor to not use a mutable list. --- Lib/multiprocessing/managers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 91bcf243e78e5b8..11c6e21de90e693 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1294,9 +1294,9 @@ class SyncManager(BaseManager): class _SharedMemoryTracker: "Manages one or more shared memory segments." - def __init__(self, name, segment_names=[]): + def __init__(self, name, segment_names=None): self.shared_memory_context_name = name - self.segment_names = segment_names + self.segment_names = [] if segment_names is None else segment_names def register_segment(self, segment_name): "Adds the supplied shared memory block name to tracker." From d3ff1e8eda2d608ae6da23e4e3310b457e3fbd03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Buczkowski?= Date: Mon, 6 Jul 2026 06:26:44 +0900 Subject: [PATCH 36/61] bpo-45706: Add imaplib.IMAP4.login_plain (GH-29398) Adds authentication using PLAIN SASL mechanism. This is a plain-text authentication mechanism which can be used instead of IMAP4.login() when UTF-8 support is required. --- Doc/library/imaplib.rst | 21 +++++++++- Doc/whatsnew/3.16.rst | 5 +++ Lib/imaplib.py | 24 ++++++++++++ Lib/test/test_imaplib.py | 38 +++++++++++++++++++ Misc/ACKS | 1 + ...6-07-05-21-40-00.gh-issue-89869.XG7aHz.rst | 3 ++ 6 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-21-40-00.gh-issue-89869.XG7aHz.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 0684820ccc6916c..53934dc698f19e0 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -443,13 +443,30 @@ An :class:`IMAP4` instance has the following methods: .. method:: IMAP4.login_cram_md5(user, password) Force use of ``CRAM-MD5`` authentication when identifying the client to protect - the password. Will only work if the server ``CAPABILITY`` response includes the - phrase ``AUTH=CRAM-MD5``. + the password. It will only work if the server ``CAPABILITY`` response includes + the phrase ``AUTH=CRAM-MD5``. .. versionchanged:: 3.15 An :exc:`IMAP4.error` is raised if MD5 support is not available. +.. method:: IMAP4.login_plain(user, password) + + Authenticate using the ``PLAIN`` SASL mechanism (:rfc:`4616`). + + This is a plaintext authentication mechanism that can be used instead + of :meth:`login` when UTF-8 support is required (see :rfc:`6855`). + Since the credentials are only base64-encoded, not encrypted, this + method should only be used over a TLS-protected connection, such as + :class:`IMAP4_SSL` or after :meth:`starttls`. + + It will only work if the server supports the ``PLAIN`` mechanism, + which it need not advertise as ``AUTH=PLAIN`` in its ``CAPABILITY`` + response. + + .. versionadded:: next + + .. method:: IMAP4.logout() Shutdown connection to server. Returns server ``BYE`` response. diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index e8c530e19d2b53b..e8c75d2f571061a 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -239,6 +239,11 @@ imaplib a wrapper for the ``MOVE`` command (:rfc:`6851`). (Contributed by Serhiy Storchaka in :gh:`77508`.) +* Add the :meth:`~imaplib.IMAP4.login_plain` method, which authenticates + using the ``PLAIN`` SASL mechanism (:rfc:`4616`) and supports non-ASCII + user names and passwords. + (Contributed by Przemysław Buczkowski and Serhiy Storchaka in :gh:`89869`.) + logging ------- diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 40d2b7a309b640b..b1cf8872314d977 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -762,6 +762,30 @@ def login(self, user, password): return typ, dat + def login_plain(self, user, password): + """Authenticate using the PLAIN SASL mechanism (RFC 4616). + + This is a plaintext authentication mechanism that can be used + instead of login() when UTF-8 support is required. Since the + credentials are only base64-encoded, not encrypted, it should + only be used over a TLS-protected connection. + + 'user' and 'password' can be strings (encoded to UTF-8) or + bytes-like objects. + """ + if isinstance(user, str): + user = user.encode('utf-8') + if isinstance(password, str): + password = password.encode('utf-8') + if b'\0' in user or b'\0' in password: + raise ValueError("NUL is not allowed in user name or password") + # An empty authorization identity (RFC 4616) makes the server + # derive it from the authentication identity; a non-empty one + # requests proxy authorization and is often rejected. + response = b'\0' + bytes(user) + b'\0' + bytes(password) + return self.authenticate("PLAIN", lambda _: response) + + def login_cram_md5(self, user, password): """ Force use of CRAM-MD5 authentication. diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index aba3f5e44f25668..a2ddbbf91218083 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -420,6 +420,15 @@ def cmd_AUTHENTICATE(self, tag, args): self._send_tagged(tag, 'NO', 'No access') +class AuthHandler_PLAIN(SimpleIMAPHandler): + capabilities = 'LOGINDISABLED AUTH=PLAIN' + def cmd_AUTHENTICATE(self, tag, args): + self.server.auth_args = args + self._send_textline('+') + self.server.response = yield + self._send_tagged(tag, 'OK', 'Logged in.') + + class NewIMAPTestsMixin: client = None @@ -692,6 +701,35 @@ def test_login_cram_md5_blocked(self): with self.assertRaisesRegex(imaplib.IMAP4.error, msg): client.login_cram_md5("tim", b"tanstaaftanstaaf") + def test_login_plain_ascii(self): + client, server = self._setup(AuthHandler_PLAIN) + self.assertIn('AUTH=PLAIN', client.capabilities) + ret, _ = client.login_plain("prem", "pass") + self.assertEqual(ret, "OK") + self.assertEqual(server.auth_args, ['PLAIN']) + self.assertEqual(server.response, b'AHByZW0AcGFzcw==\r\n') + + def test_login_plain_utf8(self): + client, server = self._setup(AuthHandler_PLAIN) + self.assertIn('AUTH=PLAIN', client.capabilities) + ret, _ = client.login_plain("pręm", "żółć") + self.assertEqual(ret, "OK") + self.assertEqual(server.response, b'AHByxJltAMW8w7PFgsSH\r\n') + + def test_login_plain_bytes(self): + # bytes are accepted and sent verbatim (not re-encoded). + client, server = self._setup(AuthHandler_PLAIN) + ret, _ = client.login_plain(b'pr\xc4\x99m', b'\xc5\xbc\xc3\xb3\xc5\x82\xc4\x87') + self.assertEqual(ret, "OK") + self.assertEqual(server.response, b'AHByxJltAMW8w7PFgsSH\r\n') + + def test_login_plain_nul(self): + client, _ = self._setup(AuthHandler_PLAIN) + with self.assertRaises(ValueError): + client.login_plain('user\0', 'pass') + with self.assertRaises(ValueError): + client.login_plain('user', b'pa\0ss') + def test_aborted_authentication(self): class MyServer(SimpleIMAPHandler): def cmd_AUTHENTICATE(self, tag, args): diff --git a/Misc/ACKS b/Misc/ACKS index 1f2049da56c2da7..68fed1f68de5933 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -260,6 +260,7 @@ Stan Bubrouski Brandt Bucher Curtis Bucher Colm Buckley +Przemysław Buczkowski Erik de Bueger Jan-Hein Bührman Marc Bürg diff --git a/Misc/NEWS.d/next/Library/2026-07-05-21-40-00.gh-issue-89869.XG7aHz.rst b/Misc/NEWS.d/next/Library/2026-07-05-21-40-00.gh-issue-89869.XG7aHz.rst new file mode 100644 index 000000000000000..4bf319f7f681525 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-21-40-00.gh-issue-89869.XG7aHz.rst @@ -0,0 +1,3 @@ +Add :meth:`imaplib.IMAP4.login_plain`, which authenticates using the +``PLAIN`` SASL mechanism (:rfc:`4616`). Unlike :meth:`~imaplib.IMAP4.login`, +it supports non-ASCII user names and passwords. From 0ae768b7c338b944784659c38aaf4902fb747e29 Mon Sep 17 00:00:00 2001 From: Pedram Karimi <147748351+pedramkarimii@users.noreply.github.com> Date: Mon, 6 Jul 2026 04:47:20 +0330 Subject: [PATCH 37/61] gh-151640: Track sharing of `BytesIO` buffer in free-threaded builds (GH-151651) --- Lib/test/test_free_threading/test_io.py | 29 +++++++++++ Lib/test/test_io/test_memoryio.py | 5 +- ...-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst | 3 ++ Modules/_io/bytesio.c | 49 ++++++++++++++++++- 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst diff --git a/Lib/test/test_free_threading/test_io.py b/Lib/test/test_free_threading/test_io.py index 742da6f8c788b42..e0bd7e211e73024 100644 --- a/Lib/test/test_free_threading/test_io.py +++ b/Lib/test/test_free_threading/test_io.py @@ -122,6 +122,35 @@ def sizeof(barrier, b, *ignore): class CBytesIOTest(ThreadSafetyMixin, TestCase): ioclass = io.BytesIO + @threading_helper.requires_working_threading() + @threading_helper.reap_threads + def test_concurrent_whole_buffer_read_and_resize(self): + shared = self.ioclass(b"x" * 64) + writers = 2 + readers = 8 + loops = 2000 + barrier = threading.Barrier(writers + readers) + + def writer(): + barrier.wait() + for i in range(loops): + shared.seek(0) + shared.write(b"a" * (64 + (i & 63))) + + def reader(): + barrier.wait() + for _ in range(loops): + shared.seek(0) + shared.read() + shared.seek(0) + shared.peek() + shared.getvalue() + + threads = [threading.Thread(target=writer) for _ in range(writers)] + threads += [threading.Thread(target=reader) for _ in range(readers)] + with threading_helper.start_threads(threads): + pass + class PyBytesIOTest(ThreadSafetyMixin, TestCase): ioclass = pyio.BytesIO diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py index 5a93d2634580461..f53525d77b7dbaf 100644 --- a/Lib/test/test_io/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -939,7 +939,10 @@ def test_setstate(self): @support.cpython_only def test_sizeof(self): - basesize = support.calcobjsize('P2n2Pn') + if support.Py_GIL_DISABLED: + basesize = support.calcobjsize('P2n2Pni') + else: + basesize = support.calcobjsize('P2n2Pn') check = self.check_sizeof self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) check(io.BytesIO(), basesize ) diff --git a/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst b/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst new file mode 100644 index 000000000000000..ef61a7d27dd07dd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-18-12-48-03.gh-issue-151640.R4c3Fx.rst @@ -0,0 +1,3 @@ +Fix a data race in :class:`io.BytesIO` in free-threaded builds when +whole-buffer reads or peeks, or :meth:`~io.BytesIO.getvalue`, share the +internal buffer with concurrent writes. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index ffe82150be1b514..3d14ec3f8f94a92 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -22,6 +22,9 @@ typedef struct { PyObject *dict; PyObject *weakreflist; Py_ssize_t exports; +#ifdef Py_GIL_DISABLED + int buf_shared; +#endif } bytesio; #define bytesio_CAST(op) ((bytesio *)(op)) @@ -71,7 +74,45 @@ check_exports(bytesio *self) return NULL; \ } +#ifdef Py_GIL_DISABLED +#define SHARED_BUF(self) ((self)->buf_shared || !_PyObject_IsUniquelyReferenced((self)->buf)) +#else #define SHARED_BUF(self) (!_PyObject_IsUniquelyReferenced((self)->buf)) +#endif + +static inline void +set_shared_buf(bytesio *self) +{ +#ifdef Py_GIL_DISABLED + self->buf_shared = 1; +#endif +} + +static inline void +clear_shared_buf(bytesio *self) +{ +#ifdef Py_GIL_DISABLED + self->buf_shared = 0; +#endif +} + +static int +resize_unshared_buffer_lock_held(bytesio *self, Py_ssize_t size) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + +#ifdef Py_GIL_DISABLED + /* If the internal bytes object escaped via a zero-copy getvalue(), read(), + or peek(), resizing it would mutate an object visible to Python code. + Callers must detach first. */ + assert(!self->buf_shared); +#endif + int ret = _PyBytes_Resize(&self->buf, size); + if (ret == 0) { + clear_shared_buf(self); + } + return ret; +} /* Internal routine to get a line from the buffer of a BytesIO @@ -128,6 +169,7 @@ unshare_buffer_lock_held(bytesio *self, size_t size) memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf), self->string_size); Py_SETREF(self->buf, new_buf); + clear_shared_buf(self); return 0; } @@ -173,7 +215,7 @@ resize_buffer_lock_held(bytesio *self, size_t size) return -1; } else { - if (_PyBytes_Resize(&self->buf, alloc) < 0) + if (resize_unshared_buffer_lock_held(self, alloc) < 0) return -1; } @@ -381,10 +423,11 @@ _io_BytesIO_getvalue_impl(bytesio *self) return NULL; } else { - if (_PyBytes_Resize(&self->buf, self->string_size) < 0) + if (resize_unshared_buffer_lock_held(self, self->string_size) < 0) return NULL; } } + set_shared_buf(self); return Py_NewRef(self->buf); } @@ -433,6 +476,7 @@ peek_bytes_lock_held(bytesio *self, Py_ssize_t size) if (size > 1 && self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) { + set_shared_buf(self); return Py_NewRef(self->buf); } @@ -1091,6 +1135,7 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) if (initvalue && initvalue != Py_None) { if (PyBytes_CheckExact(initvalue)) { Py_XSETREF(self->buf, Py_NewRef(initvalue)); + clear_shared_buf(self); self->string_size = PyBytes_GET_SIZE(initvalue); } else { From c78ea517b9dea42b23a885cb1009ed28d9fa5f3a Mon Sep 17 00:00:00 2001 From: Pranav Choudhary Date: Mon, 6 Jul 2026 08:49:17 +0530 Subject: [PATCH 38/61] gh-82151: Update and improve urlsplit docstring (#152985) * gh-82151: Update and improve urlsplit docstring Co-authored-by: idomic * Slightly improved wording for % escapes. Consistent with rest of the doc. --------- Co-authored-by: idomic Co-authored-by: Senthil Kumaran --- Doc/library/urllib.parse.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index ef48addaba03e9c..3ce20311c42c849 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -60,11 +60,16 @@ or on combining URL components into a URL string. *missing_as_none* is true. Not defined component are represented an empty string (by default) or ``None`` if *missing_as_none* is true. - The components are not broken up - into smaller parts (for example, the network location is a single string), and % - escapes are not expanded. The delimiters as shown above are not part of the - result, except for a leading slash in the *path* component, which is retained if - present. For example: + The delimiters as shown above are not part of the result, except for a + leading slash in the *path* component, which is retained if present. + + Additionally, the netloc property is broken down into these additional + attributes added to the returned object: username, password, hostname, and + port. + + Percent-encoded sequences are not decoded. + + For example: .. doctest:: :options: +NORMALIZE_WHITESPACE From 9fda8e77365f477d877b65cf05369d8b16567e40 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 6 Jul 2026 08:22:37 +0300 Subject: [PATCH 39/61] gh-152026: Track mark-saving contexts with a counter (GH-153160) Replace the state->repeat checks that guard mark saving and restoring with an explicit save_marks counter maintained where repeat and possessive contexts are entered and left. Each push is now paired with a pop decided by the same condition. Co-authored-by: Claude Opus 4.8 --- Modules/_sre/sre.c | 1 + Modules/_sre/sre.h | 4 +++ Modules/_sre/sre_lib.h | 74 ++++++++++++++++++++---------------------- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 7d03b909226f244..e742a25e4891fce 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -738,6 +738,7 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, state->charsize = charsize; state->match_all = 0; state->must_advance = 0; + state->save_marks = 0; state->debug = ((pattern->flags & SRE_FLAG_DEBUG) != 0); state->beginning = ptr; diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h index 42681c2addf3c2c..bec4ae21d1e10f9 100644 --- a/Modules/_sre/sre.h +++ b/Modules/_sre/sre.h @@ -97,6 +97,10 @@ typedef struct { int lastmark; int lastindex; const void** mark; + int save_marks; /* if nonzero, save and restore mark values on + backtracking instead of only rewinding the lastmark + index; counts enclosing repeat contexts and + possessive bodies */ /* dynamically allocated stuff */ char* data_stack; size_t data_stack_size; diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h index 6e6ae46f05a50f0..444cd39d2fed288 100644 --- a/Modules/_sre/sre_lib.h +++ b/Modules/_sre/sre_lib.h @@ -863,7 +863,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) /* <0=skip> code ... */ TRACE(("|%p|%p|BRANCH\n", pattern, ptr)); LASTMARK_SAVE(); - if (state->repeat) + if (state->save_marks) MARK_PUSH(ctx->lastmark); for (; pattern[0]; pattern += pattern[0]) { if (pattern[1] == SRE_OP_LITERAL && @@ -878,16 +878,16 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) state->ptr = ptr; DO_JUMP(JUMP_BRANCH, jump_branch, pattern+1); if (ret) { - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); RETURN_ON_ERROR(ret); RETURN_SUCCESS; } - if (state->repeat) + if (state->save_marks) MARK_POP_KEEP(ctx->lastmark); LASTMARK_RESTORE(); } - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); RETURN_FAILURE; @@ -933,7 +933,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) } LASTMARK_SAVE(); - if (state->repeat) + if (state->save_marks) MARK_PUSH(ctx->lastmark); if (pattern[pattern[0]] == SRE_OP_LITERAL) { @@ -952,19 +952,19 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) DO_JUMP(JUMP_REPEAT_ONE_1, jump_repeat_one_1, pattern+pattern[0]); if (ret) { - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); RETURN_ON_ERROR(ret); RETURN_SUCCESS; } - if (state->repeat) + if (state->save_marks) MARK_POP_KEEP(ctx->lastmark); LASTMARK_RESTORE(); ptr--; ctx->count--; } - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); } else { /* general case */ @@ -973,19 +973,19 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) DO_JUMP(JUMP_REPEAT_ONE_2, jump_repeat_one_2, pattern+pattern[0]); if (ret) { - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); RETURN_ON_ERROR(ret); RETURN_SUCCESS; } - if (state->repeat) + if (state->save_marks) MARK_POP_KEEP(ctx->lastmark); LASTMARK_RESTORE(); ptr--; ctx->count--; } - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); } RETURN_FAILURE; @@ -1035,7 +1035,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) } else { /* general case */ LASTMARK_SAVE(); - if (state->repeat) + if (state->save_marks) MARK_PUSH(ctx->lastmark); while ((Py_ssize_t)pattern[2] == SRE_MAXREPEAT @@ -1044,12 +1044,12 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) DO_JUMP(JUMP_MIN_REPEAT_ONE,jump_min_repeat_one, pattern+pattern[0]); if (ret) { - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); RETURN_ON_ERROR(ret); RETURN_SUCCESS; } - if (state->repeat) + if (state->save_marks) MARK_POP_KEEP(ctx->lastmark); LASTMARK_RESTORE(); @@ -1063,7 +1063,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) ptr++; ctx->count++; } - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); } RETURN_FAILURE; @@ -1140,10 +1140,12 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) ctx->u.rep->prev = state->repeat; ctx->u.rep->last_ptr = NULL; state->repeat = ctx->u.rep; + state->save_marks++; state->ptr = ptr; DO_JUMP(JUMP_REPEAT, jump_repeat, pattern+pattern[0]); state->repeat = ctx->u.rep->prev; + state->save_marks--; repeat_pool_free(state, ctx->u.rep); if (ret) { @@ -1212,8 +1214,10 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) /* cannot match more repeated items here. make sure the tail matches */ state->repeat = ctx->u.rep->prev; + state->save_marks--; DO_JUMP(JUMP_MAX_UNTIL_3, jump_max_until_3, pattern); state->repeat = ctx->u.rep; // restore repeat before return + state->save_marks++; RETURN_ON_SUCCESS(ret); state->ptr = ptr; @@ -1250,22 +1254,26 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) /* see if the tail matches */ state->repeat = ctx->u.rep->prev; + state->save_marks--; LASTMARK_SAVE(); - if (state->repeat) + if (state->save_marks) MARK_PUSH(ctx->lastmark); DO_JUMP(JUMP_MIN_UNTIL_2, jump_min_until_2, pattern); - SRE_REPEAT *repeat_of_tail = state->repeat; + /* save_marks is balanced across the jump, so this equals the + value tested for MARK_PUSH above */ + int pushed = state->save_marks != 0; state->repeat = ctx->u.rep; // restore repeat before return + state->save_marks++; if (ret) { - if (repeat_of_tail) + if (pushed) MARK_POP_DISCARD(ctx->lastmark); RETURN_ON_ERROR(ret); RETURN_SUCCESS; } - if (repeat_of_tail) + if (pushed) MARK_POP(ctx->lastmark); LASTMARK_RESTORE(); @@ -1302,16 +1310,10 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) pointer */ state->ptr = ptr; - /* Set state->repeat to non-NULL */ - ctx->u.rep = repeat_pool_malloc(state); - if (!ctx->u.rep) { - RETURN_ERROR(SRE_ERROR_MEMORY); - } - ctx->u.rep->count = -1; - ctx->u.rep->pattern = NULL; - ctx->u.rep->prev = state->repeat; - ctx->u.rep->last_ptr = NULL; - state->repeat = ctx->u.rep; + /* Capture groups in the body can be revisited on backtracking + between iterations, so their marks must be saved and restored, + as is done inside a repeat. */ + state->save_marks++; /* Initialize Count to 0 */ ctx->count = 0; @@ -1327,9 +1329,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) } else { state->ptr = ptr; - /* Restore state->repeat */ - state->repeat = ctx->u.rep->prev; - repeat_pool_free(state, ctx->u.rep); + state->save_marks--; RETURN_FAILURE; } } @@ -1402,9 +1402,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) } } - /* Restore state->repeat */ - state->repeat = ctx->u.rep->prev; - repeat_pool_free(state, ctx->u.rep); + state->save_marks--; /* Evaluate Tail */ /* Jump to end of pattern indicated by skip, and then skip @@ -1586,17 +1584,17 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) if ((uintptr_t)(ptr - (SRE_CHAR *)state->beginning) >= pattern[1]) { state->ptr = ptr - pattern[1]; LASTMARK_SAVE(); - if (state->repeat) + if (state->save_marks) MARK_PUSH(ctx->lastmark); DO_JUMP0(JUMP_ASSERT_NOT, jump_assert_not, pattern+2); if (ret) { - if (state->repeat) + if (state->save_marks) MARK_POP_DISCARD(ctx->lastmark); RETURN_ON_ERROR(ret); RETURN_FAILURE; } - if (state->repeat) + if (state->save_marks) MARK_POP(ctx->lastmark); LASTMARK_RESTORE(); } From 410d1020e6d99fe09cd0155950b2b7af7d76dc9a Mon Sep 17 00:00:00 2001 From: Eoin Shaughnessy <45000144+EoinTrial@users.noreply.github.com> Date: Mon, 6 Jul 2026 08:44:48 +0100 Subject: [PATCH 40/61] gh-148765: Fix description of *include_hidden* parameter in `glob.glob()` docs (#148768) Co-authored-by: Stan Ulbrych --- Doc/library/glob.rst | 7 ++++--- Lib/glob.py | 8 ++++---- Misc/ACKS | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Doc/library/glob.rst b/Doc/library/glob.rst index 942f23d216fc075..bbeb808159d446b 100644 --- a/Doc/library/glob.rst +++ b/Doc/library/glob.rst @@ -29,7 +29,7 @@ not by actually invoking a subshell. The pathnames are returned in no particular order. If you need a specific order, sort the results. -Files beginning with a dot (``.``) can only be matched by +By default, files beginning with a dot (``.``) can only be matched by patterns that also start with a dot, unlike :func:`fnmatch.fnmatch` or :func:`pathlib.Path.glob`. For tilde and shell variable expansion, use :func:`os.path.expanduser` and @@ -70,7 +70,8 @@ The :mod:`!glob` module defines the following functions: pattern is followed by an :data:`os.sep` or :data:`os.altsep` then files will not match. - If *include_hidden* is true, "``**``" pattern will match hidden directories. + If *include_hidden* is true, wildcards can match path segments that + begin with a dot (``.``). .. audit-event:: glob.glob pathname,recursive glob.glob .. audit-event:: glob.glob/2 pathname,recursive,root_dir,dir_fd glob.glob @@ -131,7 +132,7 @@ The :mod:`!glob` module defines the following functions: Escape all special characters (``'?'``, ``'*'`` and ``'['``). This is useful if you want to match an arbitrary literal string that may have special characters in it. Special characters in drive/UNC - sharepoints are not escaped, e.g. on Windows + sharepoints are not escaped, for example on Windows ``escape('//?/c:/Quo vadis?.txt')`` returns ``'//?/c:/Quo vadis[?].txt'``. .. versionadded:: 3.4 diff --git a/Lib/glob.py b/Lib/glob.py index 5a8ff46137ba5e4..07b9d3eb952ed65 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -34,8 +34,8 @@ def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, If `dir_fd` is not None, it should be a file descriptor referring to a directory, and paths will then be relative to that directory. - If `include_hidden` is true, the patterns '*', '?', '**' will match - hidden directories. + If `include_hidden` is true, wildcards can match path segments beginning + with a dot ('.'). If `recursive` is true, the pattern '**' will match any files and zero or more directories and subdirectories. @@ -64,8 +64,8 @@ def iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False, If `dir_fd` is not None, it should be a file descriptor referring to a directory, and paths will then be relative to that directory. - If `include_hidden` is true, the patterns '*', '?', '**' will match - hidden directories. + If `include_hidden` is true, wildcards can match path segments beginning + with a dot ('.'). If `recursive` is true, the pattern '**' will match any files and zero or more directories and subdirectories. diff --git a/Misc/ACKS b/Misc/ACKS index 68fed1f68de5933..fec00c1b272f4ea 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1756,6 +1756,7 @@ Ha Shao Richard Shapiro Soumya Sharma Varun Sharma +Eoin Shaughnessy Daniel Shaulov Vlad Shcherbina Justin Sheehy From e9ae92d2363063acc89e03df363389d17207d658 Mon Sep 17 00:00:00 2001 From: An Long Date: Mon, 6 Jul 2026 18:41:47 +0900 Subject: [PATCH 41/61] gh-145855: Remove the DELETE_ATTR bytecode (GH-146216) --- Doc/library/dis.rst | 11 - Doc/tools/removed-ids.txt | 1 + Include/internal/pycore_magic_number.h | 3 +- Include/internal/pycore_opcode_metadata.h | 10 +- Include/internal/pycore_uop_ids.h | 1584 ++++++++--------- Include/internal/pycore_uop_metadata.h | 15 - Include/opcode_ids.h | 117 +- Lib/_opcode_metadata.py | 117 +- Lib/test/test_compile.py | 5 +- ...-03-20-16-27-15.gh-issue-145855.3yaHO4.rst | 1 + Modules/_testinternalcapi/test_cases.c.h | 67 +- Modules/_testinternalcapi/test_targets.h | 9 +- Programs/test_frozenmain.h | 20 +- Python/bytecodes.c | 22 +- Python/codegen.c | 7 +- Python/executor_cases.c.h | 43 +- Python/generated_cases.c.h | 67 +- Python/opcode_targets.h | 9 +- Python/optimizer_cases.c.h | 7 - 19 files changed, 990 insertions(+), 1125 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-03-20-16-27-15.gh-issue-145855.3yaHO4.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 9196d09b6a6a58f..5cc0d68a24acee9 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1095,17 +1095,6 @@ iterations of the loop. where *namei* is the index of name in :attr:`~codeobject.co_names` of the :ref:`code object `. -.. opcode:: DELETE_ATTR (namei) - - Implements:: - - obj = STACK.pop() - del obj.name - - where *namei* is the index of name into :attr:`~codeobject.co_names` of the - :ref:`code object `. - - .. opcode:: STORE_GLOBAL (namei) Works as :opcode:`STORE_NAME`, but stores the name as a global. diff --git a/Doc/tools/removed-ids.txt b/Doc/tools/removed-ids.txt index a01681ee9d0fc67..48c9809f0502bfa 100644 --- a/Doc/tools/removed-ids.txt +++ b/Doc/tools/removed-ids.txt @@ -6,6 +6,7 @@ c-api/file.html: deprecated-api # Removed sections library/asyncio-task.html: terminating-a-task-group +library/dis.html: opcode-DELETE_ATTR library/dis.html: opcode-DELETE_GLOBAL library/dis.html: opcode-DELETE_NAME library/asyncio-llapi-index.html: event-loop-policies diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index 74703dcdbcdd6fa..53ed570f99f118a 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -301,6 +301,7 @@ Known values: Python 3.16a0 3701 (Add CONSTANT_EMPTY_TUPLE to LOAD_COMMON_CONSTANT) Python 3.16a1 3702 (Replace DELETE_NAME with PUSH_NULL; STORE_NAME) Python 3.16a1 3703 (Replace DELETE_GLOBAL with PUSH_NULL; STORE_GLOBAL) + Python 3.16a1 3704 (Replace DELETE_ATTR with PUSH_NULL; STORE_ATTR) Python 3.17 will start with 3750 @@ -314,7 +315,7 @@ PC/launcher.c must also be updated. */ -#define PYC_MAGIC_NUMBER 3703 +#define PYC_MAGIC_NUMBER 3704 /* 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/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 6086dfd21f0839a..647f6b6cbb989ad 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -178,8 +178,6 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 1 + (oparg-1); case COPY_FREE_VARS: return 0; - case DELETE_ATTR: - return 1; case DELETE_DEREF: return 0; case DELETE_FAST: @@ -675,8 +673,6 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 2 + (oparg-1); case COPY_FREE_VARS: return 0; - case DELETE_ATTR: - return 0; case DELETE_DEREF: return 0; case DELETE_FAST: @@ -1174,7 +1170,6 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [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 }, [DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [DELETE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DELETE_SUBSCR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1425,7 +1420,6 @@ _PyOpcode_macro_expansion[256] = { [CONVERT_VALUE] = { .nuops = 1, .uops = { { _CONVERT_VALUE, OPARG_SIMPLE, 0 } } }, [COPY] = { .nuops = 1, .uops = { { _COPY, OPARG_SIMPLE, 0 } } }, [COPY_FREE_VARS] = { .nuops = 1, .uops = { { _COPY_FREE_VARS, OPARG_SIMPLE, 0 } } }, - [DELETE_ATTR] = { .nuops = 1, .uops = { { _DELETE_ATTR, OPARG_SIMPLE, 0 } } }, [DELETE_DEREF] = { .nuops = 1, .uops = { { _DELETE_DEREF, OPARG_SIMPLE, 0 } } }, [DELETE_FAST] = { .nuops = 1, .uops = { { _DELETE_FAST, OPARG_SIMPLE, 0 } } }, [DELETE_SUBSCR] = { .nuops = 1, .uops = { { _DELETE_SUBSCR, OPARG_SIMPLE, 0 } } }, @@ -1628,7 +1622,6 @@ const char *_PyOpcode_OpName[267] = { [CONVERT_VALUE] = "CONVERT_VALUE", [COPY] = "COPY", [COPY_FREE_VARS] = "COPY_FREE_VARS", - [DELETE_ATTR] = "DELETE_ATTR", [DELETE_DEREF] = "DELETE_DEREF", [DELETE_FAST] = "DELETE_FAST", [DELETE_SUBSCR] = "DELETE_SUBSCR", @@ -1834,6 +1827,7 @@ const uint8_t _PyOpcode_Caches[256] = { PyAPI_DATA(const uint8_t) _PyOpcode_Deopt[256]; #ifdef NEED_OPCODE_METADATA const uint8_t _PyOpcode_Deopt[256] = { + [117] = 117, [118] = 118, [119] = 119, [120] = 120, @@ -1928,7 +1922,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [CONVERT_VALUE] = CONVERT_VALUE, [COPY] = COPY, [COPY_FREE_VARS] = COPY_FREE_VARS, - [DELETE_ATTR] = DELETE_ATTR, [DELETE_DEREF] = DELETE_DEREF, [DELETE_FAST] = DELETE_FAST, [DELETE_SUBSCR] = DELETE_SUBSCR, @@ -2095,6 +2088,7 @@ const uint8_t _PyOpcode_Deopt[256] = { #endif // NEED_OPCODE_METADATA #define EXTRA_CASES \ + case 117: \ case 118: \ case 119: \ case 120: \ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 1dc04e3591ac083..cd34aaa9d34afde 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -120,7 +120,6 @@ extern "C" { #define _COPY_3 397 #define _COPY_FREE_VARS COPY_FREE_VARS #define _CREATE_INIT_FRAME 398 -#define _DELETE_ATTR DELETE_ATTR #define _DELETE_DEREF DELETE_DEREF #define _DELETE_FAST DELETE_FAST #define _DELETE_SUBSCR DELETE_SUBSCR @@ -644,798 +643,797 @@ extern "C" { #define _COPY_FREE_VARS_r22 858 #define _COPY_FREE_VARS_r33 859 #define _CREATE_INIT_FRAME_r01 860 -#define _DELETE_ATTR_r10 861 -#define _DELETE_DEREF_r00 862 -#define _DELETE_FAST_r00 863 -#define _DELETE_SUBSCR_r20 864 -#define _DEOPT_r00 865 -#define _DEOPT_r10 866 -#define _DEOPT_r20 867 -#define _DEOPT_r30 868 -#define _DICT_MERGE_r11 869 -#define _DICT_UPDATE_r11 870 -#define _DO_CALL_r01 871 -#define _DO_CALL_FUNCTION_EX_r31 872 -#define _DO_CALL_KW_r11 873 -#define _DYNAMIC_EXIT_r00 874 -#define _DYNAMIC_EXIT_r10 875 -#define _DYNAMIC_EXIT_r20 876 -#define _DYNAMIC_EXIT_r30 877 -#define _END_FOR_r10 878 -#define _END_SEND_r31 879 -#define _ERROR_POP_N_r00 880 -#define _EXIT_INIT_CHECK_r10 881 -#define _EXIT_TRACE_r00 882 -#define _EXIT_TRACE_r10 883 -#define _EXIT_TRACE_r20 884 -#define _EXIT_TRACE_r30 885 -#define _EXPAND_METHOD_r00 886 -#define _EXPAND_METHOD_KW_r11 887 -#define _FATAL_ERROR_r00 888 -#define _FATAL_ERROR_r11 889 -#define _FATAL_ERROR_r22 890 -#define _FATAL_ERROR_r33 891 -#define _FORMAT_SIMPLE_r11 892 -#define _FORMAT_WITH_SPEC_r21 893 -#define _FOR_ITER_r23 894 -#define _FOR_ITER_GEN_FRAME_r03 895 -#define _FOR_ITER_GEN_FRAME_r13 896 -#define _FOR_ITER_GEN_FRAME_r23 897 -#define _FOR_ITER_TIER_TWO_r23 898 -#define _FOR_ITER_VIRTUAL_r23 899 -#define _FOR_ITER_VIRTUAL_TIER_TWO_r23 900 -#define _GET_AITER_r11 901 -#define _GET_ANEXT_r12 902 -#define _GET_AWAITABLE_r11 903 -#define _GET_ITER_r12 904 -#define _GET_ITER_TRAD_r12 905 -#define _GET_LEN_r12 906 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r03 907 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r13 908 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r23 909 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r33 910 -#define _GUARD_BINARY_OP_EXTEND_r22 911 -#define _GUARD_BINARY_OP_EXTEND_LHS_r02 912 -#define _GUARD_BINARY_OP_EXTEND_LHS_r12 913 -#define _GUARD_BINARY_OP_EXTEND_LHS_r22 914 -#define _GUARD_BINARY_OP_EXTEND_LHS_r33 915 -#define _GUARD_BINARY_OP_EXTEND_RHS_r02 916 -#define _GUARD_BINARY_OP_EXTEND_RHS_r12 917 -#define _GUARD_BINARY_OP_EXTEND_RHS_r22 918 -#define _GUARD_BINARY_OP_EXTEND_RHS_r33 919 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 920 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 921 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 922 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 923 -#define _GUARD_BIT_IS_SET_POP_r00 924 -#define _GUARD_BIT_IS_SET_POP_r10 925 -#define _GUARD_BIT_IS_SET_POP_r21 926 -#define _GUARD_BIT_IS_SET_POP_r32 927 -#define _GUARD_BIT_IS_SET_POP_4_r00 928 -#define _GUARD_BIT_IS_SET_POP_4_r10 929 -#define _GUARD_BIT_IS_SET_POP_4_r21 930 -#define _GUARD_BIT_IS_SET_POP_4_r32 931 -#define _GUARD_BIT_IS_SET_POP_5_r00 932 -#define _GUARD_BIT_IS_SET_POP_5_r10 933 -#define _GUARD_BIT_IS_SET_POP_5_r21 934 -#define _GUARD_BIT_IS_SET_POP_5_r32 935 -#define _GUARD_BIT_IS_SET_POP_6_r00 936 -#define _GUARD_BIT_IS_SET_POP_6_r10 937 -#define _GUARD_BIT_IS_SET_POP_6_r21 938 -#define _GUARD_BIT_IS_SET_POP_6_r32 939 -#define _GUARD_BIT_IS_SET_POP_7_r00 940 -#define _GUARD_BIT_IS_SET_POP_7_r10 941 -#define _GUARD_BIT_IS_SET_POP_7_r21 942 -#define _GUARD_BIT_IS_SET_POP_7_r32 943 -#define _GUARD_BIT_IS_UNSET_POP_r00 944 -#define _GUARD_BIT_IS_UNSET_POP_r10 945 -#define _GUARD_BIT_IS_UNSET_POP_r21 946 -#define _GUARD_BIT_IS_UNSET_POP_r32 947 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 948 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 949 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 950 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 951 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 952 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 953 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 954 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 955 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 956 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 957 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 958 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 959 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 960 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 961 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 962 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 963 -#define _GUARD_CALLABLE_BUILTIN_CLASS_r00 964 -#define _GUARD_CALLABLE_BUILTIN_FAST_r00 965 -#define _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS_r00 966 -#define _GUARD_CALLABLE_BUILTIN_O_r00 967 -#define _GUARD_CALLABLE_ISINSTANCE_r03 968 -#define _GUARD_CALLABLE_ISINSTANCE_r13 969 -#define _GUARD_CALLABLE_ISINSTANCE_r23 970 -#define _GUARD_CALLABLE_ISINSTANCE_r33 971 -#define _GUARD_CALLABLE_LEN_r03 972 -#define _GUARD_CALLABLE_LEN_r13 973 -#define _GUARD_CALLABLE_LEN_r23 974 -#define _GUARD_CALLABLE_LEN_r33 975 -#define _GUARD_CALLABLE_LIST_APPEND_r03 976 -#define _GUARD_CALLABLE_LIST_APPEND_r13 977 -#define _GUARD_CALLABLE_LIST_APPEND_r23 978 -#define _GUARD_CALLABLE_LIST_APPEND_r33 979 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_r00 980 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 981 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS_r00 982 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_O_r00 983 -#define _GUARD_CALLABLE_STR_1_r03 984 -#define _GUARD_CALLABLE_STR_1_r13 985 -#define _GUARD_CALLABLE_STR_1_r23 986 -#define _GUARD_CALLABLE_STR_1_r33 987 -#define _GUARD_CALLABLE_TUPLE_1_r03 988 -#define _GUARD_CALLABLE_TUPLE_1_r13 989 -#define _GUARD_CALLABLE_TUPLE_1_r23 990 -#define _GUARD_CALLABLE_TUPLE_1_r33 991 -#define _GUARD_CALLABLE_TYPE_1_r03 992 -#define _GUARD_CALLABLE_TYPE_1_r13 993 -#define _GUARD_CALLABLE_TYPE_1_r23 994 -#define _GUARD_CALLABLE_TYPE_1_r33 995 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r00 996 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r11 997 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r22 998 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r33 999 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r00 1000 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r11 1001 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r22 1002 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r33 1003 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r00 1004 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r11 1005 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r22 1006 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r33 1007 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r00 1008 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r11 1009 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r22 1010 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r33 1011 -#define _GUARD_DORV_NO_DICT_r01 1012 -#define _GUARD_DORV_NO_DICT_r11 1013 -#define _GUARD_DORV_NO_DICT_r22 1014 -#define _GUARD_DORV_NO_DICT_r33 1015 -#define _GUARD_GLOBALS_VERSION_r00 1016 -#define _GUARD_GLOBALS_VERSION_r11 1017 -#define _GUARD_GLOBALS_VERSION_r22 1018 -#define _GUARD_GLOBALS_VERSION_r33 1019 -#define _GUARD_IP_RETURN_GENERATOR_r00 1020 -#define _GUARD_IP_RETURN_GENERATOR_r11 1021 -#define _GUARD_IP_RETURN_GENERATOR_r22 1022 -#define _GUARD_IP_RETURN_GENERATOR_r33 1023 -#define _GUARD_IP_RETURN_VALUE_r00 1024 -#define _GUARD_IP_RETURN_VALUE_r11 1025 -#define _GUARD_IP_RETURN_VALUE_r22 1026 -#define _GUARD_IP_RETURN_VALUE_r33 1027 -#define _GUARD_IP_YIELD_VALUE_r00 1028 -#define _GUARD_IP_YIELD_VALUE_r11 1029 -#define _GUARD_IP_YIELD_VALUE_r22 1030 -#define _GUARD_IP_YIELD_VALUE_r33 1031 -#define _GUARD_IP__PUSH_FRAME_r00 1032 -#define _GUARD_IP__PUSH_FRAME_r11 1033 -#define _GUARD_IP__PUSH_FRAME_r22 1034 -#define _GUARD_IP__PUSH_FRAME_r33 1035 -#define _GUARD_IS_FALSE_POP_r00 1036 -#define _GUARD_IS_FALSE_POP_r10 1037 -#define _GUARD_IS_FALSE_POP_r21 1038 -#define _GUARD_IS_FALSE_POP_r32 1039 -#define _GUARD_IS_NONE_POP_r00 1040 -#define _GUARD_IS_NONE_POP_r10 1041 -#define _GUARD_IS_NONE_POP_r21 1042 -#define _GUARD_IS_NONE_POP_r32 1043 -#define _GUARD_IS_NOT_NONE_POP_r10 1044 -#define _GUARD_IS_TRUE_POP_r00 1045 -#define _GUARD_IS_TRUE_POP_r10 1046 -#define _GUARD_IS_TRUE_POP_r21 1047 -#define _GUARD_IS_TRUE_POP_r32 1048 -#define _GUARD_ITERATOR_r01 1049 -#define _GUARD_ITERATOR_r11 1050 -#define _GUARD_ITERATOR_r22 1051 -#define _GUARD_ITERATOR_r33 1052 -#define _GUARD_ITER_VIRTUAL_r01 1053 -#define _GUARD_ITER_VIRTUAL_r11 1054 -#define _GUARD_ITER_VIRTUAL_r22 1055 -#define _GUARD_ITER_VIRTUAL_r33 1056 -#define _GUARD_KEYS_VERSION_r01 1057 -#define _GUARD_KEYS_VERSION_r11 1058 -#define _GUARD_KEYS_VERSION_r22 1059 -#define _GUARD_KEYS_VERSION_r33 1060 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r03 1061 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r13 1062 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r23 1063 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r33 1064 -#define _GUARD_NOS_COMPACT_ASCII_r02 1065 -#define _GUARD_NOS_COMPACT_ASCII_r12 1066 -#define _GUARD_NOS_COMPACT_ASCII_r22 1067 -#define _GUARD_NOS_COMPACT_ASCII_r33 1068 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 1069 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 1070 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 1071 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 1072 -#define _GUARD_NOS_DICT_SUBSCRIPT_r02 1073 -#define _GUARD_NOS_DICT_SUBSCRIPT_r12 1074 -#define _GUARD_NOS_DICT_SUBSCRIPT_r22 1075 -#define _GUARD_NOS_DICT_SUBSCRIPT_r33 1076 -#define _GUARD_NOS_FLOAT_r02 1077 -#define _GUARD_NOS_FLOAT_r12 1078 -#define _GUARD_NOS_FLOAT_r22 1079 -#define _GUARD_NOS_FLOAT_r33 1080 -#define _GUARD_NOS_INT_r02 1081 -#define _GUARD_NOS_INT_r12 1082 -#define _GUARD_NOS_INT_r22 1083 -#define _GUARD_NOS_INT_r33 1084 -#define _GUARD_NOS_ITER_VIRTUAL_r02 1085 -#define _GUARD_NOS_ITER_VIRTUAL_r12 1086 -#define _GUARD_NOS_ITER_VIRTUAL_r22 1087 -#define _GUARD_NOS_ITER_VIRTUAL_r33 1088 -#define _GUARD_NOS_LIST_r02 1089 -#define _GUARD_NOS_LIST_r12 1090 -#define _GUARD_NOS_LIST_r22 1091 -#define _GUARD_NOS_LIST_r33 1092 -#define _GUARD_NOS_NOT_NULL_r02 1093 -#define _GUARD_NOS_NOT_NULL_r12 1094 -#define _GUARD_NOS_NOT_NULL_r22 1095 -#define _GUARD_NOS_NOT_NULL_r33 1096 -#define _GUARD_NOS_NULL_r02 1097 -#define _GUARD_NOS_NULL_r12 1098 -#define _GUARD_NOS_NULL_r22 1099 -#define _GUARD_NOS_NULL_r33 1100 -#define _GUARD_NOS_OVERFLOWED_r02 1101 -#define _GUARD_NOS_OVERFLOWED_r12 1102 -#define _GUARD_NOS_OVERFLOWED_r22 1103 -#define _GUARD_NOS_OVERFLOWED_r33 1104 -#define _GUARD_NOS_TUPLE_r02 1105 -#define _GUARD_NOS_TUPLE_r12 1106 -#define _GUARD_NOS_TUPLE_r22 1107 -#define _GUARD_NOS_TUPLE_r33 1108 -#define _GUARD_NOS_TYPE_VERSION_r02 1109 -#define _GUARD_NOS_TYPE_VERSION_r12 1110 -#define _GUARD_NOS_TYPE_VERSION_r22 1111 -#define _GUARD_NOS_TYPE_VERSION_r33 1112 -#define _GUARD_NOS_UNICODE_r02 1113 -#define _GUARD_NOS_UNICODE_r12 1114 -#define _GUARD_NOS_UNICODE_r22 1115 -#define _GUARD_NOS_UNICODE_r33 1116 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 1117 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 1118 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 1119 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 1120 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 1121 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 1122 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 1123 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 1124 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 1125 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 1126 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 1127 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 1128 -#define _GUARD_THIRD_NULL_r03 1129 -#define _GUARD_THIRD_NULL_r13 1130 -#define _GUARD_THIRD_NULL_r23 1131 -#define _GUARD_THIRD_NULL_r33 1132 -#define _GUARD_TOS_ANY_DICT_r01 1133 -#define _GUARD_TOS_ANY_DICT_r11 1134 -#define _GUARD_TOS_ANY_DICT_r22 1135 -#define _GUARD_TOS_ANY_DICT_r33 1136 -#define _GUARD_TOS_ANY_SET_r01 1137 -#define _GUARD_TOS_ANY_SET_r11 1138 -#define _GUARD_TOS_ANY_SET_r22 1139 -#define _GUARD_TOS_ANY_SET_r33 1140 -#define _GUARD_TOS_DICT_r01 1141 -#define _GUARD_TOS_DICT_r11 1142 -#define _GUARD_TOS_DICT_r22 1143 -#define _GUARD_TOS_DICT_r33 1144 -#define _GUARD_TOS_FLOAT_r01 1145 -#define _GUARD_TOS_FLOAT_r11 1146 -#define _GUARD_TOS_FLOAT_r22 1147 -#define _GUARD_TOS_FLOAT_r33 1148 -#define _GUARD_TOS_FROZENDICT_r01 1149 -#define _GUARD_TOS_FROZENDICT_r11 1150 -#define _GUARD_TOS_FROZENDICT_r22 1151 -#define _GUARD_TOS_FROZENDICT_r33 1152 -#define _GUARD_TOS_FROZENSET_r01 1153 -#define _GUARD_TOS_FROZENSET_r11 1154 -#define _GUARD_TOS_FROZENSET_r22 1155 -#define _GUARD_TOS_FROZENSET_r33 1156 -#define _GUARD_TOS_INT_r01 1157 -#define _GUARD_TOS_INT_r11 1158 -#define _GUARD_TOS_INT_r22 1159 -#define _GUARD_TOS_INT_r33 1160 -#define _GUARD_TOS_IS_NONE_r01 1161 -#define _GUARD_TOS_IS_NONE_r11 1162 -#define _GUARD_TOS_IS_NONE_r22 1163 -#define _GUARD_TOS_IS_NONE_r33 1164 -#define _GUARD_TOS_LIST_r01 1165 -#define _GUARD_TOS_LIST_r11 1166 -#define _GUARD_TOS_LIST_r22 1167 -#define _GUARD_TOS_LIST_r33 1168 -#define _GUARD_TOS_NOT_NULL_r01 1169 -#define _GUARD_TOS_NOT_NULL_r11 1170 -#define _GUARD_TOS_NOT_NULL_r22 1171 -#define _GUARD_TOS_NOT_NULL_r33 1172 -#define _GUARD_TOS_OVERFLOWED_r01 1173 -#define _GUARD_TOS_OVERFLOWED_r11 1174 -#define _GUARD_TOS_OVERFLOWED_r22 1175 -#define _GUARD_TOS_OVERFLOWED_r33 1176 -#define _GUARD_TOS_SET_r01 1177 -#define _GUARD_TOS_SET_r11 1178 -#define _GUARD_TOS_SET_r22 1179 -#define _GUARD_TOS_SET_r33 1180 -#define _GUARD_TOS_SLICE_r01 1181 -#define _GUARD_TOS_SLICE_r11 1182 -#define _GUARD_TOS_SLICE_r22 1183 -#define _GUARD_TOS_SLICE_r33 1184 -#define _GUARD_TOS_TUPLE_r01 1185 -#define _GUARD_TOS_TUPLE_r11 1186 -#define _GUARD_TOS_TUPLE_r22 1187 -#define _GUARD_TOS_TUPLE_r33 1188 -#define _GUARD_TOS_UNICODE_r01 1189 -#define _GUARD_TOS_UNICODE_r11 1190 -#define _GUARD_TOS_UNICODE_r22 1191 -#define _GUARD_TOS_UNICODE_r33 1192 -#define _GUARD_TYPE_r01 1193 -#define _GUARD_TYPE_r11 1194 -#define _GUARD_TYPE_r22 1195 -#define _GUARD_TYPE_r33 1196 -#define _GUARD_TYPE_ITER_r02 1197 -#define _GUARD_TYPE_ITER_r12 1198 -#define _GUARD_TYPE_ITER_r22 1199 -#define _GUARD_TYPE_ITER_r33 1200 -#define _GUARD_TYPE_VERSION_r01 1201 -#define _GUARD_TYPE_VERSION_r11 1202 -#define _GUARD_TYPE_VERSION_r22 1203 -#define _GUARD_TYPE_VERSION_r33 1204 -#define _GUARD_TYPE_VERSION_LOCKED_r01 1205 -#define _GUARD_TYPE_VERSION_LOCKED_r11 1206 -#define _GUARD_TYPE_VERSION_LOCKED_r22 1207 -#define _GUARD_TYPE_VERSION_LOCKED_r33 1208 -#define _HANDLE_PENDING_AND_DEOPT_r00 1209 -#define _HANDLE_PENDING_AND_DEOPT_r10 1210 -#define _HANDLE_PENDING_AND_DEOPT_r20 1211 -#define _HANDLE_PENDING_AND_DEOPT_r30 1212 -#define _IMPORT_FROM_r12 1213 -#define _IMPORT_NAME_r21 1214 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1215 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1216 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1217 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1218 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1219 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1220 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1221 -#define _INSERT_NULL_r10 1222 -#define _INSTRUMENTED_FOR_ITER_r23 1223 -#define _INSTRUMENTED_INSTRUCTION_r00 1224 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1225 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1226 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1227 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1228 -#define _INSTRUMENTED_LINE_r00 1229 -#define _INSTRUMENTED_NOT_TAKEN_r00 1230 -#define _INSTRUMENTED_NOT_TAKEN_r11 1231 -#define _INSTRUMENTED_NOT_TAKEN_r22 1232 -#define _INSTRUMENTED_NOT_TAKEN_r33 1233 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1234 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1235 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1236 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1237 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1238 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1239 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1240 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1241 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1242 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1243 -#define _IS_NONE_r11 1244 -#define _IS_OP_r03 1245 -#define _IS_OP_r13 1246 -#define _IS_OP_r23 1247 -#define _ITER_CHECK_LIST_r02 1248 -#define _ITER_CHECK_LIST_r12 1249 -#define _ITER_CHECK_LIST_r22 1250 -#define _ITER_CHECK_LIST_r33 1251 -#define _ITER_CHECK_RANGE_r02 1252 -#define _ITER_CHECK_RANGE_r12 1253 -#define _ITER_CHECK_RANGE_r22 1254 -#define _ITER_CHECK_RANGE_r33 1255 -#define _ITER_CHECK_TUPLE_r02 1256 -#define _ITER_CHECK_TUPLE_r12 1257 -#define _ITER_CHECK_TUPLE_r22 1258 -#define _ITER_CHECK_TUPLE_r33 1259 -#define _ITER_JUMP_LIST_r02 1260 -#define _ITER_JUMP_LIST_r12 1261 -#define _ITER_JUMP_LIST_r22 1262 -#define _ITER_JUMP_LIST_r33 1263 -#define _ITER_JUMP_RANGE_r02 1264 -#define _ITER_JUMP_RANGE_r12 1265 -#define _ITER_JUMP_RANGE_r22 1266 -#define _ITER_JUMP_RANGE_r33 1267 -#define _ITER_JUMP_TUPLE_r02 1268 -#define _ITER_JUMP_TUPLE_r12 1269 -#define _ITER_JUMP_TUPLE_r22 1270 -#define _ITER_JUMP_TUPLE_r33 1271 -#define _ITER_NEXT_INLINE_r23 1272 -#define _ITER_NEXT_LIST_r23 1273 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1274 -#define _ITER_NEXT_RANGE_r03 1275 -#define _ITER_NEXT_RANGE_r13 1276 -#define _ITER_NEXT_RANGE_r23 1277 -#define _ITER_NEXT_TUPLE_r03 1278 -#define _ITER_NEXT_TUPLE_r13 1279 -#define _ITER_NEXT_TUPLE_r23 1280 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1281 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1282 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1283 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1284 -#define _JUMP_TO_TOP_r00 1285 -#define _LIST_APPEND_r10 1286 -#define _LIST_EXTEND_r11 1287 -#define _LOAD_ATTR_r10 1288 -#define _LOAD_ATTR_CLASS_r11 1289 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME_r11 1290 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1291 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1292 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1293 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1294 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1295 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1296 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1297 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1298 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1299 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1300 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1301 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1302 -#define _LOAD_ATTR_MODULE_r12 1303 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1304 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1305 -#define _LOAD_ATTR_PROPERTY_FRAME_r01 1306 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1307 -#define _LOAD_ATTR_PROPERTY_FRAME_r22 1308 -#define _LOAD_ATTR_PROPERTY_FRAME_r33 1309 -#define _LOAD_ATTR_SLOT_r02 1310 -#define _LOAD_ATTR_SLOT_r12 1311 -#define _LOAD_ATTR_SLOT_r23 1312 -#define _LOAD_ATTR_WITH_HINT_r12 1313 -#define _LOAD_BUILD_CLASS_r01 1314 -#define _LOAD_BYTECODE_r00 1315 -#define _LOAD_COMMON_CONSTANT_r01 1316 -#define _LOAD_COMMON_CONSTANT_r12 1317 -#define _LOAD_COMMON_CONSTANT_r23 1318 -#define _LOAD_CONST_r01 1319 -#define _LOAD_CONST_r12 1320 -#define _LOAD_CONST_r23 1321 -#define _LOAD_CONST_INLINE_r01 1322 -#define _LOAD_CONST_INLINE_r12 1323 -#define _LOAD_CONST_INLINE_r23 1324 -#define _LOAD_CONST_INLINE_BORROW_r01 1325 -#define _LOAD_CONST_INLINE_BORROW_r12 1326 -#define _LOAD_CONST_INLINE_BORROW_r23 1327 -#define _LOAD_DEREF_r01 1328 -#define _LOAD_FAST_r01 1329 -#define _LOAD_FAST_r12 1330 -#define _LOAD_FAST_r23 1331 -#define _LOAD_FAST_0_r01 1332 -#define _LOAD_FAST_0_r12 1333 -#define _LOAD_FAST_0_r23 1334 -#define _LOAD_FAST_1_r01 1335 -#define _LOAD_FAST_1_r12 1336 -#define _LOAD_FAST_1_r23 1337 -#define _LOAD_FAST_2_r01 1338 -#define _LOAD_FAST_2_r12 1339 -#define _LOAD_FAST_2_r23 1340 -#define _LOAD_FAST_3_r01 1341 -#define _LOAD_FAST_3_r12 1342 -#define _LOAD_FAST_3_r23 1343 -#define _LOAD_FAST_4_r01 1344 -#define _LOAD_FAST_4_r12 1345 -#define _LOAD_FAST_4_r23 1346 -#define _LOAD_FAST_5_r01 1347 -#define _LOAD_FAST_5_r12 1348 -#define _LOAD_FAST_5_r23 1349 -#define _LOAD_FAST_6_r01 1350 -#define _LOAD_FAST_6_r12 1351 -#define _LOAD_FAST_6_r23 1352 -#define _LOAD_FAST_7_r01 1353 -#define _LOAD_FAST_7_r12 1354 -#define _LOAD_FAST_7_r23 1355 -#define _LOAD_FAST_AND_CLEAR_r01 1356 -#define _LOAD_FAST_AND_CLEAR_r12 1357 -#define _LOAD_FAST_AND_CLEAR_r23 1358 -#define _LOAD_FAST_BORROW_r01 1359 -#define _LOAD_FAST_BORROW_r12 1360 -#define _LOAD_FAST_BORROW_r23 1361 -#define _LOAD_FAST_BORROW_0_r01 1362 -#define _LOAD_FAST_BORROW_0_r12 1363 -#define _LOAD_FAST_BORROW_0_r23 1364 -#define _LOAD_FAST_BORROW_1_r01 1365 -#define _LOAD_FAST_BORROW_1_r12 1366 -#define _LOAD_FAST_BORROW_1_r23 1367 -#define _LOAD_FAST_BORROW_2_r01 1368 -#define _LOAD_FAST_BORROW_2_r12 1369 -#define _LOAD_FAST_BORROW_2_r23 1370 -#define _LOAD_FAST_BORROW_3_r01 1371 -#define _LOAD_FAST_BORROW_3_r12 1372 -#define _LOAD_FAST_BORROW_3_r23 1373 -#define _LOAD_FAST_BORROW_4_r01 1374 -#define _LOAD_FAST_BORROW_4_r12 1375 -#define _LOAD_FAST_BORROW_4_r23 1376 -#define _LOAD_FAST_BORROW_5_r01 1377 -#define _LOAD_FAST_BORROW_5_r12 1378 -#define _LOAD_FAST_BORROW_5_r23 1379 -#define _LOAD_FAST_BORROW_6_r01 1380 -#define _LOAD_FAST_BORROW_6_r12 1381 -#define _LOAD_FAST_BORROW_6_r23 1382 -#define _LOAD_FAST_BORROW_7_r01 1383 -#define _LOAD_FAST_BORROW_7_r12 1384 -#define _LOAD_FAST_BORROW_7_r23 1385 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1386 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1387 -#define _LOAD_FAST_CHECK_r01 1388 -#define _LOAD_FAST_CHECK_r12 1389 -#define _LOAD_FAST_CHECK_r23 1390 -#define _LOAD_FAST_LOAD_FAST_r02 1391 -#define _LOAD_FAST_LOAD_FAST_r13 1392 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1393 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1394 -#define _LOAD_GLOBAL_r00 1395 -#define _LOAD_GLOBAL_BUILTINS_r01 1396 -#define _LOAD_GLOBAL_MODULE_r01 1397 -#define _LOAD_LOCALS_r01 1398 -#define _LOAD_LOCALS_r12 1399 -#define _LOAD_LOCALS_r23 1400 -#define _LOAD_NAME_r01 1401 -#define _LOAD_SMALL_INT_r01 1402 -#define _LOAD_SMALL_INT_r12 1403 -#define _LOAD_SMALL_INT_r23 1404 -#define _LOAD_SMALL_INT_0_r01 1405 -#define _LOAD_SMALL_INT_0_r12 1406 -#define _LOAD_SMALL_INT_0_r23 1407 -#define _LOAD_SMALL_INT_1_r01 1408 -#define _LOAD_SMALL_INT_1_r12 1409 -#define _LOAD_SMALL_INT_1_r23 1410 -#define _LOAD_SMALL_INT_2_r01 1411 -#define _LOAD_SMALL_INT_2_r12 1412 -#define _LOAD_SMALL_INT_2_r23 1413 -#define _LOAD_SMALL_INT_3_r01 1414 -#define _LOAD_SMALL_INT_3_r12 1415 -#define _LOAD_SMALL_INT_3_r23 1416 -#define _LOAD_SPECIAL_r00 1417 -#define _LOAD_SUPER_ATTR_ATTR_r31 1418 -#define _LOAD_SUPER_ATTR_METHOD_r32 1419 -#define _LOCK_OBJECT_r01 1420 -#define _LOCK_OBJECT_r11 1421 -#define _LOCK_OBJECT_r22 1422 -#define _LOCK_OBJECT_r33 1423 -#define _MAKE_CALLARGS_A_TUPLE_r33 1424 -#define _MAKE_CELL_r00 1425 -#define _MAKE_FUNCTION_r12 1426 -#define _MAKE_HEAP_SAFE_r01 1427 -#define _MAKE_HEAP_SAFE_r11 1428 -#define _MAKE_HEAP_SAFE_r22 1429 -#define _MAKE_HEAP_SAFE_r33 1430 -#define _MAKE_WARM_r00 1431 -#define _MAKE_WARM_r11 1432 -#define _MAKE_WARM_r22 1433 -#define _MAKE_WARM_r33 1434 -#define _MAP_ADD_r20 1435 -#define _MATCH_CLASS_r33 1436 -#define _MATCH_KEYS_r23 1437 -#define _MATCH_MAPPING_r02 1438 -#define _MATCH_MAPPING_r12 1439 -#define _MATCH_MAPPING_r23 1440 -#define _MATCH_SEQUENCE_r02 1441 -#define _MATCH_SEQUENCE_r12 1442 -#define _MATCH_SEQUENCE_r23 1443 -#define _MAYBE_EXPAND_METHOD_r00 1444 -#define _MAYBE_EXPAND_METHOD_KW_r11 1445 -#define _MONITOR_CALL_r00 1446 -#define _MONITOR_CALL_KW_r11 1447 -#define _MONITOR_JUMP_BACKWARD_r00 1448 -#define _MONITOR_JUMP_BACKWARD_r11 1449 -#define _MONITOR_JUMP_BACKWARD_r22 1450 -#define _MONITOR_JUMP_BACKWARD_r33 1451 -#define _MONITOR_RESUME_r00 1452 -#define _NOP_r00 1453 -#define _NOP_r11 1454 -#define _NOP_r22 1455 -#define _NOP_r33 1456 -#define _POP_EXCEPT_r10 1457 -#define _POP_ITER_r20 1458 -#define _POP_JUMP_IF_FALSE_r00 1459 -#define _POP_JUMP_IF_FALSE_r10 1460 -#define _POP_JUMP_IF_FALSE_r21 1461 -#define _POP_JUMP_IF_FALSE_r32 1462 -#define _POP_JUMP_IF_TRUE_r00 1463 -#define _POP_JUMP_IF_TRUE_r10 1464 -#define _POP_JUMP_IF_TRUE_r21 1465 -#define _POP_JUMP_IF_TRUE_r32 1466 -#define _POP_TOP_r10 1467 -#define _POP_TOP_FLOAT_r00 1468 -#define _POP_TOP_FLOAT_r10 1469 -#define _POP_TOP_FLOAT_r21 1470 -#define _POP_TOP_FLOAT_r32 1471 -#define _POP_TOP_INT_r00 1472 -#define _POP_TOP_INT_r10 1473 -#define _POP_TOP_INT_r21 1474 -#define _POP_TOP_INT_r32 1475 -#define _POP_TOP_NOP_r00 1476 -#define _POP_TOP_NOP_r10 1477 -#define _POP_TOP_NOP_r21 1478 -#define _POP_TOP_NOP_r32 1479 -#define _POP_TOP_OPARG_r00 1480 -#define _POP_TOP_UNICODE_r00 1481 -#define _POP_TOP_UNICODE_r10 1482 -#define _POP_TOP_UNICODE_r21 1483 -#define _POP_TOP_UNICODE_r32 1484 -#define _PUSH_EXC_INFO_r02 1485 -#define _PUSH_EXC_INFO_r12 1486 -#define _PUSH_EXC_INFO_r23 1487 -#define _PUSH_FRAME_r10 1488 -#define _PUSH_NULL_r01 1489 -#define _PUSH_NULL_r12 1490 -#define _PUSH_NULL_r23 1491 -#define _PUSH_NULL_CONDITIONAL_r00 1492 -#define _PUSH_TAGGED_ZERO_r01 1493 -#define _PUSH_TAGGED_ZERO_r12 1494 -#define _PUSH_TAGGED_ZERO_r23 1495 -#define _PY_FRAME_EX_r31 1496 -#define _PY_FRAME_GENERAL_r01 1497 -#define _PY_FRAME_KW_r11 1498 -#define _REPLACE_WITH_TRUE_r02 1499 -#define _REPLACE_WITH_TRUE_r12 1500 -#define _REPLACE_WITH_TRUE_r23 1501 -#define _RESUME_CHECK_r00 1502 -#define _RESUME_CHECK_r11 1503 -#define _RESUME_CHECK_r22 1504 -#define _RESUME_CHECK_r33 1505 -#define _RETURN_GENERATOR_r01 1506 -#define _RETURN_VALUE_r11 1507 -#define _RROT_3_r03 1508 -#define _RROT_3_r13 1509 -#define _RROT_3_r23 1510 -#define _RROT_3_r33 1511 -#define _SAVE_RETURN_OFFSET_r00 1512 -#define _SAVE_RETURN_OFFSET_r11 1513 -#define _SAVE_RETURN_OFFSET_r22 1514 -#define _SAVE_RETURN_OFFSET_r33 1515 -#define _SEND_ASYNC_GEN_r33 1516 -#define _SEND_ASYNC_GEN_TIER_TWO_r33 1517 -#define _SEND_GEN_FRAME_r33 1518 -#define _SEND_VIRTUAL_r33 1519 -#define _SEND_VIRTUAL_TIER_TWO_r03 1520 -#define _SEND_VIRTUAL_TIER_TWO_r13 1521 -#define _SEND_VIRTUAL_TIER_TWO_r23 1522 -#define _SEND_VIRTUAL_TIER_TWO_r33 1523 -#define _SETUP_ANNOTATIONS_r00 1524 -#define _SET_ADD_r10 1525 -#define _SET_FUNCTION_ATTRIBUTE_r01 1526 -#define _SET_FUNCTION_ATTRIBUTE_r11 1527 -#define _SET_FUNCTION_ATTRIBUTE_r21 1528 -#define _SET_FUNCTION_ATTRIBUTE_r32 1529 -#define _SET_IP_r00 1530 -#define _SET_IP_r11 1531 -#define _SET_IP_r22 1532 -#define _SET_IP_r33 1533 -#define _SET_UPDATE_r11 1534 -#define _SPILL_OR_RELOAD_r01 1535 -#define _SPILL_OR_RELOAD_r02 1536 -#define _SPILL_OR_RELOAD_r03 1537 -#define _SPILL_OR_RELOAD_r10 1538 -#define _SPILL_OR_RELOAD_r12 1539 -#define _SPILL_OR_RELOAD_r13 1540 -#define _SPILL_OR_RELOAD_r20 1541 -#define _SPILL_OR_RELOAD_r21 1542 -#define _SPILL_OR_RELOAD_r23 1543 -#define _SPILL_OR_RELOAD_r30 1544 -#define _SPILL_OR_RELOAD_r31 1545 -#define _SPILL_OR_RELOAD_r32 1546 -#define _START_EXECUTOR_r00 1547 -#define _STORE_ATTR_r20 1548 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1549 -#define _STORE_ATTR_SLOT_r21 1550 -#define _STORE_ATTR_WITH_HINT_r21 1551 -#define _STORE_DEREF_r10 1552 -#define _STORE_FAST_LOAD_FAST_r11 1553 -#define _STORE_FAST_STORE_FAST_r20 1554 -#define _STORE_GLOBAL_r10 1555 -#define _STORE_NAME_r10 1556 -#define _STORE_SLICE_r30 1557 -#define _STORE_SUBSCR_r30 1558 -#define _STORE_SUBSCR_DICT_r31 1559 -#define _STORE_SUBSCR_DICT_KNOWN_HASH_r31 1560 -#define _STORE_SUBSCR_LIST_INT_r32 1561 -#define _SWAP_r11 1562 -#define _SWAP_2_r02 1563 -#define _SWAP_2_r12 1564 -#define _SWAP_2_r22 1565 -#define _SWAP_2_r33 1566 -#define _SWAP_3_r03 1567 -#define _SWAP_3_r13 1568 -#define _SWAP_3_r23 1569 -#define _SWAP_3_r33 1570 -#define _SWAP_FAST_r01 1571 -#define _SWAP_FAST_r11 1572 -#define _SWAP_FAST_r22 1573 -#define _SWAP_FAST_r33 1574 -#define _SWAP_FAST_0_r01 1575 -#define _SWAP_FAST_0_r11 1576 -#define _SWAP_FAST_0_r22 1577 -#define _SWAP_FAST_0_r33 1578 -#define _SWAP_FAST_1_r01 1579 -#define _SWAP_FAST_1_r11 1580 -#define _SWAP_FAST_1_r22 1581 -#define _SWAP_FAST_1_r33 1582 -#define _SWAP_FAST_2_r01 1583 -#define _SWAP_FAST_2_r11 1584 -#define _SWAP_FAST_2_r22 1585 -#define _SWAP_FAST_2_r33 1586 -#define _SWAP_FAST_3_r01 1587 -#define _SWAP_FAST_3_r11 1588 -#define _SWAP_FAST_3_r22 1589 -#define _SWAP_FAST_3_r33 1590 -#define _SWAP_FAST_4_r01 1591 -#define _SWAP_FAST_4_r11 1592 -#define _SWAP_FAST_4_r22 1593 -#define _SWAP_FAST_4_r33 1594 -#define _SWAP_FAST_5_r01 1595 -#define _SWAP_FAST_5_r11 1596 -#define _SWAP_FAST_5_r22 1597 -#define _SWAP_FAST_5_r33 1598 -#define _SWAP_FAST_6_r01 1599 -#define _SWAP_FAST_6_r11 1600 -#define _SWAP_FAST_6_r22 1601 -#define _SWAP_FAST_6_r33 1602 -#define _SWAP_FAST_7_r01 1603 -#define _SWAP_FAST_7_r11 1604 -#define _SWAP_FAST_7_r22 1605 -#define _SWAP_FAST_7_r33 1606 -#define _TIER2_RESUME_CHECK_r00 1607 -#define _TIER2_RESUME_CHECK_r11 1608 -#define _TIER2_RESUME_CHECK_r22 1609 -#define _TIER2_RESUME_CHECK_r33 1610 -#define _TO_BOOL_r11 1611 -#define _TO_BOOL_BOOL_r01 1612 -#define _TO_BOOL_BOOL_r11 1613 -#define _TO_BOOL_BOOL_r22 1614 -#define _TO_BOOL_BOOL_r33 1615 -#define _TO_BOOL_INT_r02 1616 -#define _TO_BOOL_INT_r12 1617 -#define _TO_BOOL_INT_r23 1618 -#define _TO_BOOL_LIST_r02 1619 -#define _TO_BOOL_LIST_r12 1620 -#define _TO_BOOL_LIST_r23 1621 -#define _TO_BOOL_NONE_r01 1622 -#define _TO_BOOL_NONE_r11 1623 -#define _TO_BOOL_NONE_r22 1624 -#define _TO_BOOL_NONE_r33 1625 -#define _TO_BOOL_STR_r02 1626 -#define _TO_BOOL_STR_r12 1627 -#define _TO_BOOL_STR_r23 1628 -#define _TRACE_RECORD_r00 1629 -#define _UNARY_INVERT_r12 1630 -#define _UNARY_NEGATIVE_r12 1631 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r02 1632 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r12 1633 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r23 1634 -#define _UNARY_NOT_r01 1635 -#define _UNARY_NOT_r11 1636 -#define _UNARY_NOT_r22 1637 -#define _UNARY_NOT_r33 1638 -#define _UNPACK_EX_r10 1639 -#define _UNPACK_SEQUENCE_r10 1640 -#define _UNPACK_SEQUENCE_LIST_r10 1641 -#define _UNPACK_SEQUENCE_TUPLE_r10 1642 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1643 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1644 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1645 -#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1646 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1647 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1648 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1649 -#define _WITH_EXCEPT_START_r33 1650 -#define _YIELD_VALUE_r11 1651 -#define MAX_UOP_REGS_ID 1651 +#define _DELETE_DEREF_r00 861 +#define _DELETE_FAST_r00 862 +#define _DELETE_SUBSCR_r20 863 +#define _DEOPT_r00 864 +#define _DEOPT_r10 865 +#define _DEOPT_r20 866 +#define _DEOPT_r30 867 +#define _DICT_MERGE_r11 868 +#define _DICT_UPDATE_r11 869 +#define _DO_CALL_r01 870 +#define _DO_CALL_FUNCTION_EX_r31 871 +#define _DO_CALL_KW_r11 872 +#define _DYNAMIC_EXIT_r00 873 +#define _DYNAMIC_EXIT_r10 874 +#define _DYNAMIC_EXIT_r20 875 +#define _DYNAMIC_EXIT_r30 876 +#define _END_FOR_r10 877 +#define _END_SEND_r31 878 +#define _ERROR_POP_N_r00 879 +#define _EXIT_INIT_CHECK_r10 880 +#define _EXIT_TRACE_r00 881 +#define _EXIT_TRACE_r10 882 +#define _EXIT_TRACE_r20 883 +#define _EXIT_TRACE_r30 884 +#define _EXPAND_METHOD_r00 885 +#define _EXPAND_METHOD_KW_r11 886 +#define _FATAL_ERROR_r00 887 +#define _FATAL_ERROR_r11 888 +#define _FATAL_ERROR_r22 889 +#define _FATAL_ERROR_r33 890 +#define _FORMAT_SIMPLE_r11 891 +#define _FORMAT_WITH_SPEC_r21 892 +#define _FOR_ITER_r23 893 +#define _FOR_ITER_GEN_FRAME_r03 894 +#define _FOR_ITER_GEN_FRAME_r13 895 +#define _FOR_ITER_GEN_FRAME_r23 896 +#define _FOR_ITER_TIER_TWO_r23 897 +#define _FOR_ITER_VIRTUAL_r23 898 +#define _FOR_ITER_VIRTUAL_TIER_TWO_r23 899 +#define _GET_AITER_r11 900 +#define _GET_ANEXT_r12 901 +#define _GET_AWAITABLE_r11 902 +#define _GET_ITER_r12 903 +#define _GET_ITER_TRAD_r12 904 +#define _GET_LEN_r12 905 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r03 906 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r13 907 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r23 908 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r33 909 +#define _GUARD_BINARY_OP_EXTEND_r22 910 +#define _GUARD_BINARY_OP_EXTEND_LHS_r02 911 +#define _GUARD_BINARY_OP_EXTEND_LHS_r12 912 +#define _GUARD_BINARY_OP_EXTEND_LHS_r22 913 +#define _GUARD_BINARY_OP_EXTEND_LHS_r33 914 +#define _GUARD_BINARY_OP_EXTEND_RHS_r02 915 +#define _GUARD_BINARY_OP_EXTEND_RHS_r12 916 +#define _GUARD_BINARY_OP_EXTEND_RHS_r22 917 +#define _GUARD_BINARY_OP_EXTEND_RHS_r33 918 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 919 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 920 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 921 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 922 +#define _GUARD_BIT_IS_SET_POP_r00 923 +#define _GUARD_BIT_IS_SET_POP_r10 924 +#define _GUARD_BIT_IS_SET_POP_r21 925 +#define _GUARD_BIT_IS_SET_POP_r32 926 +#define _GUARD_BIT_IS_SET_POP_4_r00 927 +#define _GUARD_BIT_IS_SET_POP_4_r10 928 +#define _GUARD_BIT_IS_SET_POP_4_r21 929 +#define _GUARD_BIT_IS_SET_POP_4_r32 930 +#define _GUARD_BIT_IS_SET_POP_5_r00 931 +#define _GUARD_BIT_IS_SET_POP_5_r10 932 +#define _GUARD_BIT_IS_SET_POP_5_r21 933 +#define _GUARD_BIT_IS_SET_POP_5_r32 934 +#define _GUARD_BIT_IS_SET_POP_6_r00 935 +#define _GUARD_BIT_IS_SET_POP_6_r10 936 +#define _GUARD_BIT_IS_SET_POP_6_r21 937 +#define _GUARD_BIT_IS_SET_POP_6_r32 938 +#define _GUARD_BIT_IS_SET_POP_7_r00 939 +#define _GUARD_BIT_IS_SET_POP_7_r10 940 +#define _GUARD_BIT_IS_SET_POP_7_r21 941 +#define _GUARD_BIT_IS_SET_POP_7_r32 942 +#define _GUARD_BIT_IS_UNSET_POP_r00 943 +#define _GUARD_BIT_IS_UNSET_POP_r10 944 +#define _GUARD_BIT_IS_UNSET_POP_r21 945 +#define _GUARD_BIT_IS_UNSET_POP_r32 946 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 947 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 948 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 949 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 950 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 951 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 952 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 953 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 954 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 955 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 956 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 957 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 958 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 959 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 960 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 961 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 962 +#define _GUARD_CALLABLE_BUILTIN_CLASS_r00 963 +#define _GUARD_CALLABLE_BUILTIN_FAST_r00 964 +#define _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS_r00 965 +#define _GUARD_CALLABLE_BUILTIN_O_r00 966 +#define _GUARD_CALLABLE_ISINSTANCE_r03 967 +#define _GUARD_CALLABLE_ISINSTANCE_r13 968 +#define _GUARD_CALLABLE_ISINSTANCE_r23 969 +#define _GUARD_CALLABLE_ISINSTANCE_r33 970 +#define _GUARD_CALLABLE_LEN_r03 971 +#define _GUARD_CALLABLE_LEN_r13 972 +#define _GUARD_CALLABLE_LEN_r23 973 +#define _GUARD_CALLABLE_LEN_r33 974 +#define _GUARD_CALLABLE_LIST_APPEND_r03 975 +#define _GUARD_CALLABLE_LIST_APPEND_r13 976 +#define _GUARD_CALLABLE_LIST_APPEND_r23 977 +#define _GUARD_CALLABLE_LIST_APPEND_r33 978 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_r00 979 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 980 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS_r00 981 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_O_r00 982 +#define _GUARD_CALLABLE_STR_1_r03 983 +#define _GUARD_CALLABLE_STR_1_r13 984 +#define _GUARD_CALLABLE_STR_1_r23 985 +#define _GUARD_CALLABLE_STR_1_r33 986 +#define _GUARD_CALLABLE_TUPLE_1_r03 987 +#define _GUARD_CALLABLE_TUPLE_1_r13 988 +#define _GUARD_CALLABLE_TUPLE_1_r23 989 +#define _GUARD_CALLABLE_TUPLE_1_r33 990 +#define _GUARD_CALLABLE_TYPE_1_r03 991 +#define _GUARD_CALLABLE_TYPE_1_r13 992 +#define _GUARD_CALLABLE_TYPE_1_r23 993 +#define _GUARD_CALLABLE_TYPE_1_r33 994 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r00 995 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r11 996 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r22 997 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r33 998 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r00 999 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r11 1000 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r22 1001 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r33 1002 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r00 1003 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r11 1004 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r22 1005 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r33 1006 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r00 1007 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r11 1008 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r22 1009 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r33 1010 +#define _GUARD_DORV_NO_DICT_r01 1011 +#define _GUARD_DORV_NO_DICT_r11 1012 +#define _GUARD_DORV_NO_DICT_r22 1013 +#define _GUARD_DORV_NO_DICT_r33 1014 +#define _GUARD_GLOBALS_VERSION_r00 1015 +#define _GUARD_GLOBALS_VERSION_r11 1016 +#define _GUARD_GLOBALS_VERSION_r22 1017 +#define _GUARD_GLOBALS_VERSION_r33 1018 +#define _GUARD_IP_RETURN_GENERATOR_r00 1019 +#define _GUARD_IP_RETURN_GENERATOR_r11 1020 +#define _GUARD_IP_RETURN_GENERATOR_r22 1021 +#define _GUARD_IP_RETURN_GENERATOR_r33 1022 +#define _GUARD_IP_RETURN_VALUE_r00 1023 +#define _GUARD_IP_RETURN_VALUE_r11 1024 +#define _GUARD_IP_RETURN_VALUE_r22 1025 +#define _GUARD_IP_RETURN_VALUE_r33 1026 +#define _GUARD_IP_YIELD_VALUE_r00 1027 +#define _GUARD_IP_YIELD_VALUE_r11 1028 +#define _GUARD_IP_YIELD_VALUE_r22 1029 +#define _GUARD_IP_YIELD_VALUE_r33 1030 +#define _GUARD_IP__PUSH_FRAME_r00 1031 +#define _GUARD_IP__PUSH_FRAME_r11 1032 +#define _GUARD_IP__PUSH_FRAME_r22 1033 +#define _GUARD_IP__PUSH_FRAME_r33 1034 +#define _GUARD_IS_FALSE_POP_r00 1035 +#define _GUARD_IS_FALSE_POP_r10 1036 +#define _GUARD_IS_FALSE_POP_r21 1037 +#define _GUARD_IS_FALSE_POP_r32 1038 +#define _GUARD_IS_NONE_POP_r00 1039 +#define _GUARD_IS_NONE_POP_r10 1040 +#define _GUARD_IS_NONE_POP_r21 1041 +#define _GUARD_IS_NONE_POP_r32 1042 +#define _GUARD_IS_NOT_NONE_POP_r10 1043 +#define _GUARD_IS_TRUE_POP_r00 1044 +#define _GUARD_IS_TRUE_POP_r10 1045 +#define _GUARD_IS_TRUE_POP_r21 1046 +#define _GUARD_IS_TRUE_POP_r32 1047 +#define _GUARD_ITERATOR_r01 1048 +#define _GUARD_ITERATOR_r11 1049 +#define _GUARD_ITERATOR_r22 1050 +#define _GUARD_ITERATOR_r33 1051 +#define _GUARD_ITER_VIRTUAL_r01 1052 +#define _GUARD_ITER_VIRTUAL_r11 1053 +#define _GUARD_ITER_VIRTUAL_r22 1054 +#define _GUARD_ITER_VIRTUAL_r33 1055 +#define _GUARD_KEYS_VERSION_r01 1056 +#define _GUARD_KEYS_VERSION_r11 1057 +#define _GUARD_KEYS_VERSION_r22 1058 +#define _GUARD_KEYS_VERSION_r33 1059 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r03 1060 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r13 1061 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r23 1062 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r33 1063 +#define _GUARD_NOS_COMPACT_ASCII_r02 1064 +#define _GUARD_NOS_COMPACT_ASCII_r12 1065 +#define _GUARD_NOS_COMPACT_ASCII_r22 1066 +#define _GUARD_NOS_COMPACT_ASCII_r33 1067 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 1068 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 1069 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 1070 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 1071 +#define _GUARD_NOS_DICT_SUBSCRIPT_r02 1072 +#define _GUARD_NOS_DICT_SUBSCRIPT_r12 1073 +#define _GUARD_NOS_DICT_SUBSCRIPT_r22 1074 +#define _GUARD_NOS_DICT_SUBSCRIPT_r33 1075 +#define _GUARD_NOS_FLOAT_r02 1076 +#define _GUARD_NOS_FLOAT_r12 1077 +#define _GUARD_NOS_FLOAT_r22 1078 +#define _GUARD_NOS_FLOAT_r33 1079 +#define _GUARD_NOS_INT_r02 1080 +#define _GUARD_NOS_INT_r12 1081 +#define _GUARD_NOS_INT_r22 1082 +#define _GUARD_NOS_INT_r33 1083 +#define _GUARD_NOS_ITER_VIRTUAL_r02 1084 +#define _GUARD_NOS_ITER_VIRTUAL_r12 1085 +#define _GUARD_NOS_ITER_VIRTUAL_r22 1086 +#define _GUARD_NOS_ITER_VIRTUAL_r33 1087 +#define _GUARD_NOS_LIST_r02 1088 +#define _GUARD_NOS_LIST_r12 1089 +#define _GUARD_NOS_LIST_r22 1090 +#define _GUARD_NOS_LIST_r33 1091 +#define _GUARD_NOS_NOT_NULL_r02 1092 +#define _GUARD_NOS_NOT_NULL_r12 1093 +#define _GUARD_NOS_NOT_NULL_r22 1094 +#define _GUARD_NOS_NOT_NULL_r33 1095 +#define _GUARD_NOS_NULL_r02 1096 +#define _GUARD_NOS_NULL_r12 1097 +#define _GUARD_NOS_NULL_r22 1098 +#define _GUARD_NOS_NULL_r33 1099 +#define _GUARD_NOS_OVERFLOWED_r02 1100 +#define _GUARD_NOS_OVERFLOWED_r12 1101 +#define _GUARD_NOS_OVERFLOWED_r22 1102 +#define _GUARD_NOS_OVERFLOWED_r33 1103 +#define _GUARD_NOS_TUPLE_r02 1104 +#define _GUARD_NOS_TUPLE_r12 1105 +#define _GUARD_NOS_TUPLE_r22 1106 +#define _GUARD_NOS_TUPLE_r33 1107 +#define _GUARD_NOS_TYPE_VERSION_r02 1108 +#define _GUARD_NOS_TYPE_VERSION_r12 1109 +#define _GUARD_NOS_TYPE_VERSION_r22 1110 +#define _GUARD_NOS_TYPE_VERSION_r33 1111 +#define _GUARD_NOS_UNICODE_r02 1112 +#define _GUARD_NOS_UNICODE_r12 1113 +#define _GUARD_NOS_UNICODE_r22 1114 +#define _GUARD_NOS_UNICODE_r33 1115 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 1116 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 1117 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 1118 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 1119 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 1120 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 1121 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 1122 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 1123 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 1124 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 1125 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 1126 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 1127 +#define _GUARD_THIRD_NULL_r03 1128 +#define _GUARD_THIRD_NULL_r13 1129 +#define _GUARD_THIRD_NULL_r23 1130 +#define _GUARD_THIRD_NULL_r33 1131 +#define _GUARD_TOS_ANY_DICT_r01 1132 +#define _GUARD_TOS_ANY_DICT_r11 1133 +#define _GUARD_TOS_ANY_DICT_r22 1134 +#define _GUARD_TOS_ANY_DICT_r33 1135 +#define _GUARD_TOS_ANY_SET_r01 1136 +#define _GUARD_TOS_ANY_SET_r11 1137 +#define _GUARD_TOS_ANY_SET_r22 1138 +#define _GUARD_TOS_ANY_SET_r33 1139 +#define _GUARD_TOS_DICT_r01 1140 +#define _GUARD_TOS_DICT_r11 1141 +#define _GUARD_TOS_DICT_r22 1142 +#define _GUARD_TOS_DICT_r33 1143 +#define _GUARD_TOS_FLOAT_r01 1144 +#define _GUARD_TOS_FLOAT_r11 1145 +#define _GUARD_TOS_FLOAT_r22 1146 +#define _GUARD_TOS_FLOAT_r33 1147 +#define _GUARD_TOS_FROZENDICT_r01 1148 +#define _GUARD_TOS_FROZENDICT_r11 1149 +#define _GUARD_TOS_FROZENDICT_r22 1150 +#define _GUARD_TOS_FROZENDICT_r33 1151 +#define _GUARD_TOS_FROZENSET_r01 1152 +#define _GUARD_TOS_FROZENSET_r11 1153 +#define _GUARD_TOS_FROZENSET_r22 1154 +#define _GUARD_TOS_FROZENSET_r33 1155 +#define _GUARD_TOS_INT_r01 1156 +#define _GUARD_TOS_INT_r11 1157 +#define _GUARD_TOS_INT_r22 1158 +#define _GUARD_TOS_INT_r33 1159 +#define _GUARD_TOS_IS_NONE_r01 1160 +#define _GUARD_TOS_IS_NONE_r11 1161 +#define _GUARD_TOS_IS_NONE_r22 1162 +#define _GUARD_TOS_IS_NONE_r33 1163 +#define _GUARD_TOS_LIST_r01 1164 +#define _GUARD_TOS_LIST_r11 1165 +#define _GUARD_TOS_LIST_r22 1166 +#define _GUARD_TOS_LIST_r33 1167 +#define _GUARD_TOS_NOT_NULL_r01 1168 +#define _GUARD_TOS_NOT_NULL_r11 1169 +#define _GUARD_TOS_NOT_NULL_r22 1170 +#define _GUARD_TOS_NOT_NULL_r33 1171 +#define _GUARD_TOS_OVERFLOWED_r01 1172 +#define _GUARD_TOS_OVERFLOWED_r11 1173 +#define _GUARD_TOS_OVERFLOWED_r22 1174 +#define _GUARD_TOS_OVERFLOWED_r33 1175 +#define _GUARD_TOS_SET_r01 1176 +#define _GUARD_TOS_SET_r11 1177 +#define _GUARD_TOS_SET_r22 1178 +#define _GUARD_TOS_SET_r33 1179 +#define _GUARD_TOS_SLICE_r01 1180 +#define _GUARD_TOS_SLICE_r11 1181 +#define _GUARD_TOS_SLICE_r22 1182 +#define _GUARD_TOS_SLICE_r33 1183 +#define _GUARD_TOS_TUPLE_r01 1184 +#define _GUARD_TOS_TUPLE_r11 1185 +#define _GUARD_TOS_TUPLE_r22 1186 +#define _GUARD_TOS_TUPLE_r33 1187 +#define _GUARD_TOS_UNICODE_r01 1188 +#define _GUARD_TOS_UNICODE_r11 1189 +#define _GUARD_TOS_UNICODE_r22 1190 +#define _GUARD_TOS_UNICODE_r33 1191 +#define _GUARD_TYPE_r01 1192 +#define _GUARD_TYPE_r11 1193 +#define _GUARD_TYPE_r22 1194 +#define _GUARD_TYPE_r33 1195 +#define _GUARD_TYPE_ITER_r02 1196 +#define _GUARD_TYPE_ITER_r12 1197 +#define _GUARD_TYPE_ITER_r22 1198 +#define _GUARD_TYPE_ITER_r33 1199 +#define _GUARD_TYPE_VERSION_r01 1200 +#define _GUARD_TYPE_VERSION_r11 1201 +#define _GUARD_TYPE_VERSION_r22 1202 +#define _GUARD_TYPE_VERSION_r33 1203 +#define _GUARD_TYPE_VERSION_LOCKED_r01 1204 +#define _GUARD_TYPE_VERSION_LOCKED_r11 1205 +#define _GUARD_TYPE_VERSION_LOCKED_r22 1206 +#define _GUARD_TYPE_VERSION_LOCKED_r33 1207 +#define _HANDLE_PENDING_AND_DEOPT_r00 1208 +#define _HANDLE_PENDING_AND_DEOPT_r10 1209 +#define _HANDLE_PENDING_AND_DEOPT_r20 1210 +#define _HANDLE_PENDING_AND_DEOPT_r30 1211 +#define _IMPORT_FROM_r12 1212 +#define _IMPORT_NAME_r21 1213 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1214 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1215 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1216 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1217 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1218 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1219 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1220 +#define _INSERT_NULL_r10 1221 +#define _INSTRUMENTED_FOR_ITER_r23 1222 +#define _INSTRUMENTED_INSTRUCTION_r00 1223 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1224 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1225 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1226 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1227 +#define _INSTRUMENTED_LINE_r00 1228 +#define _INSTRUMENTED_NOT_TAKEN_r00 1229 +#define _INSTRUMENTED_NOT_TAKEN_r11 1230 +#define _INSTRUMENTED_NOT_TAKEN_r22 1231 +#define _INSTRUMENTED_NOT_TAKEN_r33 1232 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1233 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1234 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1235 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1236 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1237 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1238 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1239 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1240 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1241 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1242 +#define _IS_NONE_r11 1243 +#define _IS_OP_r03 1244 +#define _IS_OP_r13 1245 +#define _IS_OP_r23 1246 +#define _ITER_CHECK_LIST_r02 1247 +#define _ITER_CHECK_LIST_r12 1248 +#define _ITER_CHECK_LIST_r22 1249 +#define _ITER_CHECK_LIST_r33 1250 +#define _ITER_CHECK_RANGE_r02 1251 +#define _ITER_CHECK_RANGE_r12 1252 +#define _ITER_CHECK_RANGE_r22 1253 +#define _ITER_CHECK_RANGE_r33 1254 +#define _ITER_CHECK_TUPLE_r02 1255 +#define _ITER_CHECK_TUPLE_r12 1256 +#define _ITER_CHECK_TUPLE_r22 1257 +#define _ITER_CHECK_TUPLE_r33 1258 +#define _ITER_JUMP_LIST_r02 1259 +#define _ITER_JUMP_LIST_r12 1260 +#define _ITER_JUMP_LIST_r22 1261 +#define _ITER_JUMP_LIST_r33 1262 +#define _ITER_JUMP_RANGE_r02 1263 +#define _ITER_JUMP_RANGE_r12 1264 +#define _ITER_JUMP_RANGE_r22 1265 +#define _ITER_JUMP_RANGE_r33 1266 +#define _ITER_JUMP_TUPLE_r02 1267 +#define _ITER_JUMP_TUPLE_r12 1268 +#define _ITER_JUMP_TUPLE_r22 1269 +#define _ITER_JUMP_TUPLE_r33 1270 +#define _ITER_NEXT_INLINE_r23 1271 +#define _ITER_NEXT_LIST_r23 1272 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1273 +#define _ITER_NEXT_RANGE_r03 1274 +#define _ITER_NEXT_RANGE_r13 1275 +#define _ITER_NEXT_RANGE_r23 1276 +#define _ITER_NEXT_TUPLE_r03 1277 +#define _ITER_NEXT_TUPLE_r13 1278 +#define _ITER_NEXT_TUPLE_r23 1279 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1280 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1281 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1282 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1283 +#define _JUMP_TO_TOP_r00 1284 +#define _LIST_APPEND_r10 1285 +#define _LIST_EXTEND_r11 1286 +#define _LOAD_ATTR_r10 1287 +#define _LOAD_ATTR_CLASS_r11 1288 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME_r11 1289 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1290 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1291 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1292 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1293 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1294 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1295 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1296 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1297 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1298 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1299 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1300 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1301 +#define _LOAD_ATTR_MODULE_r12 1302 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1303 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1304 +#define _LOAD_ATTR_PROPERTY_FRAME_r01 1305 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1306 +#define _LOAD_ATTR_PROPERTY_FRAME_r22 1307 +#define _LOAD_ATTR_PROPERTY_FRAME_r33 1308 +#define _LOAD_ATTR_SLOT_r02 1309 +#define _LOAD_ATTR_SLOT_r12 1310 +#define _LOAD_ATTR_SLOT_r23 1311 +#define _LOAD_ATTR_WITH_HINT_r12 1312 +#define _LOAD_BUILD_CLASS_r01 1313 +#define _LOAD_BYTECODE_r00 1314 +#define _LOAD_COMMON_CONSTANT_r01 1315 +#define _LOAD_COMMON_CONSTANT_r12 1316 +#define _LOAD_COMMON_CONSTANT_r23 1317 +#define _LOAD_CONST_r01 1318 +#define _LOAD_CONST_r12 1319 +#define _LOAD_CONST_r23 1320 +#define _LOAD_CONST_INLINE_r01 1321 +#define _LOAD_CONST_INLINE_r12 1322 +#define _LOAD_CONST_INLINE_r23 1323 +#define _LOAD_CONST_INLINE_BORROW_r01 1324 +#define _LOAD_CONST_INLINE_BORROW_r12 1325 +#define _LOAD_CONST_INLINE_BORROW_r23 1326 +#define _LOAD_DEREF_r01 1327 +#define _LOAD_FAST_r01 1328 +#define _LOAD_FAST_r12 1329 +#define _LOAD_FAST_r23 1330 +#define _LOAD_FAST_0_r01 1331 +#define _LOAD_FAST_0_r12 1332 +#define _LOAD_FAST_0_r23 1333 +#define _LOAD_FAST_1_r01 1334 +#define _LOAD_FAST_1_r12 1335 +#define _LOAD_FAST_1_r23 1336 +#define _LOAD_FAST_2_r01 1337 +#define _LOAD_FAST_2_r12 1338 +#define _LOAD_FAST_2_r23 1339 +#define _LOAD_FAST_3_r01 1340 +#define _LOAD_FAST_3_r12 1341 +#define _LOAD_FAST_3_r23 1342 +#define _LOAD_FAST_4_r01 1343 +#define _LOAD_FAST_4_r12 1344 +#define _LOAD_FAST_4_r23 1345 +#define _LOAD_FAST_5_r01 1346 +#define _LOAD_FAST_5_r12 1347 +#define _LOAD_FAST_5_r23 1348 +#define _LOAD_FAST_6_r01 1349 +#define _LOAD_FAST_6_r12 1350 +#define _LOAD_FAST_6_r23 1351 +#define _LOAD_FAST_7_r01 1352 +#define _LOAD_FAST_7_r12 1353 +#define _LOAD_FAST_7_r23 1354 +#define _LOAD_FAST_AND_CLEAR_r01 1355 +#define _LOAD_FAST_AND_CLEAR_r12 1356 +#define _LOAD_FAST_AND_CLEAR_r23 1357 +#define _LOAD_FAST_BORROW_r01 1358 +#define _LOAD_FAST_BORROW_r12 1359 +#define _LOAD_FAST_BORROW_r23 1360 +#define _LOAD_FAST_BORROW_0_r01 1361 +#define _LOAD_FAST_BORROW_0_r12 1362 +#define _LOAD_FAST_BORROW_0_r23 1363 +#define _LOAD_FAST_BORROW_1_r01 1364 +#define _LOAD_FAST_BORROW_1_r12 1365 +#define _LOAD_FAST_BORROW_1_r23 1366 +#define _LOAD_FAST_BORROW_2_r01 1367 +#define _LOAD_FAST_BORROW_2_r12 1368 +#define _LOAD_FAST_BORROW_2_r23 1369 +#define _LOAD_FAST_BORROW_3_r01 1370 +#define _LOAD_FAST_BORROW_3_r12 1371 +#define _LOAD_FAST_BORROW_3_r23 1372 +#define _LOAD_FAST_BORROW_4_r01 1373 +#define _LOAD_FAST_BORROW_4_r12 1374 +#define _LOAD_FAST_BORROW_4_r23 1375 +#define _LOAD_FAST_BORROW_5_r01 1376 +#define _LOAD_FAST_BORROW_5_r12 1377 +#define _LOAD_FAST_BORROW_5_r23 1378 +#define _LOAD_FAST_BORROW_6_r01 1379 +#define _LOAD_FAST_BORROW_6_r12 1380 +#define _LOAD_FAST_BORROW_6_r23 1381 +#define _LOAD_FAST_BORROW_7_r01 1382 +#define _LOAD_FAST_BORROW_7_r12 1383 +#define _LOAD_FAST_BORROW_7_r23 1384 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1385 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1386 +#define _LOAD_FAST_CHECK_r01 1387 +#define _LOAD_FAST_CHECK_r12 1388 +#define _LOAD_FAST_CHECK_r23 1389 +#define _LOAD_FAST_LOAD_FAST_r02 1390 +#define _LOAD_FAST_LOAD_FAST_r13 1391 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1392 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1393 +#define _LOAD_GLOBAL_r00 1394 +#define _LOAD_GLOBAL_BUILTINS_r01 1395 +#define _LOAD_GLOBAL_MODULE_r01 1396 +#define _LOAD_LOCALS_r01 1397 +#define _LOAD_LOCALS_r12 1398 +#define _LOAD_LOCALS_r23 1399 +#define _LOAD_NAME_r01 1400 +#define _LOAD_SMALL_INT_r01 1401 +#define _LOAD_SMALL_INT_r12 1402 +#define _LOAD_SMALL_INT_r23 1403 +#define _LOAD_SMALL_INT_0_r01 1404 +#define _LOAD_SMALL_INT_0_r12 1405 +#define _LOAD_SMALL_INT_0_r23 1406 +#define _LOAD_SMALL_INT_1_r01 1407 +#define _LOAD_SMALL_INT_1_r12 1408 +#define _LOAD_SMALL_INT_1_r23 1409 +#define _LOAD_SMALL_INT_2_r01 1410 +#define _LOAD_SMALL_INT_2_r12 1411 +#define _LOAD_SMALL_INT_2_r23 1412 +#define _LOAD_SMALL_INT_3_r01 1413 +#define _LOAD_SMALL_INT_3_r12 1414 +#define _LOAD_SMALL_INT_3_r23 1415 +#define _LOAD_SPECIAL_r00 1416 +#define _LOAD_SUPER_ATTR_ATTR_r31 1417 +#define _LOAD_SUPER_ATTR_METHOD_r32 1418 +#define _LOCK_OBJECT_r01 1419 +#define _LOCK_OBJECT_r11 1420 +#define _LOCK_OBJECT_r22 1421 +#define _LOCK_OBJECT_r33 1422 +#define _MAKE_CALLARGS_A_TUPLE_r33 1423 +#define _MAKE_CELL_r00 1424 +#define _MAKE_FUNCTION_r12 1425 +#define _MAKE_HEAP_SAFE_r01 1426 +#define _MAKE_HEAP_SAFE_r11 1427 +#define _MAKE_HEAP_SAFE_r22 1428 +#define _MAKE_HEAP_SAFE_r33 1429 +#define _MAKE_WARM_r00 1430 +#define _MAKE_WARM_r11 1431 +#define _MAKE_WARM_r22 1432 +#define _MAKE_WARM_r33 1433 +#define _MAP_ADD_r20 1434 +#define _MATCH_CLASS_r33 1435 +#define _MATCH_KEYS_r23 1436 +#define _MATCH_MAPPING_r02 1437 +#define _MATCH_MAPPING_r12 1438 +#define _MATCH_MAPPING_r23 1439 +#define _MATCH_SEQUENCE_r02 1440 +#define _MATCH_SEQUENCE_r12 1441 +#define _MATCH_SEQUENCE_r23 1442 +#define _MAYBE_EXPAND_METHOD_r00 1443 +#define _MAYBE_EXPAND_METHOD_KW_r11 1444 +#define _MONITOR_CALL_r00 1445 +#define _MONITOR_CALL_KW_r11 1446 +#define _MONITOR_JUMP_BACKWARD_r00 1447 +#define _MONITOR_JUMP_BACKWARD_r11 1448 +#define _MONITOR_JUMP_BACKWARD_r22 1449 +#define _MONITOR_JUMP_BACKWARD_r33 1450 +#define _MONITOR_RESUME_r00 1451 +#define _NOP_r00 1452 +#define _NOP_r11 1453 +#define _NOP_r22 1454 +#define _NOP_r33 1455 +#define _POP_EXCEPT_r10 1456 +#define _POP_ITER_r20 1457 +#define _POP_JUMP_IF_FALSE_r00 1458 +#define _POP_JUMP_IF_FALSE_r10 1459 +#define _POP_JUMP_IF_FALSE_r21 1460 +#define _POP_JUMP_IF_FALSE_r32 1461 +#define _POP_JUMP_IF_TRUE_r00 1462 +#define _POP_JUMP_IF_TRUE_r10 1463 +#define _POP_JUMP_IF_TRUE_r21 1464 +#define _POP_JUMP_IF_TRUE_r32 1465 +#define _POP_TOP_r10 1466 +#define _POP_TOP_FLOAT_r00 1467 +#define _POP_TOP_FLOAT_r10 1468 +#define _POP_TOP_FLOAT_r21 1469 +#define _POP_TOP_FLOAT_r32 1470 +#define _POP_TOP_INT_r00 1471 +#define _POP_TOP_INT_r10 1472 +#define _POP_TOP_INT_r21 1473 +#define _POP_TOP_INT_r32 1474 +#define _POP_TOP_NOP_r00 1475 +#define _POP_TOP_NOP_r10 1476 +#define _POP_TOP_NOP_r21 1477 +#define _POP_TOP_NOP_r32 1478 +#define _POP_TOP_OPARG_r00 1479 +#define _POP_TOP_UNICODE_r00 1480 +#define _POP_TOP_UNICODE_r10 1481 +#define _POP_TOP_UNICODE_r21 1482 +#define _POP_TOP_UNICODE_r32 1483 +#define _PUSH_EXC_INFO_r02 1484 +#define _PUSH_EXC_INFO_r12 1485 +#define _PUSH_EXC_INFO_r23 1486 +#define _PUSH_FRAME_r10 1487 +#define _PUSH_NULL_r01 1488 +#define _PUSH_NULL_r12 1489 +#define _PUSH_NULL_r23 1490 +#define _PUSH_NULL_CONDITIONAL_r00 1491 +#define _PUSH_TAGGED_ZERO_r01 1492 +#define _PUSH_TAGGED_ZERO_r12 1493 +#define _PUSH_TAGGED_ZERO_r23 1494 +#define _PY_FRAME_EX_r31 1495 +#define _PY_FRAME_GENERAL_r01 1496 +#define _PY_FRAME_KW_r11 1497 +#define _REPLACE_WITH_TRUE_r02 1498 +#define _REPLACE_WITH_TRUE_r12 1499 +#define _REPLACE_WITH_TRUE_r23 1500 +#define _RESUME_CHECK_r00 1501 +#define _RESUME_CHECK_r11 1502 +#define _RESUME_CHECK_r22 1503 +#define _RESUME_CHECK_r33 1504 +#define _RETURN_GENERATOR_r01 1505 +#define _RETURN_VALUE_r11 1506 +#define _RROT_3_r03 1507 +#define _RROT_3_r13 1508 +#define _RROT_3_r23 1509 +#define _RROT_3_r33 1510 +#define _SAVE_RETURN_OFFSET_r00 1511 +#define _SAVE_RETURN_OFFSET_r11 1512 +#define _SAVE_RETURN_OFFSET_r22 1513 +#define _SAVE_RETURN_OFFSET_r33 1514 +#define _SEND_ASYNC_GEN_r33 1515 +#define _SEND_ASYNC_GEN_TIER_TWO_r33 1516 +#define _SEND_GEN_FRAME_r33 1517 +#define _SEND_VIRTUAL_r33 1518 +#define _SEND_VIRTUAL_TIER_TWO_r03 1519 +#define _SEND_VIRTUAL_TIER_TWO_r13 1520 +#define _SEND_VIRTUAL_TIER_TWO_r23 1521 +#define _SEND_VIRTUAL_TIER_TWO_r33 1522 +#define _SETUP_ANNOTATIONS_r00 1523 +#define _SET_ADD_r10 1524 +#define _SET_FUNCTION_ATTRIBUTE_r01 1525 +#define _SET_FUNCTION_ATTRIBUTE_r11 1526 +#define _SET_FUNCTION_ATTRIBUTE_r21 1527 +#define _SET_FUNCTION_ATTRIBUTE_r32 1528 +#define _SET_IP_r00 1529 +#define _SET_IP_r11 1530 +#define _SET_IP_r22 1531 +#define _SET_IP_r33 1532 +#define _SET_UPDATE_r11 1533 +#define _SPILL_OR_RELOAD_r01 1534 +#define _SPILL_OR_RELOAD_r02 1535 +#define _SPILL_OR_RELOAD_r03 1536 +#define _SPILL_OR_RELOAD_r10 1537 +#define _SPILL_OR_RELOAD_r12 1538 +#define _SPILL_OR_RELOAD_r13 1539 +#define _SPILL_OR_RELOAD_r20 1540 +#define _SPILL_OR_RELOAD_r21 1541 +#define _SPILL_OR_RELOAD_r23 1542 +#define _SPILL_OR_RELOAD_r30 1543 +#define _SPILL_OR_RELOAD_r31 1544 +#define _SPILL_OR_RELOAD_r32 1545 +#define _START_EXECUTOR_r00 1546 +#define _STORE_ATTR_r20 1547 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1548 +#define _STORE_ATTR_SLOT_r21 1549 +#define _STORE_ATTR_WITH_HINT_r21 1550 +#define _STORE_DEREF_r10 1551 +#define _STORE_FAST_LOAD_FAST_r11 1552 +#define _STORE_FAST_STORE_FAST_r20 1553 +#define _STORE_GLOBAL_r10 1554 +#define _STORE_NAME_r10 1555 +#define _STORE_SLICE_r30 1556 +#define _STORE_SUBSCR_r30 1557 +#define _STORE_SUBSCR_DICT_r31 1558 +#define _STORE_SUBSCR_DICT_KNOWN_HASH_r31 1559 +#define _STORE_SUBSCR_LIST_INT_r32 1560 +#define _SWAP_r11 1561 +#define _SWAP_2_r02 1562 +#define _SWAP_2_r12 1563 +#define _SWAP_2_r22 1564 +#define _SWAP_2_r33 1565 +#define _SWAP_3_r03 1566 +#define _SWAP_3_r13 1567 +#define _SWAP_3_r23 1568 +#define _SWAP_3_r33 1569 +#define _SWAP_FAST_r01 1570 +#define _SWAP_FAST_r11 1571 +#define _SWAP_FAST_r22 1572 +#define _SWAP_FAST_r33 1573 +#define _SWAP_FAST_0_r01 1574 +#define _SWAP_FAST_0_r11 1575 +#define _SWAP_FAST_0_r22 1576 +#define _SWAP_FAST_0_r33 1577 +#define _SWAP_FAST_1_r01 1578 +#define _SWAP_FAST_1_r11 1579 +#define _SWAP_FAST_1_r22 1580 +#define _SWAP_FAST_1_r33 1581 +#define _SWAP_FAST_2_r01 1582 +#define _SWAP_FAST_2_r11 1583 +#define _SWAP_FAST_2_r22 1584 +#define _SWAP_FAST_2_r33 1585 +#define _SWAP_FAST_3_r01 1586 +#define _SWAP_FAST_3_r11 1587 +#define _SWAP_FAST_3_r22 1588 +#define _SWAP_FAST_3_r33 1589 +#define _SWAP_FAST_4_r01 1590 +#define _SWAP_FAST_4_r11 1591 +#define _SWAP_FAST_4_r22 1592 +#define _SWAP_FAST_4_r33 1593 +#define _SWAP_FAST_5_r01 1594 +#define _SWAP_FAST_5_r11 1595 +#define _SWAP_FAST_5_r22 1596 +#define _SWAP_FAST_5_r33 1597 +#define _SWAP_FAST_6_r01 1598 +#define _SWAP_FAST_6_r11 1599 +#define _SWAP_FAST_6_r22 1600 +#define _SWAP_FAST_6_r33 1601 +#define _SWAP_FAST_7_r01 1602 +#define _SWAP_FAST_7_r11 1603 +#define _SWAP_FAST_7_r22 1604 +#define _SWAP_FAST_7_r33 1605 +#define _TIER2_RESUME_CHECK_r00 1606 +#define _TIER2_RESUME_CHECK_r11 1607 +#define _TIER2_RESUME_CHECK_r22 1608 +#define _TIER2_RESUME_CHECK_r33 1609 +#define _TO_BOOL_r11 1610 +#define _TO_BOOL_BOOL_r01 1611 +#define _TO_BOOL_BOOL_r11 1612 +#define _TO_BOOL_BOOL_r22 1613 +#define _TO_BOOL_BOOL_r33 1614 +#define _TO_BOOL_INT_r02 1615 +#define _TO_BOOL_INT_r12 1616 +#define _TO_BOOL_INT_r23 1617 +#define _TO_BOOL_LIST_r02 1618 +#define _TO_BOOL_LIST_r12 1619 +#define _TO_BOOL_LIST_r23 1620 +#define _TO_BOOL_NONE_r01 1621 +#define _TO_BOOL_NONE_r11 1622 +#define _TO_BOOL_NONE_r22 1623 +#define _TO_BOOL_NONE_r33 1624 +#define _TO_BOOL_STR_r02 1625 +#define _TO_BOOL_STR_r12 1626 +#define _TO_BOOL_STR_r23 1627 +#define _TRACE_RECORD_r00 1628 +#define _UNARY_INVERT_r12 1629 +#define _UNARY_NEGATIVE_r12 1630 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r02 1631 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r12 1632 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r23 1633 +#define _UNARY_NOT_r01 1634 +#define _UNARY_NOT_r11 1635 +#define _UNARY_NOT_r22 1636 +#define _UNARY_NOT_r33 1637 +#define _UNPACK_EX_r10 1638 +#define _UNPACK_SEQUENCE_r10 1639 +#define _UNPACK_SEQUENCE_LIST_r10 1640 +#define _UNPACK_SEQUENCE_TUPLE_r10 1641 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1642 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1643 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1644 +#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1645 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1646 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1647 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1648 +#define _WITH_EXCEPT_START_r33 1649 +#define _YIELD_VALUE_r11 1650 +#define MAX_UOP_REGS_ID 1650 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 9e9c1239d2b600d..d4cceb5a500cab5 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -187,7 +187,6 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_UNPACK_SEQUENCE_LIST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_UNPACK_EX] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_STORE_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_DELETE_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_STORE_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_LOCALS] = HAS_ERROR_FLAG, [_LOAD_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -1814,15 +1813,6 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, - [_DELETE_ATTR] = { - .best = { 1, 1, 1, 1 }, - .entries = { - { -1, -1, -1 }, - { 0, 1, _DELETE_ATTR_r10 }, - { -1, -1, -1 }, - { -1, -1, -1 }, - }, - }, [_STORE_GLOBAL] = { .best = { 1, 1, 1, 1 }, .entries = { @@ -4308,7 +4298,6 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_UNPACK_SEQUENCE_LIST_r10] = _UNPACK_SEQUENCE_LIST, [_UNPACK_EX_r10] = _UNPACK_EX, [_STORE_ATTR_r20] = _STORE_ATTR, - [_DELETE_ATTR_r10] = _DELETE_ATTR, [_STORE_GLOBAL_r10] = _STORE_GLOBAL, [_LOAD_LOCALS_r01] = _LOAD_LOCALS, [_LOAD_LOCALS_r12] = _LOAD_LOCALS, @@ -5165,8 +5154,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_COPY_FREE_VARS_r33] = "_COPY_FREE_VARS_r33", [_CREATE_INIT_FRAME] = "_CREATE_INIT_FRAME", [_CREATE_INIT_FRAME_r01] = "_CREATE_INIT_FRAME_r01", - [_DELETE_ATTR] = "_DELETE_ATTR", - [_DELETE_ATTR_r10] = "_DELETE_ATTR_r10", [_DELETE_DEREF] = "_DELETE_DEREF", [_DELETE_DEREF_r00] = "_DELETE_DEREF_r00", [_DELETE_FAST] = "_DELETE_FAST", @@ -6483,8 +6470,6 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _STORE_ATTR: return 2; - case _DELETE_ATTR: - return 1; case _STORE_GLOBAL: return 1; case _LOAD_LOCALS: diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index ccc5c820d80ea57..11342ae451b9f6c 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -69,65 +69,64 @@ extern "C" { #define CONVERT_VALUE 56 #define COPY 57 #define COPY_FREE_VARS 58 -#define DELETE_ATTR 59 -#define DELETE_DEREF 60 -#define DELETE_FAST 61 -#define DICT_MERGE 62 -#define DICT_UPDATE 63 -#define END_ASYNC_FOR 64 -#define EXTENDED_ARG 65 -#define FOR_ITER 66 -#define GET_AWAITABLE 67 -#define GET_ITER 68 -#define IMPORT_FROM 69 -#define IMPORT_NAME 70 -#define IS_OP 71 -#define JUMP_BACKWARD 72 -#define JUMP_BACKWARD_NO_INTERRUPT 73 -#define JUMP_FORWARD 74 -#define LIST_APPEND 75 -#define LIST_EXTEND 76 -#define LOAD_ATTR 77 -#define LOAD_COMMON_CONSTANT 78 -#define LOAD_CONST 79 -#define LOAD_DEREF 80 -#define LOAD_FAST 81 -#define LOAD_FAST_AND_CLEAR 82 -#define LOAD_FAST_BORROW 83 -#define LOAD_FAST_BORROW_LOAD_FAST_BORROW 84 -#define LOAD_FAST_CHECK 85 -#define LOAD_FAST_LOAD_FAST 86 -#define LOAD_FROM_DICT_OR_DEREF 87 -#define LOAD_FROM_DICT_OR_GLOBALS 88 -#define LOAD_GLOBAL 89 -#define LOAD_NAME 90 -#define LOAD_SMALL_INT 91 -#define LOAD_SPECIAL 92 -#define LOAD_SUPER_ATTR 93 -#define MAKE_CELL 94 -#define MAP_ADD 95 -#define MATCH_CLASS 96 -#define POP_JUMP_IF_FALSE 97 -#define POP_JUMP_IF_NONE 98 -#define POP_JUMP_IF_NOT_NONE 99 -#define POP_JUMP_IF_TRUE 100 -#define RAISE_VARARGS 101 -#define RERAISE 102 -#define SEND 103 -#define SET_ADD 104 -#define SET_FUNCTION_ATTRIBUTE 105 -#define SET_UPDATE 106 -#define STORE_ATTR 107 -#define STORE_DEREF 108 -#define STORE_FAST 109 -#define STORE_FAST_LOAD_FAST 110 -#define STORE_FAST_STORE_FAST 111 -#define STORE_GLOBAL 112 -#define STORE_NAME 113 -#define SWAP 114 -#define UNPACK_EX 115 -#define UNPACK_SEQUENCE 116 -#define YIELD_VALUE 117 +#define DELETE_DEREF 59 +#define DELETE_FAST 60 +#define DICT_MERGE 61 +#define DICT_UPDATE 62 +#define END_ASYNC_FOR 63 +#define EXTENDED_ARG 64 +#define FOR_ITER 65 +#define GET_AWAITABLE 66 +#define GET_ITER 67 +#define IMPORT_FROM 68 +#define IMPORT_NAME 69 +#define IS_OP 70 +#define JUMP_BACKWARD 71 +#define JUMP_BACKWARD_NO_INTERRUPT 72 +#define JUMP_FORWARD 73 +#define LIST_APPEND 74 +#define LIST_EXTEND 75 +#define LOAD_ATTR 76 +#define LOAD_COMMON_CONSTANT 77 +#define LOAD_CONST 78 +#define LOAD_DEREF 79 +#define LOAD_FAST 80 +#define LOAD_FAST_AND_CLEAR 81 +#define LOAD_FAST_BORROW 82 +#define LOAD_FAST_BORROW_LOAD_FAST_BORROW 83 +#define LOAD_FAST_CHECK 84 +#define LOAD_FAST_LOAD_FAST 85 +#define LOAD_FROM_DICT_OR_DEREF 86 +#define LOAD_FROM_DICT_OR_GLOBALS 87 +#define LOAD_GLOBAL 88 +#define LOAD_NAME 89 +#define LOAD_SMALL_INT 90 +#define LOAD_SPECIAL 91 +#define LOAD_SUPER_ATTR 92 +#define MAKE_CELL 93 +#define MAP_ADD 94 +#define MATCH_CLASS 95 +#define POP_JUMP_IF_FALSE 96 +#define POP_JUMP_IF_NONE 97 +#define POP_JUMP_IF_NOT_NONE 98 +#define POP_JUMP_IF_TRUE 99 +#define RAISE_VARARGS 100 +#define RERAISE 101 +#define SEND 102 +#define SET_ADD 103 +#define SET_FUNCTION_ATTRIBUTE 104 +#define SET_UPDATE 105 +#define STORE_ATTR 106 +#define STORE_DEREF 107 +#define STORE_FAST 108 +#define STORE_FAST_LOAD_FAST 109 +#define STORE_FAST_STORE_FAST 110 +#define STORE_GLOBAL 111 +#define STORE_NAME 112 +#define SWAP 113 +#define UNPACK_EX 114 +#define UNPACK_SEQUENCE 115 +#define YIELD_VALUE 116 #define RESUME 128 #define BINARY_OP_ADD_FLOAT 129 #define BINARY_OP_ADD_INT 130 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index 52fa52bbf57e768..df92eae151d2488 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -289,65 +289,64 @@ CONVERT_VALUE=56, COPY=57, COPY_FREE_VARS=58, - DELETE_ATTR=59, - DELETE_DEREF=60, - DELETE_FAST=61, - DICT_MERGE=62, - DICT_UPDATE=63, - END_ASYNC_FOR=64, - EXTENDED_ARG=65, - FOR_ITER=66, - GET_AWAITABLE=67, - GET_ITER=68, - IMPORT_FROM=69, - IMPORT_NAME=70, - IS_OP=71, - JUMP_BACKWARD=72, - JUMP_BACKWARD_NO_INTERRUPT=73, - JUMP_FORWARD=74, - LIST_APPEND=75, - LIST_EXTEND=76, - LOAD_ATTR=77, - LOAD_COMMON_CONSTANT=78, - LOAD_CONST=79, - LOAD_DEREF=80, - LOAD_FAST=81, - LOAD_FAST_AND_CLEAR=82, - LOAD_FAST_BORROW=83, - LOAD_FAST_BORROW_LOAD_FAST_BORROW=84, - LOAD_FAST_CHECK=85, - LOAD_FAST_LOAD_FAST=86, - LOAD_FROM_DICT_OR_DEREF=87, - LOAD_FROM_DICT_OR_GLOBALS=88, - LOAD_GLOBAL=89, - LOAD_NAME=90, - LOAD_SMALL_INT=91, - LOAD_SPECIAL=92, - LOAD_SUPER_ATTR=93, - MAKE_CELL=94, - MAP_ADD=95, - MATCH_CLASS=96, - POP_JUMP_IF_FALSE=97, - POP_JUMP_IF_NONE=98, - POP_JUMP_IF_NOT_NONE=99, - POP_JUMP_IF_TRUE=100, - RAISE_VARARGS=101, - RERAISE=102, - SEND=103, - SET_ADD=104, - SET_FUNCTION_ATTRIBUTE=105, - SET_UPDATE=106, - STORE_ATTR=107, - STORE_DEREF=108, - STORE_FAST=109, - STORE_FAST_LOAD_FAST=110, - STORE_FAST_STORE_FAST=111, - STORE_GLOBAL=112, - STORE_NAME=113, - SWAP=114, - UNPACK_EX=115, - UNPACK_SEQUENCE=116, - YIELD_VALUE=117, + DELETE_DEREF=59, + DELETE_FAST=60, + DICT_MERGE=61, + DICT_UPDATE=62, + END_ASYNC_FOR=63, + EXTENDED_ARG=64, + FOR_ITER=65, + GET_AWAITABLE=66, + GET_ITER=67, + IMPORT_FROM=68, + IMPORT_NAME=69, + IS_OP=70, + JUMP_BACKWARD=71, + JUMP_BACKWARD_NO_INTERRUPT=72, + JUMP_FORWARD=73, + LIST_APPEND=74, + LIST_EXTEND=75, + LOAD_ATTR=76, + LOAD_COMMON_CONSTANT=77, + LOAD_CONST=78, + LOAD_DEREF=79, + LOAD_FAST=80, + LOAD_FAST_AND_CLEAR=81, + LOAD_FAST_BORROW=82, + LOAD_FAST_BORROW_LOAD_FAST_BORROW=83, + LOAD_FAST_CHECK=84, + LOAD_FAST_LOAD_FAST=85, + LOAD_FROM_DICT_OR_DEREF=86, + LOAD_FROM_DICT_OR_GLOBALS=87, + LOAD_GLOBAL=88, + LOAD_NAME=89, + LOAD_SMALL_INT=90, + LOAD_SPECIAL=91, + LOAD_SUPER_ATTR=92, + MAKE_CELL=93, + MAP_ADD=94, + MATCH_CLASS=95, + POP_JUMP_IF_FALSE=96, + POP_JUMP_IF_NONE=97, + POP_JUMP_IF_NOT_NONE=98, + POP_JUMP_IF_TRUE=99, + RAISE_VARARGS=100, + RERAISE=101, + SEND=102, + SET_ADD=103, + SET_FUNCTION_ATTRIBUTE=104, + SET_UPDATE=105, + STORE_ATTR=106, + STORE_DEREF=107, + STORE_FAST=108, + STORE_FAST_LOAD_FAST=109, + STORE_FAST_STORE_FAST=110, + STORE_GLOBAL=111, + STORE_NAME=112, + SWAP=113, + UNPACK_EX=114, + UNPACK_SEQUENCE=115, + YIELD_VALUE=116, INSTRUMENTED_END_FOR=233, INSTRUMENTED_POP_ITER=234, INSTRUMENTED_END_SEND=235, diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 9edbca3c383b43d..fdef9803144b444 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -2369,7 +2369,10 @@ def test_attribute_del(self): source = "del (\n lhs \n . \n rhs \n )" code = compile(source, "", "exec") self.assertOpcodeSourcePositionIs( - code, "DELETE_ATTR", line=4, end_line=4, column=5, end_column=8 + code, "PUSH_NULL", line=4, end_line=4, column=5, end_column=8 + ) + self.assertOpcodeSourcePositionIs( + code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8 ) def test_attribute_load(self): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-20-16-27-15.gh-issue-145855.3yaHO4.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-20-16-27-15.gh-issue-145855.3yaHO4.rst new file mode 100644 index 000000000000000..e34e51601fe5994 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-20-16-27-15.gh-issue-145855.3yaHO4.rst @@ -0,0 +1 @@ +The ``DELETE_ATTR`` opcode is now replaced with ``PUSH_NULL; STORE_ATTR``. diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index 708aa4d966e5357..ab80c422687bf2a 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -5827,33 +5827,6 @@ DISPATCH(); } - TARGET(DELETE_ATTR) { - #if _Py_TAIL_CALL_INTERP - int opcode = DELETE_ATTR; - (void)(opcode); - #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_ATTR); - _PyStackRef owner; - owner = stack_pointer[-1]; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyFrame_StackPointerValidate(frame); - int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); - _PyFrame_StackPointerInvalidate(frame); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyFrame_StackPointerValidate(frame); - PyStackRef_CLOSE(owner); - _PyFrame_StackPointerInvalidate(frame); - if (err) { - JUMP_TO_LABEL(error); - } - DISPATCH(); - } - TARGET(DELETE_DEREF) { #if _Py_TAIL_CALL_INTERP int opcode = DELETE_DEREF; @@ -12076,22 +12049,25 @@ PREDICTED_STORE_ATTR:; _Py_CODEUNIT* const this_instr = next_instr - 5; (void)this_instr; - _PyStackRef owner; _PyStackRef v; + _PyStackRef owner; // _SPECIALIZE_STORE_ATTR { owner = stack_pointer[-1]; + v = stack_pointer[-2]; 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); - _PyFrame_StackPointerValidate(frame); - _Py_Specialize_StoreAttr(owner, next_instr, name); - _PyFrame_StackPointerInvalidate(frame); - DISPATCH_SAME_OPARG(); + if (!PyStackRef_IsNull(v)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyFrame_StackPointerValidate(frame); + _Py_Specialize_StoreAttr(owner, next_instr, name); + _PyFrame_StackPointerInvalidate(frame); + DISPATCH_SAME_OPARG(); + } } OPCODE_DEFERRED_INC(STORE_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); @@ -12100,29 +12076,24 @@ /* Skip 3 cache entries */ // _STORE_ATTR { - v = stack_pointer[-2]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), name, PyStackRef_AsPyObjectBorrow(v)); _PyFrame_StackPointerInvalidate(frame); - assert(stack_pointer == _PyFrame_GetStackPointer(frame)); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); - _PyStackRef tmp = owner; - owner = PyStackRef_NULL; - stack_pointer[-1] = owner; - PyStackRef_CLOSE(tmp); + PyStackRef_CLOSE(owner); _PyFrame_StackPointerInvalidate(frame); - assert(stack_pointer == _PyFrame_GetStackPointer(frame)); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); - tmp = v; - v = PyStackRef_NULL; - stack_pointer[-2] = v; - PyStackRef_CLOSE(tmp); + PyStackRef_XCLOSE(v); _PyFrame_StackPointerInvalidate(frame); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { JUMP_TO_LABEL(error); } diff --git a/Modules/_testinternalcapi/test_targets.h b/Modules/_testinternalcapi/test_targets.h index 9133af142723484..91b424773224e4b 100644 --- a/Modules/_testinternalcapi/test_targets.h +++ b/Modules/_testinternalcapi/test_targets.h @@ -59,7 +59,6 @@ static void *opcode_targets_table[256] = { &&TARGET_CONVERT_VALUE, &&TARGET_COPY, &&TARGET_COPY_FREE_VARS, - &&TARGET_DELETE_ATTR, &&TARGET_DELETE_DEREF, &&TARGET_DELETE_FAST, &&TARGET_DICT_MERGE, @@ -128,6 +127,7 @@ static void *opcode_targets_table[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_RESUME, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, @@ -376,7 +376,7 @@ static void *opcode_tracing_targets_table[256] = { &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, - &&TARGET_TRACE_RECORD, + &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, @@ -601,7 +601,6 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONTAINS_OP_SET(TAIL_CALL_PARAMS static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONVERT_VALUE(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COPY(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COPY_FREE_VARS(TAIL_CALL_PARAMS); -static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_ATTR(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_DEREF(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_FAST(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_SUBSCR(TAIL_CALL_PARAMS); @@ -845,7 +844,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [CONVERT_VALUE] = _TAIL_CALL_CONVERT_VALUE, [COPY] = _TAIL_CALL_COPY, [COPY_FREE_VARS] = _TAIL_CALL_COPY_FREE_VARS, - [DELETE_ATTR] = _TAIL_CALL_DELETE_ATTR, [DELETE_DEREF] = _TAIL_CALL_DELETE_DEREF, [DELETE_FAST] = _TAIL_CALL_DELETE_FAST, [DELETE_SUBSCR] = _TAIL_CALL_DELETE_SUBSCR, @@ -1007,6 +1005,7 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE, [WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START, [YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE, + [117] = _TAIL_CALL_UNKNOWN_OPCODE, [118] = _TAIL_CALL_UNKNOWN_OPCODE, [119] = _TAIL_CALL_UNKNOWN_OPCODE, [120] = _TAIL_CALL_UNKNOWN_OPCODE, @@ -1103,7 +1102,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [CONVERT_VALUE] = _TAIL_CALL_TRACE_RECORD, [COPY] = _TAIL_CALL_TRACE_RECORD, [COPY_FREE_VARS] = _TAIL_CALL_TRACE_RECORD, - [DELETE_ATTR] = _TAIL_CALL_TRACE_RECORD, [DELETE_DEREF] = _TAIL_CALL_TRACE_RECORD, [DELETE_FAST] = _TAIL_CALL_TRACE_RECORD, [DELETE_SUBSCR] = _TAIL_CALL_TRACE_RECORD, @@ -1265,6 +1263,7 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_TRACE_RECORD, [WITH_EXCEPT_START] = _TAIL_CALL_TRACE_RECORD, [YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD, + [117] = _TAIL_CALL_UNKNOWN_OPCODE, [118] = _TAIL_CALL_UNKNOWN_OPCODE, [119] = _TAIL_CALL_UNKNOWN_OPCODE, [120] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 2fe612dba873008..c82b791439a3fa1 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,19 +1,19 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0, - 0,0,0,0,0,243,188,0,0,0,128,0,0,0,91,0, - 78,7,70,0,113,0,91,0,78,7,70,4,113,1,90,2, - 31,0,79,1,50,1,0,0,0,0,0,0,29,0,90,2, - 31,0,79,2,90,0,77,6,0,0,0,0,0,0,0,0, + 0,0,0,0,0,243,188,0,0,0,128,0,0,0,90,0, + 77,7,69,0,112,0,90,0,77,7,69,4,112,1,89,2, + 31,0,78,1,50,1,0,0,0,0,0,0,29,0,89,2, + 31,0,78,2,89,0,76,6,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,50,2,0,0,0,0, - 0,0,29,0,90,1,77,8,0,0,0,0,0,0,0,0, + 0,0,29,0,89,1,76,8,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,31,0,50,0,0,0, - 0,0,0,0,79,3,42,26,0,0,0,0,0,0,0,0, - 0,0,113,5,79,6,68,0,0,0,66,24,0,0,113,6, - 90,2,31,0,79,4,90,6,12,0,79,5,90,5,90,6, + 0,0,0,0,78,3,42,26,0,0,0,0,0,0,0,0, + 0,0,112,5,78,6,67,0,0,0,65,24,0,0,112,6, + 89,2,31,0,78,4,89,6,12,0,78,5,89,5,89,6, 42,26,0,0,0,0,0,0,0,0,0,0,12,0,48,4, - 50,1,0,0,0,0,0,0,29,0,72,26,0,0,9,0, - 28,0,78,7,33,0,41,7,233,0,0,0,0,122,18,70, + 50,1,0,0,0,0,0,0,29,0,71,26,0,0,9,0, + 28,0,77,7,33,0,41,7,233,0,0,0,0,122,18,70, 114,111,122,101,110,32,72,101,108,108,111,32,87,111,114,108, 100,122,8,115,121,115,46,97,114,103,118,218,6,99,111,110, 102,105,103,122,7,99,111,110,102,105,103,32,122,2,58,32, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6d5ae1b074db5b7..689feeb0a1e0700 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2131,13 +2131,15 @@ dummy_func( STORE_ATTR_WITH_HINT, }; - specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) { + specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, v, owner -- v, owner)) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - next_instr = this_instr; - _Py_Specialize_StoreAttr(owner, next_instr, name); - DISPATCH_SAME_OPARG(); + if (!PyStackRef_IsNull(v)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + next_instr = this_instr; + _Py_Specialize_StoreAttr(owner, next_instr, name); + DISPATCH_SAME_OPARG(); + } } OPCODE_DEFERRED_INC(STORE_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); @@ -2148,19 +2150,13 @@ dummy_func( PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), name, PyStackRef_AsPyObjectBorrow(v)); - DECREF_INPUTS(); + PyStackRef_CLOSE(owner); + PyStackRef_XCLOSE(v); ERROR_IF(err); } macro(STORE_ATTR) = _SPECIALIZE_STORE_ATTR + unused/3 + _STORE_ATTR; - inst(DELETE_ATTR, (owner --)) { - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); - PyStackRef_CLOSE(owner); - ERROR_IF(err); - } - inst(STORE_GLOBAL, (v --)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; diff --git a/Python/codegen.c b/Python/codegen.c index fa8c4ce88956557..81fecd09a2060d1 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -5534,18 +5534,21 @@ codegen_visit_expr(compiler *c, expr_ty e) } } RETURN_IF_ERROR(_PyCompile_MaybeAddStaticAttributeToClass(c, e)); - VISIT(c, expr, e->v.Attribute.value); loc = LOC(e); loc = update_start_location_to_match_attr(c, loc, e); switch (e->v.Attribute.ctx) { case Load: + VISIT(c, expr, e->v.Attribute.value); ADDOP_NAME(c, loc, LOAD_ATTR, e->v.Attribute.attr, names); break; case Store: + VISIT(c, expr, e->v.Attribute.value); ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names); break; case Del: - ADDOP_NAME(c, loc, DELETE_ATTR, e->v.Attribute.attr, names); + ADDOP(c, loc, PUSH_NULL); + VISIT(c, expr, e->v.Attribute.value); + ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names); break; } break; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 6be53213966678e..a012f14f7fbebe2 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9948,54 +9948,17 @@ int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), name, PyStackRef_AsPyObjectBorrow(v)); _PyFrame_StackPointerInvalidate(frame); - assert(stack_pointer == _PyFrame_GetStackPointer(frame)); - _PyFrame_StackPointerValidate(frame); - _PyStackRef tmp = owner; - owner = PyStackRef_NULL; - stack_pointer[-1] = owner; - PyStackRef_CLOSE(tmp); - _PyFrame_StackPointerInvalidate(frame); - assert(stack_pointer == _PyFrame_GetStackPointer(frame)); - _PyFrame_StackPointerValidate(frame); - tmp = v; - v = PyStackRef_NULL; - stack_pointer[-2] = v; - PyStackRef_CLOSE(tmp); - _PyFrame_StackPointerInvalidate(frame); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - if (err) { - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_ERROR(); - } - _tos_cache0 = PyStackRef_ZERO_BITS; - _tos_cache1 = PyStackRef_ZERO_BITS; - _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(0); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - break; - } - - case _DELETE_ATTR_r10: { - CHECK_CURRENT_CACHED_VALUES(1); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - _PyStackRef owner; - _PyStackRef _stack_item_0 = _tos_cache0; - oparg = CURRENT_OPARG(); - owner = _stack_item_0; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - stack_pointer[0] = owner; - stack_pointer += 1; + stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); - int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); + PyStackRef_CLOSE(owner); _PyFrame_StackPointerInvalidate(frame); stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); - PyStackRef_CLOSE(owner); + PyStackRef_XCLOSE(v); _PyFrame_StackPointerInvalidate(frame); if (err) { SET_CURRENT_CACHED_VALUES(0); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d336b9fbcd57124..b72116d367634d8 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5827,33 +5827,6 @@ DISPATCH(); } - TARGET(DELETE_ATTR) { - #if _Py_TAIL_CALL_INTERP - int opcode = DELETE_ATTR; - (void)(opcode); - #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_ATTR); - _PyStackRef owner; - owner = stack_pointer[-1]; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyFrame_StackPointerValidate(frame); - int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); - _PyFrame_StackPointerInvalidate(frame); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyFrame_StackPointerValidate(frame); - PyStackRef_CLOSE(owner); - _PyFrame_StackPointerInvalidate(frame); - if (err) { - JUMP_TO_LABEL(error); - } - DISPATCH(); - } - TARGET(DELETE_DEREF) { #if _Py_TAIL_CALL_INTERP int opcode = DELETE_DEREF; @@ -12073,22 +12046,25 @@ PREDICTED_STORE_ATTR:; _Py_CODEUNIT* const this_instr = next_instr - 5; (void)this_instr; - _PyStackRef owner; _PyStackRef v; + _PyStackRef owner; // _SPECIALIZE_STORE_ATTR { owner = stack_pointer[-1]; + v = stack_pointer[-2]; 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); - _PyFrame_StackPointerValidate(frame); - _Py_Specialize_StoreAttr(owner, next_instr, name); - _PyFrame_StackPointerInvalidate(frame); - DISPATCH_SAME_OPARG(); + if (!PyStackRef_IsNull(v)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyFrame_StackPointerValidate(frame); + _Py_Specialize_StoreAttr(owner, next_instr, name); + _PyFrame_StackPointerInvalidate(frame); + DISPATCH_SAME_OPARG(); + } } OPCODE_DEFERRED_INC(STORE_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); @@ -12097,29 +12073,24 @@ /* Skip 3 cache entries */ // _STORE_ATTR { - v = stack_pointer[-2]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), name, PyStackRef_AsPyObjectBorrow(v)); _PyFrame_StackPointerInvalidate(frame); - assert(stack_pointer == _PyFrame_GetStackPointer(frame)); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); - _PyStackRef tmp = owner; - owner = PyStackRef_NULL; - stack_pointer[-1] = owner; - PyStackRef_CLOSE(tmp); + PyStackRef_CLOSE(owner); _PyFrame_StackPointerInvalidate(frame); - assert(stack_pointer == _PyFrame_GetStackPointer(frame)); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_StackPointerValidate(frame); - tmp = v; - v = PyStackRef_NULL; - stack_pointer[-2] = v; - PyStackRef_CLOSE(tmp); + PyStackRef_XCLOSE(v); _PyFrame_StackPointerInvalidate(frame); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { JUMP_TO_LABEL(error); } diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 9133af142723484..91b424773224e4b 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -59,7 +59,6 @@ static void *opcode_targets_table[256] = { &&TARGET_CONVERT_VALUE, &&TARGET_COPY, &&TARGET_COPY_FREE_VARS, - &&TARGET_DELETE_ATTR, &&TARGET_DELETE_DEREF, &&TARGET_DELETE_FAST, &&TARGET_DICT_MERGE, @@ -128,6 +127,7 @@ static void *opcode_targets_table[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_RESUME, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, @@ -376,7 +376,7 @@ static void *opcode_tracing_targets_table[256] = { &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, - &&TARGET_TRACE_RECORD, + &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, @@ -601,7 +601,6 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONTAINS_OP_SET(TAIL_CALL_PARAMS static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONVERT_VALUE(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COPY(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COPY_FREE_VARS(TAIL_CALL_PARAMS); -static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_ATTR(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_DEREF(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_FAST(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_SUBSCR(TAIL_CALL_PARAMS); @@ -845,7 +844,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [CONVERT_VALUE] = _TAIL_CALL_CONVERT_VALUE, [COPY] = _TAIL_CALL_COPY, [COPY_FREE_VARS] = _TAIL_CALL_COPY_FREE_VARS, - [DELETE_ATTR] = _TAIL_CALL_DELETE_ATTR, [DELETE_DEREF] = _TAIL_CALL_DELETE_DEREF, [DELETE_FAST] = _TAIL_CALL_DELETE_FAST, [DELETE_SUBSCR] = _TAIL_CALL_DELETE_SUBSCR, @@ -1007,6 +1005,7 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE, [WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START, [YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE, + [117] = _TAIL_CALL_UNKNOWN_OPCODE, [118] = _TAIL_CALL_UNKNOWN_OPCODE, [119] = _TAIL_CALL_UNKNOWN_OPCODE, [120] = _TAIL_CALL_UNKNOWN_OPCODE, @@ -1103,7 +1102,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [CONVERT_VALUE] = _TAIL_CALL_TRACE_RECORD, [COPY] = _TAIL_CALL_TRACE_RECORD, [COPY_FREE_VARS] = _TAIL_CALL_TRACE_RECORD, - [DELETE_ATTR] = _TAIL_CALL_TRACE_RECORD, [DELETE_DEREF] = _TAIL_CALL_TRACE_RECORD, [DELETE_FAST] = _TAIL_CALL_TRACE_RECORD, [DELETE_SUBSCR] = _TAIL_CALL_TRACE_RECORD, @@ -1265,6 +1263,7 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_TRACE_RECORD, [WITH_EXCEPT_START] = _TAIL_CALL_TRACE_RECORD, [YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD, + [117] = _TAIL_CALL_UNKNOWN_OPCODE, [118] = _TAIL_CALL_UNKNOWN_OPCODE, [119] = _TAIL_CALL_UNKNOWN_OPCODE, [120] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 8fd67f955e153c2..3ad23c3a74f7087 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2149,13 +2149,6 @@ break; } - case _DELETE_ATTR: { - CHECK_STACK_BOUNDS(-1); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - break; - } - case _STORE_GLOBAL: { CHECK_STACK_BOUNDS(-1); stack_pointer += -1; From f48a1fe34443dba78cf72fc269e115f63f694649 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 6 Jul 2026 13:00:05 +0300 Subject: [PATCH 42/61] gh-153171: Produce specialized syntax errors for 'not' after an operator in more positions (GH-153175) Move the invalid_factor rule from term to factor and the invalid_arithmetic rule from shift_expr to sum, so that they are tried at all positions where the invalid construct can occur. Previously a generic "invalid syntax" error was reported for constructs like "1 << 2 + not x" or "1 * + not x". Co-authored-by: Claude Fable 5 --- Grammar/python.gram | 4 +- Lib/test/test_syntax.py | 16 ++++ ...07-06-18-00-00.gh-issue-153171.errloc1.rst | 3 + Parser/parser.c | 86 +++++++++---------- 4 files changed, 64 insertions(+), 45 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-18-00-00.gh-issue-153171.errloc1.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 221629a6230270d..ac1b4a64f38c75a 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -835,7 +835,6 @@ bitwise_and[expr_ty]: shift_expr[expr_ty]: | a=shift_expr '<<' b=sum { _PyAST_BinOp(a, LShift, b, EXTRA) } | a=shift_expr '>>' b=sum { _PyAST_BinOp(a, RShift, b, EXTRA) } - | invalid_arithmetic | sum # Arithmetic operators @@ -844,6 +843,7 @@ shift_expr[expr_ty]: sum[expr_ty]: | a=sum '+' b=term { _PyAST_BinOp(a, Add, b, EXTRA) } | a=sum '-' b=term { _PyAST_BinOp(a, Sub, b, EXTRA) } + | invalid_arithmetic | term term[expr_ty]: @@ -852,7 +852,6 @@ term[expr_ty]: | a=term '//' b=factor { _PyAST_BinOp(a, FloorDiv, b, EXTRA) } | a=term '%' b=factor { _PyAST_BinOp(a, Mod, b, EXTRA) } | a=term '@' b=factor { CHECK_VERSION(expr_ty, 5, "The '@' operator is", _PyAST_BinOp(a, MatMult, b, EXTRA)) } - | invalid_factor | factor factor[expr_ty] (memo): @@ -860,6 +859,7 @@ factor[expr_ty] (memo): | '-' a=factor { _PyAST_UnaryOp(USub, a, EXTRA) } | '~' a=factor { _PyAST_UnaryOp(Invert, a, EXTRA) } | power + | invalid_factor power[expr_ty]: | a=await_primary '**' b=factor { _PyAST_BinOp(a, Pow, b, EXTRA) } diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 013917614178fde..29278d928fbb402 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -2268,6 +2268,22 @@ Traceback (most recent call last): SyntaxError: 'not' after an operator must be parenthesized +>>> 1 << 2 + not 3 +Traceback (most recent call last): +SyntaxError: 'not' after an operator must be parenthesized + +>>> 1 >> 2 * not 3 +Traceback (most recent call last): +SyntaxError: 'not' after an operator must be parenthesized + +>>> 3 * + not 3 +Traceback (most recent call last): +SyntaxError: 'not' after an operator must be parenthesized + +>>> 3 ** - not 3 +Traceback (most recent call last): +SyntaxError: 'not' after an operator must be parenthesized + # Check that we don't introduce misleading errors >>> not 1 */ 2 Traceback (most recent call last): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-18-00-00.gh-issue-153171.errloc1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-18-00-00.gh-issue-153171.errloc1.rst new file mode 100644 index 000000000000000..aa3171b701894d7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-06-18-00-00.gh-issue-153171.errloc1.rst @@ -0,0 +1,3 @@ +Improve syntax error messages for misplaced ``not`` after an operator +in contexts where a generic "invalid syntax" error was previously reported, +such as ``1 << 2 + not x`` and ``1 * + not x``. diff --git a/Parser/parser.c b/Parser/parser.c index 8f218077a8b9033..4f4fd3ed46d1f02 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -360,7 +360,7 @@ static char *soft_keywords[] = { #define invalid_tstring_replacement_field_type 1271 #define invalid_tstring_conversion_character_type 1272 #define invalid_string_tstring_concat_type 1273 -#define invalid_arithmetic_type 1274 +#define invalid_arithmetic_type 1274 // Left-recursive #define invalid_factor_type 1275 #define invalid_type_params_type 1276 #define invalid_bitwise_and_type 1277 // Left-recursive @@ -13933,7 +13933,7 @@ bitwise_and_raw(Parser *p) } // Left-recursive -// shift_expr: shift_expr '<<' sum | shift_expr '>>' sum | invalid_arithmetic | sum +// shift_expr: shift_expr '<<' sum | shift_expr '>>' sum | sum static expr_ty shift_expr_raw(Parser *); static expr_ty shift_expr_rule(Parser *p) @@ -14068,25 +14068,6 @@ shift_expr_raw(Parser *p) D(fprintf(stderr, "%*c%s shift_expr[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "shift_expr '>>' sum")); } - if (p->call_invalid_rules) { // invalid_arithmetic - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> shift_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_arithmetic")); - void *invalid_arithmetic_var; - if ( - (invalid_arithmetic_var = invalid_arithmetic_rule(p)) // invalid_arithmetic - ) - { - D(fprintf(stderr, "%*c+ shift_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_arithmetic")); - _res = invalid_arithmetic_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s shift_expr[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_arithmetic")); - } { // sum if (p->error_indicator) { p->level--; @@ -14113,7 +14094,7 @@ shift_expr_raw(Parser *p) } // Left-recursive -// sum: sum '+' term | sum '-' term | term +// sum: sum '+' term | sum '-' term | invalid_arithmetic | term static expr_ty sum_raw(Parser *); static expr_ty sum_rule(Parser *p) @@ -14248,6 +14229,25 @@ sum_raw(Parser *p) D(fprintf(stderr, "%*c%s sum[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "sum '-' term")); } + if (p->call_invalid_rules) { // invalid_arithmetic + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> sum[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_arithmetic")); + void *invalid_arithmetic_var; + if ( + (invalid_arithmetic_var = invalid_arithmetic_rule(p)) // invalid_arithmetic + ) + { + D(fprintf(stderr, "%*c+ sum[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_arithmetic")); + _res = invalid_arithmetic_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s sum[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_arithmetic")); + } { // term if (p->error_indicator) { p->level--; @@ -14280,7 +14280,6 @@ sum_raw(Parser *p) // | term '//' factor // | term '%' factor // | term '@' factor -// | invalid_factor // | factor static expr_ty term_raw(Parser *); static expr_ty @@ -14533,25 +14532,6 @@ term_raw(Parser *p) D(fprintf(stderr, "%*c%s term[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "term '@' factor")); } - if (p->call_invalid_rules) { // invalid_factor - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> term[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_factor")); - void *invalid_factor_var; - if ( - (invalid_factor_var = invalid_factor_rule(p)) // invalid_factor - ) - { - D(fprintf(stderr, "%*c+ term[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_factor")); - _res = invalid_factor_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s term[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_factor")); - } { // factor if (p->error_indicator) { p->level--; @@ -14577,7 +14557,7 @@ term_raw(Parser *p) return _res; } -// factor: '+' factor | '-' factor | '~' factor | power +// factor: '+' factor | '-' factor | '~' factor | power | invalid_factor static expr_ty factor_rule(Parser *p) { @@ -14730,6 +14710,25 @@ factor_rule(Parser *p) D(fprintf(stderr, "%*c%s factor[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "power")); } + if (p->call_invalid_rules) { // invalid_factor + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> factor[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_factor")); + void *invalid_factor_var; + if ( + (invalid_factor_var = invalid_factor_rule(p)) // invalid_factor + ) + { + D(fprintf(stderr, "%*c+ factor[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_factor")); + _res = invalid_factor_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s factor[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_factor")); + } _res = NULL; done: _PyPegen_insert_memo(p, _mark, factor_type, _res); @@ -28410,6 +28409,7 @@ invalid_string_tstring_concat_rule(Parser *p) return _res; } +// Left-recursive // invalid_arithmetic: sum ('+' | '-' | '*' | '/' | '%' | '//' | '@') 'not' inversion static void * invalid_arithmetic_rule(Parser *p) From bca7b6b3d5801f3a7a5922a342b204152cc5e3c0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 6 Jul 2026 16:49:17 +0300 Subject: [PATCH 43/61] Add tests for syntax error messages that had no test coverage (GH-153192) "illegal target for annotation" and "cannot use dict unpacking here" were not tested at all, and "f-string: expecting '!', or ':', or '}'" was only tested for its t-string variant. Co-authored-by: Claude Fable 5 --- Lib/test/test_fstring.py | 3 +++ Lib/test/test_syntax.py | 10 ++++++++++ Lib/test/test_unpack_ex.py | 14 ++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 5cc02c30ec2ba33..9a8e56836fc671c 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1706,6 +1706,9 @@ def test_invalid_syntax_error_message(self): with self.assertRaisesRegex(SyntaxError, "f-string: expecting '=', or '!', or ':', or '}'"): compile("f'{a $ b}'", "?", "exec") + with self.assertRaisesRegex(SyntaxError, + "f-string: expecting '!', or ':', or '}'"): + compile("f'{a=b}'", "?", "exec") def test_with_two_commas_in_format_specifier(self): error_msg = re.escape("Cannot specify ',' with ','.") diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 29278d928fbb402..a63042055210c5c 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -2238,6 +2238,16 @@ Traceback (most recent call last): SyntaxError: only single target (not list) can be annotated +>>> 1: int +Traceback (most recent call last): +SyntaxError: illegal target for annotation +>>> -x: int = 1 +Traceback (most recent call last): +SyntaxError: illegal target for annotation +>>> (x for x in y): int +Traceback (most recent call last): +SyntaxError: illegal target for annotation + # 'not' after operators: >>> 3 + not 3 diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py index 33c96b84964b591..4fe19765cacf110 100644 --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -355,6 +355,20 @@ ^^^ SyntaxError: cannot use dict unpacking in a dictionary value + >>> (**a) + Traceback (most recent call last): + ... + (**a) + ^^ + SyntaxError: cannot use dict unpacking here + + >>> {**a for a in {1: 2}.items(): b} + Traceback (most recent call last): + ... + {**a for a in {1: 2}.items(): b} + ^^ + SyntaxError: cannot use dict unpacking here + # Generator expression in function arguments From 24d6f09ebd8e883dcabcf9e7dfaee23e7b427392 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:25:32 +0300 Subject: [PATCH 44/61] gh-145098: Use `macos-26[-intel]` instead of `macos-15[-intel]` in `{jit,tail-call}.yml` (#153194) --- .github/workflows/jit.yml | 4 ++-- .github/workflows/tail-call.yml | 4 ++-- .pre-commit-config.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 846c90d2525d253..524a7baa3fd626f 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -102,9 +102,9 @@ jobs: - false include: - target: x86_64-apple-darwin/clang - runner: macos-15-intel + runner: macos-26-intel - target: aarch64-apple-darwin/clang - runner: macos-15 + runner: macos-26 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index f5b174d87d84486..139724de34870c2 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -32,9 +32,9 @@ jobs: matrix: include: - target: x86_64-apple-darwin/clang - runner: macos-15-intel + runner: macos-26-intel - target: aarch64-apple-darwin/clang - runner: macos-15 + runner: macos-26 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6c7f1b93e66e879..615ba587c6a4005 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -111,7 +111,7 @@ repos: - id: check-readthedocs - repo: https://github.com/rhysd/actionlint - rev: 393031adb9afb225ee52ae2ccd7a5af5525e03e8 # frozen: v1.7.11 + rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # frozen: v1.7.12 hooks: - id: actionlint From dcd75bab51b8142de22411a7ab00e174f91da7ee Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Jul 2026 16:47:55 +0200 Subject: [PATCH 45/61] gh-148286: Remove invalid test in `test_decodeescape` (#153187) --- Lib/test/test_capi/test_bytes.py | 2 +- Tools/ubsan/suppressions.txt | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py index 410ebab729c2cf4..c591e986bbce35f 100644 --- a/Lib/test/test_capi/test_bytes.py +++ b/Lib/test/test_capi/test_bytes.py @@ -222,10 +222,10 @@ def test_decodeescape(self): self.assertEqual(decodeescape(br'x\xa\xy', 'replace'), b'x??y') self.assertEqual(decodeescape(br'x\xa\xy', 'ignore'), b'xy') self.assertRaises(ValueError, decodeescape, b'\\', 'spam') - self.assertEqual(decodeescape(NULL), b'') self.assertRaises(OverflowError, decodeescape, b'abc', NULL, PY_SSIZE_T_MAX) self.assertRaises(OverflowError, decodeescape, NULL, NULL, PY_SSIZE_T_MAX) + # INVALID decodeescape(NULL) # CRASHES decodeescape(b'abc', NULL, -1) # CRASHES decodeescape(NULL, NULL, 1) diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt index a00e256b3336182..e3679bc421f4205 100644 --- a/Tools/ubsan/suppressions.txt +++ b/Tools/ubsan/suppressions.txt @@ -20,6 +20,3 @@ pointer-overflow:Modules/_zstd/decompressor.c # Modules/_io/stringio.c:350:24: runtime error: addition of unsigned offset to 0x7fd01ec25850 overflowed to 0x7fd01ec2584c pointer-overflow:Modules/_io/stringio.c - -# Objects/bytesobject.c:1190:25: runtime error: applying zero offset to null pointer -pointer-overflow:Objects/bytesobject.c From 573bcfdaff188059a97d042a3c7ebec9db229762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?tonghuaroot=20=28=E7=AB=A5=E8=AF=9D=29?= Date: Mon, 6 Jul 2026 22:50:15 +0800 Subject: [PATCH 46/61] gh-152849: Fix `OverflowError` message for out-of-range timestamps in the `time` module (#152850) Co-authored-by: Stan Ulbrych --- Lib/test/test_time.py | 11 +++++++++++ .../2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst | 2 ++ Python/pytime.c | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 1850f053aaffd66..985984b55123ce6 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -1013,6 +1013,17 @@ def test_FromSecondsObject(self): with self.assertRaises(ValueError): _PyTime_FromSecondsObject(float('nan'), time_rnd) + def test_FromSecondsObject_float_overflow_message(self): + # Float path must report a PyTime_t overflow, like the integer path. + from _testinternalcapi import _PyTime_FromSecondsObject + for value in (PyTime_MAX, PyTime_MIN): + for time_rnd, _ in ROUNDING_MODES: + with self.subTest(value=value, time_rnd=time_rnd): + with self.assertRaisesRegex( + OverflowError, + "timestamp out of range for C PyTime_t"): + _PyTime_FromSecondsObject(value, time_rnd) + def test_AsSecondsDouble(self): from _testcapi import PyTime_AsSecondsDouble diff --git a/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst b/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst new file mode 100644 index 000000000000000..053a5dfea3f3ff4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-13-30-00.gh-issue-152849.K9dRvP.rst @@ -0,0 +1,2 @@ +Out-of-range float and integer timestamps now raise :exc:`OverflowError` +with the same message. Patch by tonghuaroot. diff --git a/Python/pytime.c b/Python/pytime.c index 399ff59ad01ab69..53c82736137a16b 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -107,7 +107,7 @@ static void pytime_overflow(void) { PyErr_SetString(PyExc_OverflowError, - "timestamp too large to convert to C PyTime_t"); + "timestamp out of range for C PyTime_t"); } @@ -636,7 +636,7 @@ pytime_from_double(PyTime_t *tp, double value, _PyTime_round_t round, /* See comments in pytime_double_to_denominator */ if (!((double)PyTime_MIN <= d && d < -(double)PyTime_MIN)) { - pytime_time_t_overflow(); + pytime_overflow(); *tp = 0; return -1; } From 2a7a6499489fddcbe7f3898b5f5ec9c6e0c827c4 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Mon, 6 Jul 2026 08:40:45 -0700 Subject: [PATCH 47/61] Docs: Link to the `contextlib.chdir` context manager in the `os.chdir` docs (#153152) Co-authored-by: Stan Ulbrych --- Doc/library/os.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 7b043f257ca0b57..6331ba4a034c5c6 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2180,6 +2180,11 @@ features: .. audit-event:: os.chdir path os.chdir + .. seealso:: + + The :func:`contextlib.chdir` context manager, which changes the current + working directory on entering and restores the previous one on exit. + .. versionchanged:: 3.3 Added support for specifying *path* as a file descriptor on some platforms. From 0048a8ed798e4916ad3acf6872b15de72e4e92e4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 6 Jul 2026 17:44:21 +0200 Subject: [PATCH 48/61] gh-152785: Upgrade Ubuntu from 24.04 to 26.04 in GitHub Actions (#152717) * Replace "ubuntu-24.04" with "ubuntu-26.04". * Replace "ubuntu-latest" with "ubuntu-26.04" for Cross build Linux. * Replace "ubuntu-latest" with "ubuntu-slim" for small workloads. * Update ".github/actionlint.yaml" to allow "ubuntu-26.04" and "ubuntu-26.04-arm" images. * Install Ubuntu libmpdec-dev package, rather than installing libmpdec from source (tarball). * No longer run https://apt.llvm.org/llvm.sh, since ubuntu-26.04 provides clang-21 by default. Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .github/actionlint.yaml | 7 ++++++ .github/workflows/add-issue-header.yml | 2 +- .github/workflows/build.yml | 22 +++++++++---------- .github/workflows/jit.yml | 14 +++++------- .../workflows/new-bugs-announce-notifier.yml | 2 +- .github/workflows/posix-deps-apt.sh | 20 +++-------------- .github/workflows/require-pr-label.yml | 4 ++-- .github/workflows/reusable-docs.yml | 2 +- .github/workflows/reusable-emscripten.yml | 2 +- .github/workflows/reusable-san.yml | 11 ++-------- .github/workflows/reusable-ubuntu.yml | 2 +- .github/workflows/reusable-wasi.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/tail-call.yml | 9 ++++---- .github/workflows/verify-expat.yml | 2 +- 15 files changed, 43 insertions(+), 60 deletions(-) diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index eacfff24889021b..61ee08db9919bb9 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -1,5 +1,12 @@ config-variables: null +# Pending release of actionlint > 1.7.12 for ubuntu-26.04* support: +# https://github.com/rhysd/actionlint/pull/683 +self-hosted-runner: + labels: + - ubuntu-26.04 + - ubuntu-26.04-arm + paths: .github/workflows/**/*.yml: ignore: diff --git a/.github/workflows/add-issue-header.yml b/.github/workflows/add-issue-header.yml index 09da61a470ff959..55095f17bb4cce9 100644 --- a/.github/workflows/add-issue-header.yml +++ b/.github/workflows/add-issue-header.yml @@ -17,7 +17,7 @@ permissions: jobs: add-header: - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: issues: write timeout-minutes: 5 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ef98f556cb205b..b541dbd0c23d326 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,7 +53,7 @@ jobs: 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 + runs-on: ubuntu-26.04 container: image: ghcr.io/python/autoconf:2025.01.02.12581854023 timeout-minutes: 60 @@ -96,7 +96,7 @@ jobs: name: 'Check if generated 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 + runs-on: ubuntu-26.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-tests == 'true' @@ -239,18 +239,18 @@ jobs: - false - true os: - - ubuntu-24.04 - - ubuntu-24.04-arm + - ubuntu-26.04 + - ubuntu-26.04-arm exclude: # Do not test BOLT with free-threading, to conserve resources - bolt: true free-threading: true # BOLT currently crashes during instrumentation on aarch64 - - os: ubuntu-24.04-arm + - os: ubuntu-26.04-arm bolt: true include: # Enable CPU-intensive tests on ARM (default build only) - - os: ubuntu-24.04-arm + - os: ubuntu-26.04-arm bolt: false free-threading: false test-opts: '-u cpu' @@ -270,7 +270,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04] + os: [ubuntu-26.04] ssllib: # See Tools/ssl/make_ssl_data.py for notes on adding a new version ## OpenSSL @@ -346,7 +346,7 @@ jobs: - arch: aarch64 runs-on: macos-26 - arch: x86_64 - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 runs-on: ${{ matrix.runs-on }} steps: @@ -393,7 +393,7 @@ jobs: test-hypothesis: name: "Hypothesis tests on Ubuntu" - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-ubuntu == 'true' @@ -504,7 +504,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04] + os: [ubuntu-26.04] env: OPENSSL_VER: 3.5.7 PYTHONSTRICTEXTENSIONBUILD: 1 @@ -568,7 +568,7 @@ jobs: cross-build-linux: name: Cross build Linux - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 timeout-minutes: 60 needs: build-context if: needs.build-context.outputs.run-ubuntu == 'true' diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 524a7baa3fd626f..813589c2bc14c8b 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -29,7 +29,7 @@ env: jobs: interpreter: name: Interpreter (Debug) - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -145,9 +145,9 @@ jobs: - false include: - target: x86_64-unknown-linux-gnu/gcc - runner: ubuntu-24.04 + runner: ubuntu-26.04 - target: aarch64-unknown-linux-gnu/gcc - runner: ubuntu-24.04-arm + runner: ubuntu-26.04-arm steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: @@ -160,8 +160,7 @@ jobs: sudo ./.github/workflows/posix-deps-apt.sh - name: Build run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }} - export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH" + # On ubuntu-26.04 image, clang is clang-21 by default ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '' }} make all --jobs 4 - name: Test @@ -171,7 +170,7 @@ jobs: linux-extras: name: ${{ matrix.name }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 strategy: fail-fast: false @@ -202,8 +201,7 @@ jobs: sudo ./.github/workflows/posix-deps-apt.sh - name: Build run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }} - export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH" + # On ubuntu-26.04 image, clang is clang-21 by default if [ "${{ matrix.use_clang }}" = "true" ]; then export CC=clang-${{ env.LLVM_VERSION }} fi diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml index 9c19adb7ffda707..864d0f48904bcc3 100644 --- a/.github/workflows/new-bugs-announce-notifier.yml +++ b/.github/workflows/new-bugs-announce-notifier.yml @@ -10,7 +10,7 @@ permissions: jobs: notify-new-bugs-announce: - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: issues: read timeout-minutes: 10 diff --git a/.github/workflows/posix-deps-apt.sh b/.github/workflows/posix-deps-apt.sh index f241fccdeb2a32a..803204635abfe11 100755 --- a/.github/workflows/posix-deps-apt.sh +++ b/.github/workflows/posix-deps-apt.sh @@ -5,37 +5,23 @@ apt-get -yq --no-install-recommends install \ build-essential \ pkg-config \ cmake \ + curl \ gdb \ lcov \ libb2-dev \ libbz2-dev \ libffi-dev \ - libgdbm-dev \ libgdbm-compat-dev \ + libgdbm-dev \ liblzma-dev \ + libmpdec-dev \ libncurses5-dev \ libreadline6-dev \ libsqlite3-dev \ libssl-dev \ libzstd-dev \ - lzma \ - lzma-dev \ strace \ tk-dev \ uuid-dev \ xvfb \ zlib1g-dev - -# Workaround missing libmpdec-dev on ubuntu 24.04 by building mpdecimal -# from source. ppa:ondrej/php (launchpad.net) are unreliable -# (https://status.canonical.com) so fetch the tarball directly -# from the upstream host. -# https://www.bytereef.org/mpdecimal/ -MPDECIMAL_VERSION=4.0.1 -curl -fsSL "https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-${MPDECIMAL_VERSION}.tar.gz" \ - | tar -xz -C /tmp -(cd "/tmp/mpdecimal-${MPDECIMAL_VERSION}" \ - && ./configure --prefix=/usr/local \ - && make -j"$(nproc)" \ - && make install) -ldconfig diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml index f3e2666879530f9..8af254c10786e1b 100644 --- a/.github/workflows/require-pr-label.yml +++ b/.github/workflows/require-pr-label.yml @@ -11,7 +11,7 @@ jobs: label-dnm: name: DO-NOT-MERGE if: github.repository_owner == 'python' - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: pull-requests: read timeout-minutes: 10 @@ -28,7 +28,7 @@ jobs: label-reviews: name: Unresolved review if: github.repository_owner == 'python' - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: pull-requests: read timeout-minutes: 10 diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index cac481d26a8d0cc..a792553a63b8bab 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-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 diff --git a/.github/workflows/reusable-emscripten.yml b/.github/workflows/reusable-emscripten.yml index 46664522aa6d793..0205203ef77a9f5 100644 --- a/.github/workflows/reusable-emscripten.yml +++ b/.github/workflows/reusable-emscripten.yml @@ -12,7 +12,7 @@ env: jobs: build-emscripten-reusable: name: 'build and test' - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 40 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index d29f4e83b48dac8..405fa36454a62bf 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -26,7 +26,7 @@ jobs: && ' (free-threading)' || '' }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -37,14 +37,7 @@ jobs: - name: Install dependencies run: | sudo ./.github/workflows/posix-deps-apt.sh - # Install clang - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 21 - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-21 100 - sudo update-alternatives --set clang /usr/bin/clang-21 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 100 - sudo update-alternatives --set clang++ /usr/bin/clang++-21 + # On ubuntu-26.04 image, clang is clang-21 by default if [ "${SANITIZER}" = "TSan" ]; then # Reduce ASLR to avoid TSan crashing diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml index cd810babb7a9d6e..4ecc541e6aa7d02 100644 --- a/.github/workflows/reusable-ubuntu.yml +++ b/.github/workflows/reusable-ubuntu.yml @@ -49,7 +49,7 @@ jobs: - name: Install Clang and BOLT if: ${{ fromJSON(inputs.bolt-optimizations) }} run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 21 + # On ubuntu-26.04 image, LLVM is LLVM-21 by default sudo apt-get install --no-install-recommends bolt-21 echo PATH="$(llvm-config-21 --bindir):$PATH" >> $GITHUB_ENV - name: Configure OpenSSL env vars diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml index 9675c39b86a24c4..b0dda62d0b291c2 100644 --- a/.github/workflows/reusable-wasi.yml +++ b/.github/workflows/reusable-wasi.yml @@ -12,7 +12,7 @@ env: jobs: build-wasi-reusable: name: 'build and test' - runs-on: ubuntu-24.04-arm + runs-on: ubuntu-26.04-arm timeout-minutes: 60 env: WASMTIME_VERSION: 38.0.3 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 37f78519dedc329..0283e9f621dcf05 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -10,7 +10,7 @@ permissions: jobs: stale: if: github.repository_owner == 'python' - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: actions: write pull-requests: write diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index 139724de34870c2..81e8235f236ea70 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -66,13 +66,13 @@ jobs: matrix: include: - target: x86_64-unknown-linux-gnu/gcc - runner: ubuntu-24.04 + runner: ubuntu-26.04 configure_flags: --with-pydebug - target: x86_64-unknown-linux-gnu/gcc-free-threading - runner: ubuntu-24.04 + runner: ubuntu-26.04 configure_flags: --disable-gil - target: aarch64-unknown-linux-gnu/gcc - runner: ubuntu-24.04-arm + runner: ubuntu-26.04-arm configure_flags: --with-pydebug steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -83,8 +83,7 @@ jobs: python-version: '3.11' - name: Build run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }} - export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH" + # On ubuntu-26.04 image, clang is clang-21 by default CC=clang-${{ env.LLVM_VERSION }} ./configure --with-tail-call-interp ${{ matrix.configure_flags }} make all --jobs 4 - name: Test diff --git a/.github/workflows/verify-expat.yml b/.github/workflows/verify-expat.yml index bae93a4d9ac0a2b..b96e71b487dbe57 100644 --- a/.github/workflows/verify-expat.yml +++ b/.github/workflows/verify-expat.yml @@ -20,7 +20,7 @@ concurrency: jobs: verify: - runs-on: ubuntu-latest + runs-on: ubuntu-slim timeout-minutes: 5 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 From aadb0539d678760cc1e1a822c8e251bbc61b1417 Mon Sep 17 00:00:00 2001 From: thexai <58434170+thexai@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:32:36 +0200 Subject: [PATCH 49/61] gh-152433: Allow _ssl module to build for Windows UWP API set (GH-152791) --- ...2026-07-01-16-38-24.gh-issue-152433.jvEiHh.rst | 1 + Modules/_ssl.c | 15 ++++++++------- Modules/_ssl/debughelpers.c | 14 +++++++++----- 3 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-07-01-16-38-24.gh-issue-152433.jvEiHh.rst diff --git a/Misc/NEWS.d/next/Windows/2026-07-01-16-38-24.gh-issue-152433.jvEiHh.rst b/Misc/NEWS.d/next/Windows/2026-07-01-16-38-24.gh-issue-152433.jvEiHh.rst new file mode 100644 index 000000000000000..d5aead5fbe0b9e2 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-07-01-16-38-24.gh-issue-152433.jvEiHh.rst @@ -0,0 +1 @@ +:mod:`ssl`: improve UWP build compatibility. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index f451c0ce7364ab9..20564e1ba4165a6 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4924,16 +4924,16 @@ static PyObject * _ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath) /*[clinic end generated code: output=dd74b3c524dd2723 input=832769a0734b8c4d]*/ { - FILE *f; - DH *dh; - -#if defined(MS_WINDOWS) && defined(Py_DEBUG) +#if defined(MS_WINDOWS_APP) && !defined(MS_WINDOWS_DESKTOP) + PyErr_SetString(PyExc_NotImplementedError, "load_dh_params: unavailable on UWP build"); + return NULL; +#elif defined(MS_WINDOWS) && defined(Py_DEBUG) PyErr_SetString(PyExc_NotImplementedError, "load_dh_params: unavailable on Windows debug build"); return NULL; -#endif - - f = Py_fopen(filepath, "rb"); +#else + FILE* f = Py_fopen(filepath, "rb"); + DH* dh; if (f == NULL) return NULL; @@ -4959,6 +4959,7 @@ _ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath) } DH_free(dh); Py_RETURN_NONE; +#endif } /*[clinic input] diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index e0cb7ca9a09f91e..fb9043994f08f9e 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -182,14 +182,17 @@ static int _PySSLContext_set_keylog_filename(PyObject *op, PyObject *arg, void *Py_UNUSED(closure)) { - PySSLContext *self = PySSLContext_CAST(op); - FILE *fp; - -#if defined(MS_WINDOWS) && defined(Py_DEBUG) +#if defined(MS_WINDOWS_APP) && !defined(MS_WINDOWS_DESKTOP) + PyErr_SetString(PyExc_NotImplementedError, + "set_keylog_filename: unavailable on UWP build"); + return -1; +#elif defined(MS_WINDOWS) && defined(Py_DEBUG) PyErr_SetString(PyExc_NotImplementedError, "set_keylog_filename: unavailable on Windows debug build"); return -1; -#endif +#else + PySSLContext* self = PySSLContext_CAST(op); + FILE* fp; /* Reset variables and callback first */ SSL_CTX_set_keylog_callback(self->ctx, NULL); @@ -231,4 +234,5 @@ _PySSLContext_set_keylog_filename(PyObject *op, PyObject *arg, PySSL_END_ALLOW_THREADS(self) SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback); return 0; +#endif } From f804cddb9d529a85de07bddfa43a913dcc9b6b1e Mon Sep 17 00:00:00 2001 From: Zain Nadeem Date: Mon, 6 Jul 2026 22:14:28 +0500 Subject: [PATCH 50/61] gh-150880: Clarify DirEntry.path construction semantics (GH-153218) --- Doc/library/os.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 6331ba4a034c5c6..5858d9733c57796 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3037,10 +3037,16 @@ features: .. attribute:: path - The entry's full path name: equivalent to ``os.path.join(scandir_path, - entry.name)`` where *scandir_path* is the :func:`scandir` *path* - argument. The path is only absolute if the :func:`scandir` *path* - argument was absolute. If the :func:`scandir` *path* + The entry's path name: equivalent to ``os.path.join(scandir_path, + entry.name)`` where *scandir_path* is the original :func:`scandir` + *path* argument. Apart from the filename, the path preserves the + original :func:`scandir` argument. If the :func:`scandir` *path* + argument was relative, the :attr:`path` attribute is also relative. + Changing the current working directory after creating the + :func:`scandir` iterator may cause later uses of :attr:`path` to resolve + differently. On some platforms, the constructed path may not be valid + if the original :func:`scandir` argument was usable for enumeration but + not for joining with the entry name. If the :func:`scandir` *path* argument was a :ref:`file descriptor `, the :attr:`path` attribute is the same as the :attr:`name` attribute. From 3607cc9a799c15b68e476faa6cdc28e329c3aeb4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 6 Jul 2026 21:10:23 +0300 Subject: [PATCH 51/61] gh-153200: Fix math.isqrt() for int subclasses with overridden comparison operators (GH-153203) The final check-and-correct comparison in the arbitrary precision path could call a comparison operator overridden in an int subclass. Compare by value with int's tp_richcompare. --- Lib/test/test_math_integer.py | 18 ++++++++++++++++++ ...-07-06-12-00-00.gh-issue-153200.isqrtLt.rst | 3 +++ Modules/mathintegermodule.c | 10 +++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst diff --git a/Lib/test/test_math_integer.py b/Lib/test/test_math_integer.py index 09a98d93bd636c9..d1bc776dc42391a 100644 --- a/Lib/test/test_math_integer.py +++ b/Lib/test/test_math_integer.py @@ -15,6 +15,19 @@ def __init__(self, value): def __index__(self): return self.value +# int subclass with broken arithmetic operators; implementations must +# convert their arguments to exact ints instead of using these. +class BadIntSubclass(int): + def _binop(self, other='ignored', mod=None): + return 42 + __add__ = __radd__ = __sub__ = __rsub__ = _binop + __mul__ = __rmul__ = __mod__ = __rmod__ = _binop + __divmod__ = __rdivmod__ = __pow__ = __rpow__ = _binop + __floordiv__ = __rfloordiv__ = _binop + __lshift__ = __rlshift__ = __rshift__ = __rrshift__ = _binop + __and__ = __rand__ = __or__ = __ror__ = __xor__ = __rxor__ = _binop + __lt__ = __le__ = __gt__ = __ge__ = _binop + # Here's a pure Python version of the math.integer.factorial algorithm, for # documentation and comparison purposes. # @@ -226,6 +239,11 @@ def test_isqrt(self): self.assertIntEqual(isqrt(False), 0) self.assertIntEqual(isqrt(MyIndexable(1729)), 41) + # Overridden operators of an int subclass must not affect the + # result. + self.assertIntEqual(isqrt(BadIntSubclass(10**20)), 10**10) + self.assertIntEqual(isqrt(BadIntSubclass(10**20 - 1)), 10**10 - 1) + with self.assertRaises(ValueError): isqrt(MyIndexable(-3)) diff --git a/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst b/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst new file mode 100644 index 000000000000000..a27ac73fe31a70a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-06-12-00-00.gh-issue-153200.isqrtLt.rst @@ -0,0 +1,3 @@ +Fix :func:`math.isqrt` returning an incorrect result for arguments not +less than 2**64 that are instances of an :class:`int` subclass with an +overridden comparison operator. diff --git a/Modules/mathintegermodule.c b/Modules/mathintegermodule.c index cfad4154b2d3611..0f660d461e349f8 100644 --- a/Modules/mathintegermodule.c +++ b/Modules/mathintegermodule.c @@ -454,16 +454,20 @@ math_integer_isqrt(PyObject *module, PyObject *n) /* The correct result is either a or a - 1. Figure out which, and decrement a if necessary. */ - /* a_too_large = n < a * a */ + /* a_too_large = n < a * a. Compare by value: n can be an instance + of an int subclass with an overridden __lt__ method. */ b = PyNumber_Multiply(a, a); if (b == NULL) { goto error; } - a_too_large = PyObject_RichCompareBool(n, b, Py_LT); + PyObject *cmp = PyLong_Type.tp_richcompare(n, b, Py_LT); Py_DECREF(b); - if (a_too_large == -1) { + if (cmp == NULL) { goto error; } + assert(PyBool_Check(cmp)); + a_too_large = (cmp == Py_True); + Py_DECREF(cmp); if (a_too_large) { Py_SETREF(a, PyNumber_Subtract(a, _PyLong_GetOne())); From a35ddfaa401dd51efbc044e395e021876a5b0c6c Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 6 Jul 2026 22:46:22 +0300 Subject: [PATCH 52/61] Seed pip caches for docs on `main`/`3.x` branches (#153127) --- .github/workflows/reusable-docs.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index a792553a63b8bab..199e0fd8d181f0b 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -3,6 +3,17 @@ name: Reusable Docs on: workflow_call: workflow_dispatch: + # Pushes to CPython branches seed the pip caches under the exact keys every + # docs PR restores from. Without a branch-scoped copy, each PR saves a + # duplicate into its own refs/pull/N/merge scope that nothing else can read. + push: + branches: + - main + - '3.*' + paths: + - 'Doc/pylock.toml' + - 'Doc/requirements.txt' + - '.github/workflows/reusable-docs.yml' permissions: contents: read From 0ff8c96191588359a2609002f76cd8bbf1a321fb Mon Sep 17 00:00:00 2001 From: Dino Viehland Date: Mon, 6 Jul 2026 12:56:32 -0700 Subject: [PATCH 53/61] gh-150490: Raise PyType_Modified for insertion into split dictionary (take 2) (#152914) Raise PyType_Modified for insertion into split dictionary - now with better locking discipline in free-threaded builds --- Include/internal/pycore_dict.h | 12 + Include/internal/pycore_opcode_metadata.h | 4 +- Include/internal/pycore_typeobject.h | 3 + Include/internal/pycore_uop_ids.h | 2377 ++++++++++----------- Include/internal/pycore_uop_metadata.h | 21 - Lib/test/test_free_threading/test_type.py | 80 +- Modules/_testinternalcapi/test_cases.c.h | 26 +- Objects/dictobject.c | 119 +- Objects/typeobject.c | 26 +- Python/bytecodes.c | 11 +- Python/executor_cases.c.h | 97 - Python/generated_cases.c.h | 26 +- Python/optimizer_cases.c.h | 4 - Python/specialize.c | 8 +- 14 files changed, 1395 insertions(+), 1419 deletions(-) diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index ff6588b3e9718c6..7032b61d7654b89 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -90,6 +90,7 @@ typedef struct { } PyDictUnicodeEntry; extern PyDictKeysObject *_PyDict_NewKeysForClass(PyHeapTypeObject *); +extern void _PyDict_RemoveKeysForClass(PyHeapTypeObject *); extern PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); /* Implementations of the `|` and `|=` operators for dict, used by the @@ -239,6 +240,17 @@ struct _dictkeysobject { see the DK_ENTRIES() / DK_UNICODE_ENTRIES() functions below */ }; +struct _instancekeysobject { + PyTypeObject* dsk_owning_type; + struct _dictkeysobject dsk_keys; +}; + +static inline struct _instancekeysobject *_PyDictKeys_AsSharedKeys(struct _dictkeysobject *keys) +{ + assert(keys->dk_kind == DICT_KEYS_SPLIT); + return _Py_CONTAINER_OF(keys, struct _instancekeysobject, dsk_keys); +} + /* This must be no more than 250, for the prefix size to fit in one byte. */ #define SHARED_KEYS_MAX_SIZE 30 #define NEXT_LOG2_SHARED_KEYS_MAX_SIZE 6 diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 647f6b6cbb989ad..31d2e31573d8c53 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1458,10 +1458,10 @@ _PyOpcode_macro_expansion[256] = { [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 6, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, [LOAD_ATTR_MODULE] = { .nuops = 4, .uops = { { _LOAD_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, OPERAND1_1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } }, - [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, [LOAD_ATTR_PROPERTY] = { .nuops = 7, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_PROPERTY_FRAME, 2, 3 }, { _LOAD_ATTR_PROPERTY_FRAME, OPERAND1_4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_SLOT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_WITH_HINT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 785b77d3e3be81e..c8b888f1c395483 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -148,6 +148,9 @@ extern int _PyType_AddMethod(PyTypeObject *, PyMethodDef *); extern void _PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long flags); +// Raise PyType_Modified with the type lock already held. +extern void _PyType_Modified_Unlocked(PyTypeObject *type); + PyAPI_FUNC(void) _PyType_SetVersion(PyTypeObject *tp, unsigned int version); PyTypeObject *_PyType_LookupByVersion(unsigned int version); diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index cd34aaa9d34afde..c30813f6d800f34 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -195,55 +195,54 @@ extern "C" { #define _GUARD_IS_TRUE_POP 459 #define _GUARD_ITERATOR 460 #define _GUARD_ITER_VIRTUAL 461 -#define _GUARD_KEYS_VERSION 462 -#define _GUARD_LOAD_SUPER_ATTR_METHOD 463 -#define _GUARD_NOS_COMPACT_ASCII 464 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT 465 -#define _GUARD_NOS_DICT_SUBSCRIPT 466 -#define _GUARD_NOS_FLOAT 467 -#define _GUARD_NOS_INT 468 -#define _GUARD_NOS_ITER_VIRTUAL 469 -#define _GUARD_NOS_LIST 470 -#define _GUARD_NOS_NOT_NULL 471 -#define _GUARD_NOS_NULL 472 -#define _GUARD_NOS_OVERFLOWED 473 -#define _GUARD_NOS_TUPLE 474 -#define _GUARD_NOS_TYPE_VERSION 475 -#define _GUARD_NOS_UNICODE 476 -#define _GUARD_NOT_EXHAUSTED_LIST 477 -#define _GUARD_NOT_EXHAUSTED_RANGE 478 -#define _GUARD_NOT_EXHAUSTED_TUPLE 479 -#define _GUARD_THIRD_NULL 480 -#define _GUARD_TOS_ANY_DICT 481 -#define _GUARD_TOS_ANY_SET 482 -#define _GUARD_TOS_DICT 483 -#define _GUARD_TOS_FLOAT 484 -#define _GUARD_TOS_FROZENDICT 485 -#define _GUARD_TOS_FROZENSET 486 -#define _GUARD_TOS_INT 487 -#define _GUARD_TOS_IS_NONE 488 -#define _GUARD_TOS_LIST 489 -#define _GUARD_TOS_NOT_NULL 490 -#define _GUARD_TOS_OVERFLOWED 491 -#define _GUARD_TOS_SET 492 -#define _GUARD_TOS_SLICE 493 -#define _GUARD_TOS_TUPLE 494 -#define _GUARD_TOS_UNICODE 495 -#define _GUARD_TYPE 496 -#define _GUARD_TYPE_ITER 497 -#define _GUARD_TYPE_VERSION 498 -#define _GUARD_TYPE_VERSION_LOCKED 499 -#define _HANDLE_PENDING_AND_DEOPT 500 +#define _GUARD_LOAD_SUPER_ATTR_METHOD 462 +#define _GUARD_NOS_COMPACT_ASCII 463 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT 464 +#define _GUARD_NOS_DICT_SUBSCRIPT 465 +#define _GUARD_NOS_FLOAT 466 +#define _GUARD_NOS_INT 467 +#define _GUARD_NOS_ITER_VIRTUAL 468 +#define _GUARD_NOS_LIST 469 +#define _GUARD_NOS_NOT_NULL 470 +#define _GUARD_NOS_NULL 471 +#define _GUARD_NOS_OVERFLOWED 472 +#define _GUARD_NOS_TUPLE 473 +#define _GUARD_NOS_TYPE_VERSION 474 +#define _GUARD_NOS_UNICODE 475 +#define _GUARD_NOT_EXHAUSTED_LIST 476 +#define _GUARD_NOT_EXHAUSTED_RANGE 477 +#define _GUARD_NOT_EXHAUSTED_TUPLE 478 +#define _GUARD_THIRD_NULL 479 +#define _GUARD_TOS_ANY_DICT 480 +#define _GUARD_TOS_ANY_SET 481 +#define _GUARD_TOS_DICT 482 +#define _GUARD_TOS_FLOAT 483 +#define _GUARD_TOS_FROZENDICT 484 +#define _GUARD_TOS_FROZENSET 485 +#define _GUARD_TOS_INT 486 +#define _GUARD_TOS_IS_NONE 487 +#define _GUARD_TOS_LIST 488 +#define _GUARD_TOS_NOT_NULL 489 +#define _GUARD_TOS_OVERFLOWED 490 +#define _GUARD_TOS_SET 491 +#define _GUARD_TOS_SLICE 492 +#define _GUARD_TOS_TUPLE 493 +#define _GUARD_TOS_UNICODE 494 +#define _GUARD_TYPE 495 +#define _GUARD_TYPE_ITER 496 +#define _GUARD_TYPE_VERSION 497 +#define _GUARD_TYPE_VERSION_LOCKED 498 +#define _HANDLE_PENDING_AND_DEOPT 499 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 501 -#define _INIT_CALL_PY_EXACT_ARGS 502 -#define _INIT_CALL_PY_EXACT_ARGS_0 503 -#define _INIT_CALL_PY_EXACT_ARGS_1 504 -#define _INIT_CALL_PY_EXACT_ARGS_2 505 -#define _INIT_CALL_PY_EXACT_ARGS_3 506 -#define _INIT_CALL_PY_EXACT_ARGS_4 507 -#define _INSERT_NULL 508 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 500 +#define _INIT_CALL_PY_EXACT_ARGS 501 +#define _INIT_CALL_PY_EXACT_ARGS_0 502 +#define _INIT_CALL_PY_EXACT_ARGS_1 503 +#define _INIT_CALL_PY_EXACT_ARGS_2 504 +#define _INIT_CALL_PY_EXACT_ARGS_3 505 +#define _INIT_CALL_PY_EXACT_ARGS_4 506 +#define _INSERT_NULL 507 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -253,1187 +252,1183 @@ 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 _IS_NONE 509 -#define _IS_OP 510 -#define _ITER_CHECK_LIST 511 -#define _ITER_CHECK_RANGE 512 -#define _ITER_CHECK_TUPLE 513 -#define _ITER_JUMP_LIST 514 -#define _ITER_JUMP_RANGE 515 -#define _ITER_JUMP_TUPLE 516 -#define _ITER_NEXT_INLINE 517 -#define _ITER_NEXT_LIST 518 -#define _ITER_NEXT_LIST_TIER_TWO 519 -#define _ITER_NEXT_RANGE 520 -#define _ITER_NEXT_TUPLE 521 +#define _IS_NONE 508 +#define _IS_OP 509 +#define _ITER_CHECK_LIST 510 +#define _ITER_CHECK_RANGE 511 +#define _ITER_CHECK_TUPLE 512 +#define _ITER_JUMP_LIST 513 +#define _ITER_JUMP_RANGE 514 +#define _ITER_JUMP_TUPLE 515 +#define _ITER_NEXT_INLINE 516 +#define _ITER_NEXT_LIST 517 +#define _ITER_NEXT_LIST_TIER_TWO 518 +#define _ITER_NEXT_RANGE 519 +#define _ITER_NEXT_TUPLE 520 #define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT -#define _JUMP_TO_TOP 522 +#define _JUMP_TO_TOP 521 #define _LIST_APPEND LIST_APPEND -#define _LIST_EXTEND 523 -#define _LOAD_ATTR 524 -#define _LOAD_ATTR_CLASS 525 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME 526 -#define _LOAD_ATTR_INSTANCE_VALUE 527 -#define _LOAD_ATTR_METHOD_LAZY_DICT 528 -#define _LOAD_ATTR_METHOD_NO_DICT 529 -#define _LOAD_ATTR_METHOD_WITH_VALUES 530 -#define _LOAD_ATTR_MODULE 531 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 532 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 533 -#define _LOAD_ATTR_PROPERTY_FRAME 534 -#define _LOAD_ATTR_SLOT 535 -#define _LOAD_ATTR_WITH_HINT 536 +#define _LIST_EXTEND 522 +#define _LOAD_ATTR 523 +#define _LOAD_ATTR_CLASS 524 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME 525 +#define _LOAD_ATTR_INSTANCE_VALUE 526 +#define _LOAD_ATTR_METHOD_LAZY_DICT 527 +#define _LOAD_ATTR_METHOD_NO_DICT 528 +#define _LOAD_ATTR_METHOD_WITH_VALUES 529 +#define _LOAD_ATTR_MODULE 530 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 531 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 532 +#define _LOAD_ATTR_PROPERTY_FRAME 533 +#define _LOAD_ATTR_SLOT 534 +#define _LOAD_ATTR_WITH_HINT 535 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 537 +#define _LOAD_BYTECODE 536 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 538 -#define _LOAD_CONST_INLINE_BORROW 539 +#define _LOAD_CONST_INLINE 537 +#define _LOAD_CONST_INLINE_BORROW 538 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 540 -#define _LOAD_FAST_0 541 -#define _LOAD_FAST_1 542 -#define _LOAD_FAST_2 543 -#define _LOAD_FAST_3 544 -#define _LOAD_FAST_4 545 -#define _LOAD_FAST_5 546 -#define _LOAD_FAST_6 547 -#define _LOAD_FAST_7 548 +#define _LOAD_FAST 539 +#define _LOAD_FAST_0 540 +#define _LOAD_FAST_1 541 +#define _LOAD_FAST_2 542 +#define _LOAD_FAST_3 543 +#define _LOAD_FAST_4 544 +#define _LOAD_FAST_5 545 +#define _LOAD_FAST_6 546 +#define _LOAD_FAST_7 547 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 549 -#define _LOAD_FAST_BORROW_0 550 -#define _LOAD_FAST_BORROW_1 551 -#define _LOAD_FAST_BORROW_2 552 -#define _LOAD_FAST_BORROW_3 553 -#define _LOAD_FAST_BORROW_4 554 -#define _LOAD_FAST_BORROW_5 555 -#define _LOAD_FAST_BORROW_6 556 -#define _LOAD_FAST_BORROW_7 557 +#define _LOAD_FAST_BORROW 548 +#define _LOAD_FAST_BORROW_0 549 +#define _LOAD_FAST_BORROW_1 550 +#define _LOAD_FAST_BORROW_2 551 +#define _LOAD_FAST_BORROW_3 552 +#define _LOAD_FAST_BORROW_4 553 +#define _LOAD_FAST_BORROW_5 554 +#define _LOAD_FAST_BORROW_6 555 +#define _LOAD_FAST_BORROW_7 556 #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #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 558 -#define _LOAD_GLOBAL_BUILTINS 559 -#define _LOAD_GLOBAL_MODULE 560 +#define _LOAD_GLOBAL 557 +#define _LOAD_GLOBAL_BUILTINS 558 +#define _LOAD_GLOBAL_MODULE 559 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 561 -#define _LOAD_SMALL_INT_0 562 -#define _LOAD_SMALL_INT_1 563 -#define _LOAD_SMALL_INT_2 564 -#define _LOAD_SMALL_INT_3 565 -#define _LOAD_SPECIAL 566 +#define _LOAD_SMALL_INT 560 +#define _LOAD_SMALL_INT_0 561 +#define _LOAD_SMALL_INT_1 562 +#define _LOAD_SMALL_INT_2 563 +#define _LOAD_SMALL_INT_3 564 +#define _LOAD_SPECIAL 565 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR -#define _LOAD_SUPER_ATTR_METHOD 567 -#define _LOCK_OBJECT 568 -#define _MAKE_CALLARGS_A_TUPLE 569 +#define _LOAD_SUPER_ATTR_METHOD 566 +#define _LOCK_OBJECT 567 +#define _MAKE_CALLARGS_A_TUPLE 568 #define _MAKE_CELL MAKE_CELL -#define _MAKE_FUNCTION 570 -#define _MAKE_HEAP_SAFE 571 -#define _MAKE_WARM 572 +#define _MAKE_FUNCTION 569 +#define _MAKE_HEAP_SAFE 570 +#define _MAKE_WARM 571 #define _MAP_ADD MAP_ADD -#define _MATCH_CLASS 573 +#define _MATCH_CLASS 572 #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 574 -#define _MAYBE_EXPAND_METHOD_KW 575 -#define _MONITOR_CALL 576 -#define _MONITOR_CALL_KW 577 -#define _MONITOR_JUMP_BACKWARD 578 -#define _MONITOR_RESUME 579 +#define _MAYBE_EXPAND_METHOD 573 +#define _MAYBE_EXPAND_METHOD_KW 574 +#define _MONITOR_CALL 575 +#define _MONITOR_CALL_KW 576 +#define _MONITOR_JUMP_BACKWARD 577 +#define _MONITOR_RESUME 578 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT #define _POP_ITER POP_ITER -#define _POP_JUMP_IF_FALSE 580 -#define _POP_JUMP_IF_TRUE 581 +#define _POP_JUMP_IF_FALSE 579 +#define _POP_JUMP_IF_TRUE 580 #define _POP_TOP POP_TOP -#define _POP_TOP_FLOAT 582 -#define _POP_TOP_INT 583 -#define _POP_TOP_NOP 584 -#define _POP_TOP_OPARG 585 -#define _POP_TOP_UNICODE 586 +#define _POP_TOP_FLOAT 581 +#define _POP_TOP_INT 582 +#define _POP_TOP_NOP 583 +#define _POP_TOP_OPARG 584 +#define _POP_TOP_UNICODE 585 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 587 +#define _PUSH_FRAME 586 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 588 -#define _PUSH_TAGGED_ZERO 589 -#define _PY_FRAME_EX 590 -#define _PY_FRAME_GENERAL 591 -#define _PY_FRAME_KW 592 -#define _RECORD_3OS_GEN_FUNC 593 -#define _RECORD_4OS 594 -#define _RECORD_BOUND_METHOD 595 -#define _RECORD_CALLABLE 596 -#define _RECORD_CALLABLE_KW 597 -#define _RECORD_CODE 598 -#define _RECORD_NOS 599 -#define _RECORD_NOS_GEN_FUNC 600 -#define _RECORD_NOS_TYPE 601 -#define _RECORD_TOS 602 -#define _RECORD_TOS_TYPE 603 -#define _REPLACE_WITH_TRUE 604 -#define _RESUME_CHECK 605 +#define _PUSH_NULL_CONDITIONAL 587 +#define _PUSH_TAGGED_ZERO 588 +#define _PY_FRAME_EX 589 +#define _PY_FRAME_GENERAL 590 +#define _PY_FRAME_KW 591 +#define _RECORD_3OS_GEN_FUNC 592 +#define _RECORD_4OS 593 +#define _RECORD_BOUND_METHOD 594 +#define _RECORD_CALLABLE 595 +#define _RECORD_CALLABLE_KW 596 +#define _RECORD_CODE 597 +#define _RECORD_NOS 598 +#define _RECORD_NOS_GEN_FUNC 599 +#define _RECORD_NOS_TYPE 600 +#define _RECORD_TOS 601 +#define _RECORD_TOS_TYPE 602 +#define _REPLACE_WITH_TRUE 603 +#define _RESUME_CHECK 604 #define _RETURN_GENERATOR RETURN_GENERATOR -#define _RETURN_VALUE 606 -#define _RROT_3 607 -#define _SAVE_RETURN_OFFSET 608 -#define _SEND_ASYNC_GEN 609 -#define _SEND_ASYNC_GEN_TIER_TWO 610 -#define _SEND_GEN_FRAME 611 -#define _SEND_VIRTUAL 612 -#define _SEND_VIRTUAL_TIER_TWO 613 +#define _RETURN_VALUE 605 +#define _RROT_3 606 +#define _SAVE_RETURN_OFFSET 607 +#define _SEND_ASYNC_GEN 608 +#define _SEND_ASYNC_GEN_TIER_TWO 609 +#define _SEND_GEN_FRAME 610 +#define _SEND_VIRTUAL 611 +#define _SEND_VIRTUAL_TIER_TWO 612 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE -#define _SET_UPDATE 614 -#define _SPILL_OR_RELOAD 615 -#define _START_EXECUTOR 616 -#define _STORE_ATTR 617 -#define _STORE_ATTR_INSTANCE_VALUE 618 -#define _STORE_ATTR_SLOT 619 -#define _STORE_ATTR_WITH_HINT 620 +#define _SET_UPDATE 613 +#define _SPILL_OR_RELOAD 614 +#define _START_EXECUTOR 615 +#define _STORE_ATTR 616 +#define _STORE_ATTR_INSTANCE_VALUE 617 +#define _STORE_ATTR_SLOT 618 +#define _STORE_ATTR_WITH_HINT 619 #define _STORE_DEREF STORE_DEREF #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 621 -#define _STORE_SUBSCR 622 -#define _STORE_SUBSCR_DICT 623 -#define _STORE_SUBSCR_DICT_KNOWN_HASH 624 -#define _STORE_SUBSCR_LIST_INT 625 -#define _SWAP 626 -#define _SWAP_2 627 -#define _SWAP_3 628 -#define _SWAP_FAST 629 -#define _SWAP_FAST_0 630 -#define _SWAP_FAST_1 631 -#define _SWAP_FAST_2 632 -#define _SWAP_FAST_3 633 -#define _SWAP_FAST_4 634 -#define _SWAP_FAST_5 635 -#define _SWAP_FAST_6 636 -#define _SWAP_FAST_7 637 -#define _TIER2_RESUME_CHECK 638 -#define _TO_BOOL 639 +#define _STORE_SLICE 620 +#define _STORE_SUBSCR 621 +#define _STORE_SUBSCR_DICT 622 +#define _STORE_SUBSCR_DICT_KNOWN_HASH 623 +#define _STORE_SUBSCR_LIST_INT 624 +#define _SWAP 625 +#define _SWAP_2 626 +#define _SWAP_3 627 +#define _SWAP_FAST 628 +#define _SWAP_FAST_0 629 +#define _SWAP_FAST_1 630 +#define _SWAP_FAST_2 631 +#define _SWAP_FAST_3 632 +#define _SWAP_FAST_4 633 +#define _SWAP_FAST_5 634 +#define _SWAP_FAST_6 635 +#define _SWAP_FAST_7 636 +#define _TIER2_RESUME_CHECK 637 +#define _TO_BOOL 638 #define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT 640 -#define _TO_BOOL_LIST 641 +#define _TO_BOOL_INT 639 +#define _TO_BOOL_LIST 640 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 642 +#define _TO_BOOL_STR 641 #define _TRACE_RECORD TRACE_RECORD -#define _UNARY_INVERT 643 -#define _UNARY_NEGATIVE 644 -#define _UNARY_NEGATIVE_FLOAT_INPLACE 645 +#define _UNARY_INVERT 642 +#define _UNARY_NEGATIVE 643 +#define _UNARY_NEGATIVE_FLOAT_INPLACE 644 #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 646 -#define _UNPACK_SEQUENCE_LIST 647 -#define _UNPACK_SEQUENCE_TUPLE 648 -#define _UNPACK_SEQUENCE_TWO_TUPLE 649 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE 650 -#define _UNPACK_SEQUENCE_UNIQUE_TUPLE 651 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE 652 +#define _UNPACK_SEQUENCE 645 +#define _UNPACK_SEQUENCE_LIST 646 +#define _UNPACK_SEQUENCE_TUPLE 647 +#define _UNPACK_SEQUENCE_TWO_TUPLE 648 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE 649 +#define _UNPACK_SEQUENCE_UNIQUE_TUPLE 650 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE 651 #define _WITH_EXCEPT_START WITH_EXCEPT_START -#define _YIELD_VALUE 653 -#define MAX_UOP_ID 653 -#define _ALLOCATE_OBJECT_r00 654 -#define _BINARY_OP_r23 655 -#define _BINARY_OP_ADD_FLOAT_r03 656 -#define _BINARY_OP_ADD_FLOAT_r13 657 -#define _BINARY_OP_ADD_FLOAT_r23 658 -#define _BINARY_OP_ADD_FLOAT_INPLACE_r03 659 -#define _BINARY_OP_ADD_FLOAT_INPLACE_r13 660 -#define _BINARY_OP_ADD_FLOAT_INPLACE_r23 661 -#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r03 662 -#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r13 663 -#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r23 664 -#define _BINARY_OP_ADD_INT_r03 665 -#define _BINARY_OP_ADD_INT_r13 666 -#define _BINARY_OP_ADD_INT_r23 667 -#define _BINARY_OP_ADD_INT_INPLACE_r03 668 -#define _BINARY_OP_ADD_INT_INPLACE_r13 669 -#define _BINARY_OP_ADD_INT_INPLACE_r23 670 -#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r03 671 -#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r13 672 -#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r23 673 -#define _BINARY_OP_ADD_UNICODE_r03 674 -#define _BINARY_OP_ADD_UNICODE_r13 675 -#define _BINARY_OP_ADD_UNICODE_r23 676 -#define _BINARY_OP_EXTEND_r23 677 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 678 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 679 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 680 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 681 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r03 682 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r13 683 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r23 684 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r03 685 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r13 686 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r23 687 -#define _BINARY_OP_MULTIPLY_INT_r03 688 -#define _BINARY_OP_MULTIPLY_INT_r13 689 -#define _BINARY_OP_MULTIPLY_INT_r23 690 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_r03 691 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_r13 692 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_r23 693 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r03 694 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r13 695 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r23 696 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 697 -#define _BINARY_OP_SUBSCR_DICT_r23 698 -#define _BINARY_OP_SUBSCR_DICT_KNOWN_HASH_r23 699 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 700 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 701 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 702 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 703 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 704 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r23 705 -#define _BINARY_OP_SUBSCR_STR_INT_r23 706 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 707 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 708 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 709 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 710 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 711 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 712 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 713 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r03 714 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r13 715 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r23 716 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r03 717 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r13 718 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r23 719 -#define _BINARY_OP_SUBTRACT_INT_r03 720 -#define _BINARY_OP_SUBTRACT_INT_r13 721 -#define _BINARY_OP_SUBTRACT_INT_r23 722 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_r03 723 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_r13 724 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_r23 725 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r03 726 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r13 727 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r23 728 -#define _BINARY_OP_TRUEDIV_FLOAT_r23 729 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r03 730 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r13 731 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r23 732 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r03 733 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r13 734 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r23 735 -#define _BINARY_SLICE_r31 736 -#define _BUILD_INTERPOLATION_r01 737 -#define _BUILD_LIST_r01 738 -#define _BUILD_MAP_r01 739 -#define _BUILD_SET_r01 740 -#define _BUILD_SLICE_r01 741 -#define _BUILD_STRING_r01 742 -#define _BUILD_TEMPLATE_r21 743 -#define _BUILD_TUPLE_r01 744 -#define _CALL_BUILTIN_CLASS_r00 745 -#define _CALL_BUILTIN_FAST_r00 746 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r00 747 -#define _CALL_BUILTIN_O_r03 748 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 749 -#define _CALL_INTRINSIC_1_r12 750 -#define _CALL_INTRINSIC_2_r23 751 -#define _CALL_ISINSTANCE_r31 752 -#define _CALL_KW_NON_PY_r11 753 -#define _CALL_LEN_r33 754 -#define _CALL_LIST_APPEND_r03 755 -#define _CALL_LIST_APPEND_r13 756 -#define _CALL_LIST_APPEND_r23 757 -#define _CALL_LIST_APPEND_r33 758 -#define _CALL_METHOD_DESCRIPTOR_FAST_r00 759 -#define _CALL_METHOD_DESCRIPTOR_FAST_INLINE_r00 760 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 761 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_INLINE_r00 762 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r03 763 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_INLINE_r03 764 -#define _CALL_METHOD_DESCRIPTOR_O_r03 765 -#define _CALL_METHOD_DESCRIPTOR_O_INLINE_r03 766 -#define _CALL_NON_PY_GENERAL_r01 767 -#define _CALL_STR_1_r32 768 -#define _CALL_TUPLE_1_r32 769 -#define _CALL_TYPE_1_r02 770 -#define _CALL_TYPE_1_r12 771 -#define _CALL_TYPE_1_r22 772 -#define _CALL_TYPE_1_r32 773 -#define _CHECK_ATTR_CLASS_r01 774 -#define _CHECK_ATTR_CLASS_r11 775 -#define _CHECK_ATTR_CLASS_r22 776 -#define _CHECK_ATTR_CLASS_r33 777 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 778 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 779 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 780 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 781 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 782 -#define _CHECK_EG_MATCH_r22 783 -#define _CHECK_EXC_MATCH_r22 784 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 785 -#define _CHECK_FUNCTION_VERSION_r00 786 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 787 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 788 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 789 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 790 -#define _CHECK_FUNCTION_VERSION_KW_r11 791 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 792 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 793 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 794 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 795 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 796 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 797 -#define _CHECK_IS_PY_CALLABLE_EX_r03 798 -#define _CHECK_IS_PY_CALLABLE_EX_r13 799 -#define _CHECK_IS_PY_CALLABLE_EX_r23 800 -#define _CHECK_IS_PY_CALLABLE_EX_r33 801 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 802 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 803 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 804 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 805 -#define _CHECK_METHOD_VERSION_r00 806 -#define _CHECK_METHOD_VERSION_KW_r11 807 -#define _CHECK_OBJECT_r00 808 -#define _CHECK_PEP_523_r00 809 -#define _CHECK_PEP_523_r11 810 -#define _CHECK_PEP_523_r22 811 -#define _CHECK_PEP_523_r33 812 -#define _CHECK_PERIODIC_r00 813 -#define _CHECK_PERIODIC_AT_END_r00 814 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 815 -#define _CHECK_RECURSION_LIMIT_r00 816 -#define _CHECK_RECURSION_LIMIT_r11 817 -#define _CHECK_RECURSION_LIMIT_r22 818 -#define _CHECK_RECURSION_LIMIT_r33 819 -#define _CHECK_RECURSION_REMAINING_r00 820 -#define _CHECK_RECURSION_REMAINING_r11 821 -#define _CHECK_RECURSION_REMAINING_r22 822 -#define _CHECK_RECURSION_REMAINING_r33 823 -#define _CHECK_STACK_SPACE_r00 824 -#define _CHECK_STACK_SPACE_OPERAND_r00 825 -#define _CHECK_STACK_SPACE_OPERAND_r11 826 -#define _CHECK_STACK_SPACE_OPERAND_r22 827 -#define _CHECK_STACK_SPACE_OPERAND_r33 828 -#define _CHECK_VALIDITY_r00 829 -#define _CHECK_VALIDITY_r11 830 -#define _CHECK_VALIDITY_r22 831 -#define _CHECK_VALIDITY_r33 832 -#define _COLD_DYNAMIC_EXIT_r00 833 -#define _COLD_EXIT_r00 834 -#define _COMPARE_OP_r21 835 -#define _COMPARE_OP_FLOAT_r03 836 -#define _COMPARE_OP_FLOAT_r13 837 -#define _COMPARE_OP_FLOAT_r23 838 -#define _COMPARE_OP_INT_r23 839 -#define _COMPARE_OP_STR_r23 840 -#define _CONTAINS_OP_r23 841 -#define _CONTAINS_OP_DICT_r23 842 -#define _CONTAINS_OP_SET_r23 843 -#define _CONVERT_VALUE_r11 844 -#define _COPY_r01 845 -#define _COPY_1_r02 846 -#define _COPY_1_r12 847 -#define _COPY_1_r23 848 -#define _COPY_2_r03 849 -#define _COPY_2_r13 850 -#define _COPY_2_r23 851 -#define _COPY_3_r03 852 -#define _COPY_3_r13 853 -#define _COPY_3_r23 854 -#define _COPY_3_r33 855 -#define _COPY_FREE_VARS_r00 856 -#define _COPY_FREE_VARS_r11 857 -#define _COPY_FREE_VARS_r22 858 -#define _COPY_FREE_VARS_r33 859 -#define _CREATE_INIT_FRAME_r01 860 -#define _DELETE_DEREF_r00 861 -#define _DELETE_FAST_r00 862 -#define _DELETE_SUBSCR_r20 863 -#define _DEOPT_r00 864 -#define _DEOPT_r10 865 -#define _DEOPT_r20 866 -#define _DEOPT_r30 867 -#define _DICT_MERGE_r11 868 -#define _DICT_UPDATE_r11 869 -#define _DO_CALL_r01 870 -#define _DO_CALL_FUNCTION_EX_r31 871 -#define _DO_CALL_KW_r11 872 -#define _DYNAMIC_EXIT_r00 873 -#define _DYNAMIC_EXIT_r10 874 -#define _DYNAMIC_EXIT_r20 875 -#define _DYNAMIC_EXIT_r30 876 -#define _END_FOR_r10 877 -#define _END_SEND_r31 878 -#define _ERROR_POP_N_r00 879 -#define _EXIT_INIT_CHECK_r10 880 -#define _EXIT_TRACE_r00 881 -#define _EXIT_TRACE_r10 882 -#define _EXIT_TRACE_r20 883 -#define _EXIT_TRACE_r30 884 -#define _EXPAND_METHOD_r00 885 -#define _EXPAND_METHOD_KW_r11 886 -#define _FATAL_ERROR_r00 887 -#define _FATAL_ERROR_r11 888 -#define _FATAL_ERROR_r22 889 -#define _FATAL_ERROR_r33 890 -#define _FORMAT_SIMPLE_r11 891 -#define _FORMAT_WITH_SPEC_r21 892 -#define _FOR_ITER_r23 893 -#define _FOR_ITER_GEN_FRAME_r03 894 -#define _FOR_ITER_GEN_FRAME_r13 895 -#define _FOR_ITER_GEN_FRAME_r23 896 -#define _FOR_ITER_TIER_TWO_r23 897 -#define _FOR_ITER_VIRTUAL_r23 898 -#define _FOR_ITER_VIRTUAL_TIER_TWO_r23 899 -#define _GET_AITER_r11 900 -#define _GET_ANEXT_r12 901 -#define _GET_AWAITABLE_r11 902 -#define _GET_ITER_r12 903 -#define _GET_ITER_TRAD_r12 904 -#define _GET_LEN_r12 905 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r03 906 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r13 907 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r23 908 -#define _GUARD_3OS_ASYNC_GEN_ASEND_r33 909 -#define _GUARD_BINARY_OP_EXTEND_r22 910 -#define _GUARD_BINARY_OP_EXTEND_LHS_r02 911 -#define _GUARD_BINARY_OP_EXTEND_LHS_r12 912 -#define _GUARD_BINARY_OP_EXTEND_LHS_r22 913 -#define _GUARD_BINARY_OP_EXTEND_LHS_r33 914 -#define _GUARD_BINARY_OP_EXTEND_RHS_r02 915 -#define _GUARD_BINARY_OP_EXTEND_RHS_r12 916 -#define _GUARD_BINARY_OP_EXTEND_RHS_r22 917 -#define _GUARD_BINARY_OP_EXTEND_RHS_r33 918 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 919 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 920 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 921 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 922 -#define _GUARD_BIT_IS_SET_POP_r00 923 -#define _GUARD_BIT_IS_SET_POP_r10 924 -#define _GUARD_BIT_IS_SET_POP_r21 925 -#define _GUARD_BIT_IS_SET_POP_r32 926 -#define _GUARD_BIT_IS_SET_POP_4_r00 927 -#define _GUARD_BIT_IS_SET_POP_4_r10 928 -#define _GUARD_BIT_IS_SET_POP_4_r21 929 -#define _GUARD_BIT_IS_SET_POP_4_r32 930 -#define _GUARD_BIT_IS_SET_POP_5_r00 931 -#define _GUARD_BIT_IS_SET_POP_5_r10 932 -#define _GUARD_BIT_IS_SET_POP_5_r21 933 -#define _GUARD_BIT_IS_SET_POP_5_r32 934 -#define _GUARD_BIT_IS_SET_POP_6_r00 935 -#define _GUARD_BIT_IS_SET_POP_6_r10 936 -#define _GUARD_BIT_IS_SET_POP_6_r21 937 -#define _GUARD_BIT_IS_SET_POP_6_r32 938 -#define _GUARD_BIT_IS_SET_POP_7_r00 939 -#define _GUARD_BIT_IS_SET_POP_7_r10 940 -#define _GUARD_BIT_IS_SET_POP_7_r21 941 -#define _GUARD_BIT_IS_SET_POP_7_r32 942 -#define _GUARD_BIT_IS_UNSET_POP_r00 943 -#define _GUARD_BIT_IS_UNSET_POP_r10 944 -#define _GUARD_BIT_IS_UNSET_POP_r21 945 -#define _GUARD_BIT_IS_UNSET_POP_r32 946 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 947 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 948 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 949 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 950 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 951 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 952 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 953 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 954 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 955 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 956 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 957 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 958 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 959 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 960 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 961 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 962 -#define _GUARD_CALLABLE_BUILTIN_CLASS_r00 963 -#define _GUARD_CALLABLE_BUILTIN_FAST_r00 964 -#define _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS_r00 965 -#define _GUARD_CALLABLE_BUILTIN_O_r00 966 -#define _GUARD_CALLABLE_ISINSTANCE_r03 967 -#define _GUARD_CALLABLE_ISINSTANCE_r13 968 -#define _GUARD_CALLABLE_ISINSTANCE_r23 969 -#define _GUARD_CALLABLE_ISINSTANCE_r33 970 -#define _GUARD_CALLABLE_LEN_r03 971 -#define _GUARD_CALLABLE_LEN_r13 972 -#define _GUARD_CALLABLE_LEN_r23 973 -#define _GUARD_CALLABLE_LEN_r33 974 -#define _GUARD_CALLABLE_LIST_APPEND_r03 975 -#define _GUARD_CALLABLE_LIST_APPEND_r13 976 -#define _GUARD_CALLABLE_LIST_APPEND_r23 977 -#define _GUARD_CALLABLE_LIST_APPEND_r33 978 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_r00 979 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 980 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS_r00 981 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_O_r00 982 -#define _GUARD_CALLABLE_STR_1_r03 983 -#define _GUARD_CALLABLE_STR_1_r13 984 -#define _GUARD_CALLABLE_STR_1_r23 985 -#define _GUARD_CALLABLE_STR_1_r33 986 -#define _GUARD_CALLABLE_TUPLE_1_r03 987 -#define _GUARD_CALLABLE_TUPLE_1_r13 988 -#define _GUARD_CALLABLE_TUPLE_1_r23 989 -#define _GUARD_CALLABLE_TUPLE_1_r33 990 -#define _GUARD_CALLABLE_TYPE_1_r03 991 -#define _GUARD_CALLABLE_TYPE_1_r13 992 -#define _GUARD_CALLABLE_TYPE_1_r23 993 -#define _GUARD_CALLABLE_TYPE_1_r33 994 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r00 995 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r11 996 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r22 997 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r33 998 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r00 999 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r11 1000 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r22 1001 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r33 1002 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r00 1003 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r11 1004 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r22 1005 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r33 1006 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r00 1007 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r11 1008 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r22 1009 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r33 1010 -#define _GUARD_DORV_NO_DICT_r01 1011 -#define _GUARD_DORV_NO_DICT_r11 1012 -#define _GUARD_DORV_NO_DICT_r22 1013 -#define _GUARD_DORV_NO_DICT_r33 1014 -#define _GUARD_GLOBALS_VERSION_r00 1015 -#define _GUARD_GLOBALS_VERSION_r11 1016 -#define _GUARD_GLOBALS_VERSION_r22 1017 -#define _GUARD_GLOBALS_VERSION_r33 1018 -#define _GUARD_IP_RETURN_GENERATOR_r00 1019 -#define _GUARD_IP_RETURN_GENERATOR_r11 1020 -#define _GUARD_IP_RETURN_GENERATOR_r22 1021 -#define _GUARD_IP_RETURN_GENERATOR_r33 1022 -#define _GUARD_IP_RETURN_VALUE_r00 1023 -#define _GUARD_IP_RETURN_VALUE_r11 1024 -#define _GUARD_IP_RETURN_VALUE_r22 1025 -#define _GUARD_IP_RETURN_VALUE_r33 1026 -#define _GUARD_IP_YIELD_VALUE_r00 1027 -#define _GUARD_IP_YIELD_VALUE_r11 1028 -#define _GUARD_IP_YIELD_VALUE_r22 1029 -#define _GUARD_IP_YIELD_VALUE_r33 1030 -#define _GUARD_IP__PUSH_FRAME_r00 1031 -#define _GUARD_IP__PUSH_FRAME_r11 1032 -#define _GUARD_IP__PUSH_FRAME_r22 1033 -#define _GUARD_IP__PUSH_FRAME_r33 1034 -#define _GUARD_IS_FALSE_POP_r00 1035 -#define _GUARD_IS_FALSE_POP_r10 1036 -#define _GUARD_IS_FALSE_POP_r21 1037 -#define _GUARD_IS_FALSE_POP_r32 1038 -#define _GUARD_IS_NONE_POP_r00 1039 -#define _GUARD_IS_NONE_POP_r10 1040 -#define _GUARD_IS_NONE_POP_r21 1041 -#define _GUARD_IS_NONE_POP_r32 1042 -#define _GUARD_IS_NOT_NONE_POP_r10 1043 -#define _GUARD_IS_TRUE_POP_r00 1044 -#define _GUARD_IS_TRUE_POP_r10 1045 -#define _GUARD_IS_TRUE_POP_r21 1046 -#define _GUARD_IS_TRUE_POP_r32 1047 -#define _GUARD_ITERATOR_r01 1048 -#define _GUARD_ITERATOR_r11 1049 -#define _GUARD_ITERATOR_r22 1050 -#define _GUARD_ITERATOR_r33 1051 -#define _GUARD_ITER_VIRTUAL_r01 1052 -#define _GUARD_ITER_VIRTUAL_r11 1053 -#define _GUARD_ITER_VIRTUAL_r22 1054 -#define _GUARD_ITER_VIRTUAL_r33 1055 -#define _GUARD_KEYS_VERSION_r01 1056 -#define _GUARD_KEYS_VERSION_r11 1057 -#define _GUARD_KEYS_VERSION_r22 1058 -#define _GUARD_KEYS_VERSION_r33 1059 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r03 1060 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r13 1061 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r23 1062 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r33 1063 -#define _GUARD_NOS_COMPACT_ASCII_r02 1064 -#define _GUARD_NOS_COMPACT_ASCII_r12 1065 -#define _GUARD_NOS_COMPACT_ASCII_r22 1066 -#define _GUARD_NOS_COMPACT_ASCII_r33 1067 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 1068 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 1069 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 1070 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 1071 -#define _GUARD_NOS_DICT_SUBSCRIPT_r02 1072 -#define _GUARD_NOS_DICT_SUBSCRIPT_r12 1073 -#define _GUARD_NOS_DICT_SUBSCRIPT_r22 1074 -#define _GUARD_NOS_DICT_SUBSCRIPT_r33 1075 -#define _GUARD_NOS_FLOAT_r02 1076 -#define _GUARD_NOS_FLOAT_r12 1077 -#define _GUARD_NOS_FLOAT_r22 1078 -#define _GUARD_NOS_FLOAT_r33 1079 -#define _GUARD_NOS_INT_r02 1080 -#define _GUARD_NOS_INT_r12 1081 -#define _GUARD_NOS_INT_r22 1082 -#define _GUARD_NOS_INT_r33 1083 -#define _GUARD_NOS_ITER_VIRTUAL_r02 1084 -#define _GUARD_NOS_ITER_VIRTUAL_r12 1085 -#define _GUARD_NOS_ITER_VIRTUAL_r22 1086 -#define _GUARD_NOS_ITER_VIRTUAL_r33 1087 -#define _GUARD_NOS_LIST_r02 1088 -#define _GUARD_NOS_LIST_r12 1089 -#define _GUARD_NOS_LIST_r22 1090 -#define _GUARD_NOS_LIST_r33 1091 -#define _GUARD_NOS_NOT_NULL_r02 1092 -#define _GUARD_NOS_NOT_NULL_r12 1093 -#define _GUARD_NOS_NOT_NULL_r22 1094 -#define _GUARD_NOS_NOT_NULL_r33 1095 -#define _GUARD_NOS_NULL_r02 1096 -#define _GUARD_NOS_NULL_r12 1097 -#define _GUARD_NOS_NULL_r22 1098 -#define _GUARD_NOS_NULL_r33 1099 -#define _GUARD_NOS_OVERFLOWED_r02 1100 -#define _GUARD_NOS_OVERFLOWED_r12 1101 -#define _GUARD_NOS_OVERFLOWED_r22 1102 -#define _GUARD_NOS_OVERFLOWED_r33 1103 -#define _GUARD_NOS_TUPLE_r02 1104 -#define _GUARD_NOS_TUPLE_r12 1105 -#define _GUARD_NOS_TUPLE_r22 1106 -#define _GUARD_NOS_TUPLE_r33 1107 -#define _GUARD_NOS_TYPE_VERSION_r02 1108 -#define _GUARD_NOS_TYPE_VERSION_r12 1109 -#define _GUARD_NOS_TYPE_VERSION_r22 1110 -#define _GUARD_NOS_TYPE_VERSION_r33 1111 -#define _GUARD_NOS_UNICODE_r02 1112 -#define _GUARD_NOS_UNICODE_r12 1113 -#define _GUARD_NOS_UNICODE_r22 1114 -#define _GUARD_NOS_UNICODE_r33 1115 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 1116 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 1117 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 1118 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 1119 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 1120 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 1121 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 1122 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 1123 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 1124 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 1125 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 1126 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 1127 -#define _GUARD_THIRD_NULL_r03 1128 -#define _GUARD_THIRD_NULL_r13 1129 -#define _GUARD_THIRD_NULL_r23 1130 -#define _GUARD_THIRD_NULL_r33 1131 -#define _GUARD_TOS_ANY_DICT_r01 1132 -#define _GUARD_TOS_ANY_DICT_r11 1133 -#define _GUARD_TOS_ANY_DICT_r22 1134 -#define _GUARD_TOS_ANY_DICT_r33 1135 -#define _GUARD_TOS_ANY_SET_r01 1136 -#define _GUARD_TOS_ANY_SET_r11 1137 -#define _GUARD_TOS_ANY_SET_r22 1138 -#define _GUARD_TOS_ANY_SET_r33 1139 -#define _GUARD_TOS_DICT_r01 1140 -#define _GUARD_TOS_DICT_r11 1141 -#define _GUARD_TOS_DICT_r22 1142 -#define _GUARD_TOS_DICT_r33 1143 -#define _GUARD_TOS_FLOAT_r01 1144 -#define _GUARD_TOS_FLOAT_r11 1145 -#define _GUARD_TOS_FLOAT_r22 1146 -#define _GUARD_TOS_FLOAT_r33 1147 -#define _GUARD_TOS_FROZENDICT_r01 1148 -#define _GUARD_TOS_FROZENDICT_r11 1149 -#define _GUARD_TOS_FROZENDICT_r22 1150 -#define _GUARD_TOS_FROZENDICT_r33 1151 -#define _GUARD_TOS_FROZENSET_r01 1152 -#define _GUARD_TOS_FROZENSET_r11 1153 -#define _GUARD_TOS_FROZENSET_r22 1154 -#define _GUARD_TOS_FROZENSET_r33 1155 -#define _GUARD_TOS_INT_r01 1156 -#define _GUARD_TOS_INT_r11 1157 -#define _GUARD_TOS_INT_r22 1158 -#define _GUARD_TOS_INT_r33 1159 -#define _GUARD_TOS_IS_NONE_r01 1160 -#define _GUARD_TOS_IS_NONE_r11 1161 -#define _GUARD_TOS_IS_NONE_r22 1162 -#define _GUARD_TOS_IS_NONE_r33 1163 -#define _GUARD_TOS_LIST_r01 1164 -#define _GUARD_TOS_LIST_r11 1165 -#define _GUARD_TOS_LIST_r22 1166 -#define _GUARD_TOS_LIST_r33 1167 -#define _GUARD_TOS_NOT_NULL_r01 1168 -#define _GUARD_TOS_NOT_NULL_r11 1169 -#define _GUARD_TOS_NOT_NULL_r22 1170 -#define _GUARD_TOS_NOT_NULL_r33 1171 -#define _GUARD_TOS_OVERFLOWED_r01 1172 -#define _GUARD_TOS_OVERFLOWED_r11 1173 -#define _GUARD_TOS_OVERFLOWED_r22 1174 -#define _GUARD_TOS_OVERFLOWED_r33 1175 -#define _GUARD_TOS_SET_r01 1176 -#define _GUARD_TOS_SET_r11 1177 -#define _GUARD_TOS_SET_r22 1178 -#define _GUARD_TOS_SET_r33 1179 -#define _GUARD_TOS_SLICE_r01 1180 -#define _GUARD_TOS_SLICE_r11 1181 -#define _GUARD_TOS_SLICE_r22 1182 -#define _GUARD_TOS_SLICE_r33 1183 -#define _GUARD_TOS_TUPLE_r01 1184 -#define _GUARD_TOS_TUPLE_r11 1185 -#define _GUARD_TOS_TUPLE_r22 1186 -#define _GUARD_TOS_TUPLE_r33 1187 -#define _GUARD_TOS_UNICODE_r01 1188 -#define _GUARD_TOS_UNICODE_r11 1189 -#define _GUARD_TOS_UNICODE_r22 1190 -#define _GUARD_TOS_UNICODE_r33 1191 -#define _GUARD_TYPE_r01 1192 -#define _GUARD_TYPE_r11 1193 -#define _GUARD_TYPE_r22 1194 -#define _GUARD_TYPE_r33 1195 -#define _GUARD_TYPE_ITER_r02 1196 -#define _GUARD_TYPE_ITER_r12 1197 -#define _GUARD_TYPE_ITER_r22 1198 -#define _GUARD_TYPE_ITER_r33 1199 -#define _GUARD_TYPE_VERSION_r01 1200 -#define _GUARD_TYPE_VERSION_r11 1201 -#define _GUARD_TYPE_VERSION_r22 1202 -#define _GUARD_TYPE_VERSION_r33 1203 -#define _GUARD_TYPE_VERSION_LOCKED_r01 1204 -#define _GUARD_TYPE_VERSION_LOCKED_r11 1205 -#define _GUARD_TYPE_VERSION_LOCKED_r22 1206 -#define _GUARD_TYPE_VERSION_LOCKED_r33 1207 -#define _HANDLE_PENDING_AND_DEOPT_r00 1208 -#define _HANDLE_PENDING_AND_DEOPT_r10 1209 -#define _HANDLE_PENDING_AND_DEOPT_r20 1210 -#define _HANDLE_PENDING_AND_DEOPT_r30 1211 -#define _IMPORT_FROM_r12 1212 -#define _IMPORT_NAME_r21 1213 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1214 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1215 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1216 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1217 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1218 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1219 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1220 -#define _INSERT_NULL_r10 1221 -#define _INSTRUMENTED_FOR_ITER_r23 1222 -#define _INSTRUMENTED_INSTRUCTION_r00 1223 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1224 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1225 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1226 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1227 -#define _INSTRUMENTED_LINE_r00 1228 -#define _INSTRUMENTED_NOT_TAKEN_r00 1229 -#define _INSTRUMENTED_NOT_TAKEN_r11 1230 -#define _INSTRUMENTED_NOT_TAKEN_r22 1231 -#define _INSTRUMENTED_NOT_TAKEN_r33 1232 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1233 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1234 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1235 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1236 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1237 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1238 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1239 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1240 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1241 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1242 -#define _IS_NONE_r11 1243 -#define _IS_OP_r03 1244 -#define _IS_OP_r13 1245 -#define _IS_OP_r23 1246 -#define _ITER_CHECK_LIST_r02 1247 -#define _ITER_CHECK_LIST_r12 1248 -#define _ITER_CHECK_LIST_r22 1249 -#define _ITER_CHECK_LIST_r33 1250 -#define _ITER_CHECK_RANGE_r02 1251 -#define _ITER_CHECK_RANGE_r12 1252 -#define _ITER_CHECK_RANGE_r22 1253 -#define _ITER_CHECK_RANGE_r33 1254 -#define _ITER_CHECK_TUPLE_r02 1255 -#define _ITER_CHECK_TUPLE_r12 1256 -#define _ITER_CHECK_TUPLE_r22 1257 -#define _ITER_CHECK_TUPLE_r33 1258 -#define _ITER_JUMP_LIST_r02 1259 -#define _ITER_JUMP_LIST_r12 1260 -#define _ITER_JUMP_LIST_r22 1261 -#define _ITER_JUMP_LIST_r33 1262 -#define _ITER_JUMP_RANGE_r02 1263 -#define _ITER_JUMP_RANGE_r12 1264 -#define _ITER_JUMP_RANGE_r22 1265 -#define _ITER_JUMP_RANGE_r33 1266 -#define _ITER_JUMP_TUPLE_r02 1267 -#define _ITER_JUMP_TUPLE_r12 1268 -#define _ITER_JUMP_TUPLE_r22 1269 -#define _ITER_JUMP_TUPLE_r33 1270 -#define _ITER_NEXT_INLINE_r23 1271 -#define _ITER_NEXT_LIST_r23 1272 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1273 -#define _ITER_NEXT_RANGE_r03 1274 -#define _ITER_NEXT_RANGE_r13 1275 -#define _ITER_NEXT_RANGE_r23 1276 -#define _ITER_NEXT_TUPLE_r03 1277 -#define _ITER_NEXT_TUPLE_r13 1278 -#define _ITER_NEXT_TUPLE_r23 1279 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1280 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1281 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1282 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1283 -#define _JUMP_TO_TOP_r00 1284 -#define _LIST_APPEND_r10 1285 -#define _LIST_EXTEND_r11 1286 -#define _LOAD_ATTR_r10 1287 -#define _LOAD_ATTR_CLASS_r11 1288 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME_r11 1289 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1290 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1291 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1292 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1293 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1294 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1295 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1296 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1297 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1298 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1299 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1300 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1301 -#define _LOAD_ATTR_MODULE_r12 1302 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1303 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1304 -#define _LOAD_ATTR_PROPERTY_FRAME_r01 1305 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1306 -#define _LOAD_ATTR_PROPERTY_FRAME_r22 1307 -#define _LOAD_ATTR_PROPERTY_FRAME_r33 1308 -#define _LOAD_ATTR_SLOT_r02 1309 -#define _LOAD_ATTR_SLOT_r12 1310 -#define _LOAD_ATTR_SLOT_r23 1311 -#define _LOAD_ATTR_WITH_HINT_r12 1312 -#define _LOAD_BUILD_CLASS_r01 1313 -#define _LOAD_BYTECODE_r00 1314 -#define _LOAD_COMMON_CONSTANT_r01 1315 -#define _LOAD_COMMON_CONSTANT_r12 1316 -#define _LOAD_COMMON_CONSTANT_r23 1317 -#define _LOAD_CONST_r01 1318 -#define _LOAD_CONST_r12 1319 -#define _LOAD_CONST_r23 1320 -#define _LOAD_CONST_INLINE_r01 1321 -#define _LOAD_CONST_INLINE_r12 1322 -#define _LOAD_CONST_INLINE_r23 1323 -#define _LOAD_CONST_INLINE_BORROW_r01 1324 -#define _LOAD_CONST_INLINE_BORROW_r12 1325 -#define _LOAD_CONST_INLINE_BORROW_r23 1326 -#define _LOAD_DEREF_r01 1327 -#define _LOAD_FAST_r01 1328 -#define _LOAD_FAST_r12 1329 -#define _LOAD_FAST_r23 1330 -#define _LOAD_FAST_0_r01 1331 -#define _LOAD_FAST_0_r12 1332 -#define _LOAD_FAST_0_r23 1333 -#define _LOAD_FAST_1_r01 1334 -#define _LOAD_FAST_1_r12 1335 -#define _LOAD_FAST_1_r23 1336 -#define _LOAD_FAST_2_r01 1337 -#define _LOAD_FAST_2_r12 1338 -#define _LOAD_FAST_2_r23 1339 -#define _LOAD_FAST_3_r01 1340 -#define _LOAD_FAST_3_r12 1341 -#define _LOAD_FAST_3_r23 1342 -#define _LOAD_FAST_4_r01 1343 -#define _LOAD_FAST_4_r12 1344 -#define _LOAD_FAST_4_r23 1345 -#define _LOAD_FAST_5_r01 1346 -#define _LOAD_FAST_5_r12 1347 -#define _LOAD_FAST_5_r23 1348 -#define _LOAD_FAST_6_r01 1349 -#define _LOAD_FAST_6_r12 1350 -#define _LOAD_FAST_6_r23 1351 -#define _LOAD_FAST_7_r01 1352 -#define _LOAD_FAST_7_r12 1353 -#define _LOAD_FAST_7_r23 1354 -#define _LOAD_FAST_AND_CLEAR_r01 1355 -#define _LOAD_FAST_AND_CLEAR_r12 1356 -#define _LOAD_FAST_AND_CLEAR_r23 1357 -#define _LOAD_FAST_BORROW_r01 1358 -#define _LOAD_FAST_BORROW_r12 1359 -#define _LOAD_FAST_BORROW_r23 1360 -#define _LOAD_FAST_BORROW_0_r01 1361 -#define _LOAD_FAST_BORROW_0_r12 1362 -#define _LOAD_FAST_BORROW_0_r23 1363 -#define _LOAD_FAST_BORROW_1_r01 1364 -#define _LOAD_FAST_BORROW_1_r12 1365 -#define _LOAD_FAST_BORROW_1_r23 1366 -#define _LOAD_FAST_BORROW_2_r01 1367 -#define _LOAD_FAST_BORROW_2_r12 1368 -#define _LOAD_FAST_BORROW_2_r23 1369 -#define _LOAD_FAST_BORROW_3_r01 1370 -#define _LOAD_FAST_BORROW_3_r12 1371 -#define _LOAD_FAST_BORROW_3_r23 1372 -#define _LOAD_FAST_BORROW_4_r01 1373 -#define _LOAD_FAST_BORROW_4_r12 1374 -#define _LOAD_FAST_BORROW_4_r23 1375 -#define _LOAD_FAST_BORROW_5_r01 1376 -#define _LOAD_FAST_BORROW_5_r12 1377 -#define _LOAD_FAST_BORROW_5_r23 1378 -#define _LOAD_FAST_BORROW_6_r01 1379 -#define _LOAD_FAST_BORROW_6_r12 1380 -#define _LOAD_FAST_BORROW_6_r23 1381 -#define _LOAD_FAST_BORROW_7_r01 1382 -#define _LOAD_FAST_BORROW_7_r12 1383 -#define _LOAD_FAST_BORROW_7_r23 1384 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1385 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1386 -#define _LOAD_FAST_CHECK_r01 1387 -#define _LOAD_FAST_CHECK_r12 1388 -#define _LOAD_FAST_CHECK_r23 1389 -#define _LOAD_FAST_LOAD_FAST_r02 1390 -#define _LOAD_FAST_LOAD_FAST_r13 1391 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1392 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1393 -#define _LOAD_GLOBAL_r00 1394 -#define _LOAD_GLOBAL_BUILTINS_r01 1395 -#define _LOAD_GLOBAL_MODULE_r01 1396 -#define _LOAD_LOCALS_r01 1397 -#define _LOAD_LOCALS_r12 1398 -#define _LOAD_LOCALS_r23 1399 -#define _LOAD_NAME_r01 1400 -#define _LOAD_SMALL_INT_r01 1401 -#define _LOAD_SMALL_INT_r12 1402 -#define _LOAD_SMALL_INT_r23 1403 -#define _LOAD_SMALL_INT_0_r01 1404 -#define _LOAD_SMALL_INT_0_r12 1405 -#define _LOAD_SMALL_INT_0_r23 1406 -#define _LOAD_SMALL_INT_1_r01 1407 -#define _LOAD_SMALL_INT_1_r12 1408 -#define _LOAD_SMALL_INT_1_r23 1409 -#define _LOAD_SMALL_INT_2_r01 1410 -#define _LOAD_SMALL_INT_2_r12 1411 -#define _LOAD_SMALL_INT_2_r23 1412 -#define _LOAD_SMALL_INT_3_r01 1413 -#define _LOAD_SMALL_INT_3_r12 1414 -#define _LOAD_SMALL_INT_3_r23 1415 -#define _LOAD_SPECIAL_r00 1416 -#define _LOAD_SUPER_ATTR_ATTR_r31 1417 -#define _LOAD_SUPER_ATTR_METHOD_r32 1418 -#define _LOCK_OBJECT_r01 1419 -#define _LOCK_OBJECT_r11 1420 -#define _LOCK_OBJECT_r22 1421 -#define _LOCK_OBJECT_r33 1422 -#define _MAKE_CALLARGS_A_TUPLE_r33 1423 -#define _MAKE_CELL_r00 1424 -#define _MAKE_FUNCTION_r12 1425 -#define _MAKE_HEAP_SAFE_r01 1426 -#define _MAKE_HEAP_SAFE_r11 1427 -#define _MAKE_HEAP_SAFE_r22 1428 -#define _MAKE_HEAP_SAFE_r33 1429 -#define _MAKE_WARM_r00 1430 -#define _MAKE_WARM_r11 1431 -#define _MAKE_WARM_r22 1432 -#define _MAKE_WARM_r33 1433 -#define _MAP_ADD_r20 1434 -#define _MATCH_CLASS_r33 1435 -#define _MATCH_KEYS_r23 1436 -#define _MATCH_MAPPING_r02 1437 -#define _MATCH_MAPPING_r12 1438 -#define _MATCH_MAPPING_r23 1439 -#define _MATCH_SEQUENCE_r02 1440 -#define _MATCH_SEQUENCE_r12 1441 -#define _MATCH_SEQUENCE_r23 1442 -#define _MAYBE_EXPAND_METHOD_r00 1443 -#define _MAYBE_EXPAND_METHOD_KW_r11 1444 -#define _MONITOR_CALL_r00 1445 -#define _MONITOR_CALL_KW_r11 1446 -#define _MONITOR_JUMP_BACKWARD_r00 1447 -#define _MONITOR_JUMP_BACKWARD_r11 1448 -#define _MONITOR_JUMP_BACKWARD_r22 1449 -#define _MONITOR_JUMP_BACKWARD_r33 1450 -#define _MONITOR_RESUME_r00 1451 -#define _NOP_r00 1452 -#define _NOP_r11 1453 -#define _NOP_r22 1454 -#define _NOP_r33 1455 -#define _POP_EXCEPT_r10 1456 -#define _POP_ITER_r20 1457 -#define _POP_JUMP_IF_FALSE_r00 1458 -#define _POP_JUMP_IF_FALSE_r10 1459 -#define _POP_JUMP_IF_FALSE_r21 1460 -#define _POP_JUMP_IF_FALSE_r32 1461 -#define _POP_JUMP_IF_TRUE_r00 1462 -#define _POP_JUMP_IF_TRUE_r10 1463 -#define _POP_JUMP_IF_TRUE_r21 1464 -#define _POP_JUMP_IF_TRUE_r32 1465 -#define _POP_TOP_r10 1466 -#define _POP_TOP_FLOAT_r00 1467 -#define _POP_TOP_FLOAT_r10 1468 -#define _POP_TOP_FLOAT_r21 1469 -#define _POP_TOP_FLOAT_r32 1470 -#define _POP_TOP_INT_r00 1471 -#define _POP_TOP_INT_r10 1472 -#define _POP_TOP_INT_r21 1473 -#define _POP_TOP_INT_r32 1474 -#define _POP_TOP_NOP_r00 1475 -#define _POP_TOP_NOP_r10 1476 -#define _POP_TOP_NOP_r21 1477 -#define _POP_TOP_NOP_r32 1478 -#define _POP_TOP_OPARG_r00 1479 -#define _POP_TOP_UNICODE_r00 1480 -#define _POP_TOP_UNICODE_r10 1481 -#define _POP_TOP_UNICODE_r21 1482 -#define _POP_TOP_UNICODE_r32 1483 -#define _PUSH_EXC_INFO_r02 1484 -#define _PUSH_EXC_INFO_r12 1485 -#define _PUSH_EXC_INFO_r23 1486 -#define _PUSH_FRAME_r10 1487 -#define _PUSH_NULL_r01 1488 -#define _PUSH_NULL_r12 1489 -#define _PUSH_NULL_r23 1490 -#define _PUSH_NULL_CONDITIONAL_r00 1491 -#define _PUSH_TAGGED_ZERO_r01 1492 -#define _PUSH_TAGGED_ZERO_r12 1493 -#define _PUSH_TAGGED_ZERO_r23 1494 -#define _PY_FRAME_EX_r31 1495 -#define _PY_FRAME_GENERAL_r01 1496 -#define _PY_FRAME_KW_r11 1497 -#define _REPLACE_WITH_TRUE_r02 1498 -#define _REPLACE_WITH_TRUE_r12 1499 -#define _REPLACE_WITH_TRUE_r23 1500 -#define _RESUME_CHECK_r00 1501 -#define _RESUME_CHECK_r11 1502 -#define _RESUME_CHECK_r22 1503 -#define _RESUME_CHECK_r33 1504 -#define _RETURN_GENERATOR_r01 1505 -#define _RETURN_VALUE_r11 1506 -#define _RROT_3_r03 1507 -#define _RROT_3_r13 1508 -#define _RROT_3_r23 1509 -#define _RROT_3_r33 1510 -#define _SAVE_RETURN_OFFSET_r00 1511 -#define _SAVE_RETURN_OFFSET_r11 1512 -#define _SAVE_RETURN_OFFSET_r22 1513 -#define _SAVE_RETURN_OFFSET_r33 1514 -#define _SEND_ASYNC_GEN_r33 1515 -#define _SEND_ASYNC_GEN_TIER_TWO_r33 1516 -#define _SEND_GEN_FRAME_r33 1517 -#define _SEND_VIRTUAL_r33 1518 -#define _SEND_VIRTUAL_TIER_TWO_r03 1519 -#define _SEND_VIRTUAL_TIER_TWO_r13 1520 -#define _SEND_VIRTUAL_TIER_TWO_r23 1521 -#define _SEND_VIRTUAL_TIER_TWO_r33 1522 -#define _SETUP_ANNOTATIONS_r00 1523 -#define _SET_ADD_r10 1524 -#define _SET_FUNCTION_ATTRIBUTE_r01 1525 -#define _SET_FUNCTION_ATTRIBUTE_r11 1526 -#define _SET_FUNCTION_ATTRIBUTE_r21 1527 -#define _SET_FUNCTION_ATTRIBUTE_r32 1528 -#define _SET_IP_r00 1529 -#define _SET_IP_r11 1530 -#define _SET_IP_r22 1531 -#define _SET_IP_r33 1532 -#define _SET_UPDATE_r11 1533 -#define _SPILL_OR_RELOAD_r01 1534 -#define _SPILL_OR_RELOAD_r02 1535 -#define _SPILL_OR_RELOAD_r03 1536 -#define _SPILL_OR_RELOAD_r10 1537 -#define _SPILL_OR_RELOAD_r12 1538 -#define _SPILL_OR_RELOAD_r13 1539 -#define _SPILL_OR_RELOAD_r20 1540 -#define _SPILL_OR_RELOAD_r21 1541 -#define _SPILL_OR_RELOAD_r23 1542 -#define _SPILL_OR_RELOAD_r30 1543 -#define _SPILL_OR_RELOAD_r31 1544 -#define _SPILL_OR_RELOAD_r32 1545 -#define _START_EXECUTOR_r00 1546 -#define _STORE_ATTR_r20 1547 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1548 -#define _STORE_ATTR_SLOT_r21 1549 -#define _STORE_ATTR_WITH_HINT_r21 1550 -#define _STORE_DEREF_r10 1551 -#define _STORE_FAST_LOAD_FAST_r11 1552 -#define _STORE_FAST_STORE_FAST_r20 1553 -#define _STORE_GLOBAL_r10 1554 -#define _STORE_NAME_r10 1555 -#define _STORE_SLICE_r30 1556 -#define _STORE_SUBSCR_r30 1557 -#define _STORE_SUBSCR_DICT_r31 1558 -#define _STORE_SUBSCR_DICT_KNOWN_HASH_r31 1559 -#define _STORE_SUBSCR_LIST_INT_r32 1560 -#define _SWAP_r11 1561 -#define _SWAP_2_r02 1562 -#define _SWAP_2_r12 1563 -#define _SWAP_2_r22 1564 -#define _SWAP_2_r33 1565 -#define _SWAP_3_r03 1566 -#define _SWAP_3_r13 1567 -#define _SWAP_3_r23 1568 -#define _SWAP_3_r33 1569 -#define _SWAP_FAST_r01 1570 -#define _SWAP_FAST_r11 1571 -#define _SWAP_FAST_r22 1572 -#define _SWAP_FAST_r33 1573 -#define _SWAP_FAST_0_r01 1574 -#define _SWAP_FAST_0_r11 1575 -#define _SWAP_FAST_0_r22 1576 -#define _SWAP_FAST_0_r33 1577 -#define _SWAP_FAST_1_r01 1578 -#define _SWAP_FAST_1_r11 1579 -#define _SWAP_FAST_1_r22 1580 -#define _SWAP_FAST_1_r33 1581 -#define _SWAP_FAST_2_r01 1582 -#define _SWAP_FAST_2_r11 1583 -#define _SWAP_FAST_2_r22 1584 -#define _SWAP_FAST_2_r33 1585 -#define _SWAP_FAST_3_r01 1586 -#define _SWAP_FAST_3_r11 1587 -#define _SWAP_FAST_3_r22 1588 -#define _SWAP_FAST_3_r33 1589 -#define _SWAP_FAST_4_r01 1590 -#define _SWAP_FAST_4_r11 1591 -#define _SWAP_FAST_4_r22 1592 -#define _SWAP_FAST_4_r33 1593 -#define _SWAP_FAST_5_r01 1594 -#define _SWAP_FAST_5_r11 1595 -#define _SWAP_FAST_5_r22 1596 -#define _SWAP_FAST_5_r33 1597 -#define _SWAP_FAST_6_r01 1598 -#define _SWAP_FAST_6_r11 1599 -#define _SWAP_FAST_6_r22 1600 -#define _SWAP_FAST_6_r33 1601 -#define _SWAP_FAST_7_r01 1602 -#define _SWAP_FAST_7_r11 1603 -#define _SWAP_FAST_7_r22 1604 -#define _SWAP_FAST_7_r33 1605 -#define _TIER2_RESUME_CHECK_r00 1606 -#define _TIER2_RESUME_CHECK_r11 1607 -#define _TIER2_RESUME_CHECK_r22 1608 -#define _TIER2_RESUME_CHECK_r33 1609 -#define _TO_BOOL_r11 1610 -#define _TO_BOOL_BOOL_r01 1611 -#define _TO_BOOL_BOOL_r11 1612 -#define _TO_BOOL_BOOL_r22 1613 -#define _TO_BOOL_BOOL_r33 1614 -#define _TO_BOOL_INT_r02 1615 -#define _TO_BOOL_INT_r12 1616 -#define _TO_BOOL_INT_r23 1617 -#define _TO_BOOL_LIST_r02 1618 -#define _TO_BOOL_LIST_r12 1619 -#define _TO_BOOL_LIST_r23 1620 -#define _TO_BOOL_NONE_r01 1621 -#define _TO_BOOL_NONE_r11 1622 -#define _TO_BOOL_NONE_r22 1623 -#define _TO_BOOL_NONE_r33 1624 -#define _TO_BOOL_STR_r02 1625 -#define _TO_BOOL_STR_r12 1626 -#define _TO_BOOL_STR_r23 1627 -#define _TRACE_RECORD_r00 1628 -#define _UNARY_INVERT_r12 1629 -#define _UNARY_NEGATIVE_r12 1630 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r02 1631 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r12 1632 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r23 1633 -#define _UNARY_NOT_r01 1634 -#define _UNARY_NOT_r11 1635 -#define _UNARY_NOT_r22 1636 -#define _UNARY_NOT_r33 1637 -#define _UNPACK_EX_r10 1638 -#define _UNPACK_SEQUENCE_r10 1639 -#define _UNPACK_SEQUENCE_LIST_r10 1640 -#define _UNPACK_SEQUENCE_TUPLE_r10 1641 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1642 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1643 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1644 -#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1645 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1646 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1647 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1648 -#define _WITH_EXCEPT_START_r33 1649 -#define _YIELD_VALUE_r11 1650 -#define MAX_UOP_REGS_ID 1650 +#define _YIELD_VALUE 652 +#define MAX_UOP_ID 652 +#define _ALLOCATE_OBJECT_r00 653 +#define _BINARY_OP_r23 654 +#define _BINARY_OP_ADD_FLOAT_r03 655 +#define _BINARY_OP_ADD_FLOAT_r13 656 +#define _BINARY_OP_ADD_FLOAT_r23 657 +#define _BINARY_OP_ADD_FLOAT_INPLACE_r03 658 +#define _BINARY_OP_ADD_FLOAT_INPLACE_r13 659 +#define _BINARY_OP_ADD_FLOAT_INPLACE_r23 660 +#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r03 661 +#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r13 662 +#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r23 663 +#define _BINARY_OP_ADD_INT_r03 664 +#define _BINARY_OP_ADD_INT_r13 665 +#define _BINARY_OP_ADD_INT_r23 666 +#define _BINARY_OP_ADD_INT_INPLACE_r03 667 +#define _BINARY_OP_ADD_INT_INPLACE_r13 668 +#define _BINARY_OP_ADD_INT_INPLACE_r23 669 +#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r03 670 +#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r13 671 +#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r23 672 +#define _BINARY_OP_ADD_UNICODE_r03 673 +#define _BINARY_OP_ADD_UNICODE_r13 674 +#define _BINARY_OP_ADD_UNICODE_r23 675 +#define _BINARY_OP_EXTEND_r23 676 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 677 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 678 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 679 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 680 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r03 681 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r13 682 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r23 683 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r03 684 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r13 685 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r23 686 +#define _BINARY_OP_MULTIPLY_INT_r03 687 +#define _BINARY_OP_MULTIPLY_INT_r13 688 +#define _BINARY_OP_MULTIPLY_INT_r23 689 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_r03 690 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_r13 691 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_r23 692 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r03 693 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r13 694 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r23 695 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 696 +#define _BINARY_OP_SUBSCR_DICT_r23 697 +#define _BINARY_OP_SUBSCR_DICT_KNOWN_HASH_r23 698 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 699 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 700 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 701 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 702 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 703 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r23 704 +#define _BINARY_OP_SUBSCR_STR_INT_r23 705 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 706 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 707 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 708 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 709 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 710 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 711 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 712 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r03 713 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r13 714 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r23 715 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r03 716 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r13 717 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r23 718 +#define _BINARY_OP_SUBTRACT_INT_r03 719 +#define _BINARY_OP_SUBTRACT_INT_r13 720 +#define _BINARY_OP_SUBTRACT_INT_r23 721 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_r03 722 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_r13 723 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_r23 724 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r03 725 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r13 726 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r23 727 +#define _BINARY_OP_TRUEDIV_FLOAT_r23 728 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r03 729 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r13 730 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r23 731 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r03 732 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r13 733 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r23 734 +#define _BINARY_SLICE_r31 735 +#define _BUILD_INTERPOLATION_r01 736 +#define _BUILD_LIST_r01 737 +#define _BUILD_MAP_r01 738 +#define _BUILD_SET_r01 739 +#define _BUILD_SLICE_r01 740 +#define _BUILD_STRING_r01 741 +#define _BUILD_TEMPLATE_r21 742 +#define _BUILD_TUPLE_r01 743 +#define _CALL_BUILTIN_CLASS_r00 744 +#define _CALL_BUILTIN_FAST_r00 745 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r00 746 +#define _CALL_BUILTIN_O_r03 747 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 748 +#define _CALL_INTRINSIC_1_r12 749 +#define _CALL_INTRINSIC_2_r23 750 +#define _CALL_ISINSTANCE_r31 751 +#define _CALL_KW_NON_PY_r11 752 +#define _CALL_LEN_r33 753 +#define _CALL_LIST_APPEND_r03 754 +#define _CALL_LIST_APPEND_r13 755 +#define _CALL_LIST_APPEND_r23 756 +#define _CALL_LIST_APPEND_r33 757 +#define _CALL_METHOD_DESCRIPTOR_FAST_r00 758 +#define _CALL_METHOD_DESCRIPTOR_FAST_INLINE_r00 759 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 760 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_INLINE_r00 761 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r03 762 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_INLINE_r03 763 +#define _CALL_METHOD_DESCRIPTOR_O_r03 764 +#define _CALL_METHOD_DESCRIPTOR_O_INLINE_r03 765 +#define _CALL_NON_PY_GENERAL_r01 766 +#define _CALL_STR_1_r32 767 +#define _CALL_TUPLE_1_r32 768 +#define _CALL_TYPE_1_r02 769 +#define _CALL_TYPE_1_r12 770 +#define _CALL_TYPE_1_r22 771 +#define _CALL_TYPE_1_r32 772 +#define _CHECK_ATTR_CLASS_r01 773 +#define _CHECK_ATTR_CLASS_r11 774 +#define _CHECK_ATTR_CLASS_r22 775 +#define _CHECK_ATTR_CLASS_r33 776 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 777 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 778 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 779 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 780 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 781 +#define _CHECK_EG_MATCH_r22 782 +#define _CHECK_EXC_MATCH_r22 783 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 784 +#define _CHECK_FUNCTION_VERSION_r00 785 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 786 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 787 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 788 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 789 +#define _CHECK_FUNCTION_VERSION_KW_r11 790 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 791 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 792 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 793 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 794 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 795 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 796 +#define _CHECK_IS_PY_CALLABLE_EX_r03 797 +#define _CHECK_IS_PY_CALLABLE_EX_r13 798 +#define _CHECK_IS_PY_CALLABLE_EX_r23 799 +#define _CHECK_IS_PY_CALLABLE_EX_r33 800 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 801 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 802 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 803 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 804 +#define _CHECK_METHOD_VERSION_r00 805 +#define _CHECK_METHOD_VERSION_KW_r11 806 +#define _CHECK_OBJECT_r00 807 +#define _CHECK_PEP_523_r00 808 +#define _CHECK_PEP_523_r11 809 +#define _CHECK_PEP_523_r22 810 +#define _CHECK_PEP_523_r33 811 +#define _CHECK_PERIODIC_r00 812 +#define _CHECK_PERIODIC_AT_END_r00 813 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 814 +#define _CHECK_RECURSION_LIMIT_r00 815 +#define _CHECK_RECURSION_LIMIT_r11 816 +#define _CHECK_RECURSION_LIMIT_r22 817 +#define _CHECK_RECURSION_LIMIT_r33 818 +#define _CHECK_RECURSION_REMAINING_r00 819 +#define _CHECK_RECURSION_REMAINING_r11 820 +#define _CHECK_RECURSION_REMAINING_r22 821 +#define _CHECK_RECURSION_REMAINING_r33 822 +#define _CHECK_STACK_SPACE_r00 823 +#define _CHECK_STACK_SPACE_OPERAND_r00 824 +#define _CHECK_STACK_SPACE_OPERAND_r11 825 +#define _CHECK_STACK_SPACE_OPERAND_r22 826 +#define _CHECK_STACK_SPACE_OPERAND_r33 827 +#define _CHECK_VALIDITY_r00 828 +#define _CHECK_VALIDITY_r11 829 +#define _CHECK_VALIDITY_r22 830 +#define _CHECK_VALIDITY_r33 831 +#define _COLD_DYNAMIC_EXIT_r00 832 +#define _COLD_EXIT_r00 833 +#define _COMPARE_OP_r21 834 +#define _COMPARE_OP_FLOAT_r03 835 +#define _COMPARE_OP_FLOAT_r13 836 +#define _COMPARE_OP_FLOAT_r23 837 +#define _COMPARE_OP_INT_r23 838 +#define _COMPARE_OP_STR_r23 839 +#define _CONTAINS_OP_r23 840 +#define _CONTAINS_OP_DICT_r23 841 +#define _CONTAINS_OP_SET_r23 842 +#define _CONVERT_VALUE_r11 843 +#define _COPY_r01 844 +#define _COPY_1_r02 845 +#define _COPY_1_r12 846 +#define _COPY_1_r23 847 +#define _COPY_2_r03 848 +#define _COPY_2_r13 849 +#define _COPY_2_r23 850 +#define _COPY_3_r03 851 +#define _COPY_3_r13 852 +#define _COPY_3_r23 853 +#define _COPY_3_r33 854 +#define _COPY_FREE_VARS_r00 855 +#define _COPY_FREE_VARS_r11 856 +#define _COPY_FREE_VARS_r22 857 +#define _COPY_FREE_VARS_r33 858 +#define _CREATE_INIT_FRAME_r01 859 +#define _DELETE_DEREF_r00 860 +#define _DELETE_FAST_r00 861 +#define _DELETE_SUBSCR_r20 862 +#define _DEOPT_r00 863 +#define _DEOPT_r10 864 +#define _DEOPT_r20 865 +#define _DEOPT_r30 866 +#define _DICT_MERGE_r11 867 +#define _DICT_UPDATE_r11 868 +#define _DO_CALL_r01 869 +#define _DO_CALL_FUNCTION_EX_r31 870 +#define _DO_CALL_KW_r11 871 +#define _DYNAMIC_EXIT_r00 872 +#define _DYNAMIC_EXIT_r10 873 +#define _DYNAMIC_EXIT_r20 874 +#define _DYNAMIC_EXIT_r30 875 +#define _END_FOR_r10 876 +#define _END_SEND_r31 877 +#define _ERROR_POP_N_r00 878 +#define _EXIT_INIT_CHECK_r10 879 +#define _EXIT_TRACE_r00 880 +#define _EXIT_TRACE_r10 881 +#define _EXIT_TRACE_r20 882 +#define _EXIT_TRACE_r30 883 +#define _EXPAND_METHOD_r00 884 +#define _EXPAND_METHOD_KW_r11 885 +#define _FATAL_ERROR_r00 886 +#define _FATAL_ERROR_r11 887 +#define _FATAL_ERROR_r22 888 +#define _FATAL_ERROR_r33 889 +#define _FORMAT_SIMPLE_r11 890 +#define _FORMAT_WITH_SPEC_r21 891 +#define _FOR_ITER_r23 892 +#define _FOR_ITER_GEN_FRAME_r03 893 +#define _FOR_ITER_GEN_FRAME_r13 894 +#define _FOR_ITER_GEN_FRAME_r23 895 +#define _FOR_ITER_TIER_TWO_r23 896 +#define _FOR_ITER_VIRTUAL_r23 897 +#define _FOR_ITER_VIRTUAL_TIER_TWO_r23 898 +#define _GET_AITER_r11 899 +#define _GET_ANEXT_r12 900 +#define _GET_AWAITABLE_r11 901 +#define _GET_ITER_r12 902 +#define _GET_ITER_TRAD_r12 903 +#define _GET_LEN_r12 904 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r03 905 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r13 906 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r23 907 +#define _GUARD_3OS_ASYNC_GEN_ASEND_r33 908 +#define _GUARD_BINARY_OP_EXTEND_r22 909 +#define _GUARD_BINARY_OP_EXTEND_LHS_r02 910 +#define _GUARD_BINARY_OP_EXTEND_LHS_r12 911 +#define _GUARD_BINARY_OP_EXTEND_LHS_r22 912 +#define _GUARD_BINARY_OP_EXTEND_LHS_r33 913 +#define _GUARD_BINARY_OP_EXTEND_RHS_r02 914 +#define _GUARD_BINARY_OP_EXTEND_RHS_r12 915 +#define _GUARD_BINARY_OP_EXTEND_RHS_r22 916 +#define _GUARD_BINARY_OP_EXTEND_RHS_r33 917 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 918 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 919 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 920 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 921 +#define _GUARD_BIT_IS_SET_POP_r00 922 +#define _GUARD_BIT_IS_SET_POP_r10 923 +#define _GUARD_BIT_IS_SET_POP_r21 924 +#define _GUARD_BIT_IS_SET_POP_r32 925 +#define _GUARD_BIT_IS_SET_POP_4_r00 926 +#define _GUARD_BIT_IS_SET_POP_4_r10 927 +#define _GUARD_BIT_IS_SET_POP_4_r21 928 +#define _GUARD_BIT_IS_SET_POP_4_r32 929 +#define _GUARD_BIT_IS_SET_POP_5_r00 930 +#define _GUARD_BIT_IS_SET_POP_5_r10 931 +#define _GUARD_BIT_IS_SET_POP_5_r21 932 +#define _GUARD_BIT_IS_SET_POP_5_r32 933 +#define _GUARD_BIT_IS_SET_POP_6_r00 934 +#define _GUARD_BIT_IS_SET_POP_6_r10 935 +#define _GUARD_BIT_IS_SET_POP_6_r21 936 +#define _GUARD_BIT_IS_SET_POP_6_r32 937 +#define _GUARD_BIT_IS_SET_POP_7_r00 938 +#define _GUARD_BIT_IS_SET_POP_7_r10 939 +#define _GUARD_BIT_IS_SET_POP_7_r21 940 +#define _GUARD_BIT_IS_SET_POP_7_r32 941 +#define _GUARD_BIT_IS_UNSET_POP_r00 942 +#define _GUARD_BIT_IS_UNSET_POP_r10 943 +#define _GUARD_BIT_IS_UNSET_POP_r21 944 +#define _GUARD_BIT_IS_UNSET_POP_r32 945 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 946 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 947 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 948 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 949 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 950 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 951 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 952 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 953 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 954 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 955 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 956 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 957 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 958 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 959 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 960 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 961 +#define _GUARD_CALLABLE_BUILTIN_CLASS_r00 962 +#define _GUARD_CALLABLE_BUILTIN_FAST_r00 963 +#define _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS_r00 964 +#define _GUARD_CALLABLE_BUILTIN_O_r00 965 +#define _GUARD_CALLABLE_ISINSTANCE_r03 966 +#define _GUARD_CALLABLE_ISINSTANCE_r13 967 +#define _GUARD_CALLABLE_ISINSTANCE_r23 968 +#define _GUARD_CALLABLE_ISINSTANCE_r33 969 +#define _GUARD_CALLABLE_LEN_r03 970 +#define _GUARD_CALLABLE_LEN_r13 971 +#define _GUARD_CALLABLE_LEN_r23 972 +#define _GUARD_CALLABLE_LEN_r33 973 +#define _GUARD_CALLABLE_LIST_APPEND_r03 974 +#define _GUARD_CALLABLE_LIST_APPEND_r13 975 +#define _GUARD_CALLABLE_LIST_APPEND_r23 976 +#define _GUARD_CALLABLE_LIST_APPEND_r33 977 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_r00 978 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 979 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS_r00 980 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_O_r00 981 +#define _GUARD_CALLABLE_STR_1_r03 982 +#define _GUARD_CALLABLE_STR_1_r13 983 +#define _GUARD_CALLABLE_STR_1_r23 984 +#define _GUARD_CALLABLE_STR_1_r33 985 +#define _GUARD_CALLABLE_TUPLE_1_r03 986 +#define _GUARD_CALLABLE_TUPLE_1_r13 987 +#define _GUARD_CALLABLE_TUPLE_1_r23 988 +#define _GUARD_CALLABLE_TUPLE_1_r33 989 +#define _GUARD_CALLABLE_TYPE_1_r03 990 +#define _GUARD_CALLABLE_TYPE_1_r13 991 +#define _GUARD_CALLABLE_TYPE_1_r23 992 +#define _GUARD_CALLABLE_TYPE_1_r33 993 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r00 994 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r11 995 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r22 996 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r33 997 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r00 998 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r11 999 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r22 1000 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r33 1001 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r00 1002 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r11 1003 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r22 1004 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r33 1005 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r00 1006 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r11 1007 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r22 1008 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r33 1009 +#define _GUARD_DORV_NO_DICT_r01 1010 +#define _GUARD_DORV_NO_DICT_r11 1011 +#define _GUARD_DORV_NO_DICT_r22 1012 +#define _GUARD_DORV_NO_DICT_r33 1013 +#define _GUARD_GLOBALS_VERSION_r00 1014 +#define _GUARD_GLOBALS_VERSION_r11 1015 +#define _GUARD_GLOBALS_VERSION_r22 1016 +#define _GUARD_GLOBALS_VERSION_r33 1017 +#define _GUARD_IP_RETURN_GENERATOR_r00 1018 +#define _GUARD_IP_RETURN_GENERATOR_r11 1019 +#define _GUARD_IP_RETURN_GENERATOR_r22 1020 +#define _GUARD_IP_RETURN_GENERATOR_r33 1021 +#define _GUARD_IP_RETURN_VALUE_r00 1022 +#define _GUARD_IP_RETURN_VALUE_r11 1023 +#define _GUARD_IP_RETURN_VALUE_r22 1024 +#define _GUARD_IP_RETURN_VALUE_r33 1025 +#define _GUARD_IP_YIELD_VALUE_r00 1026 +#define _GUARD_IP_YIELD_VALUE_r11 1027 +#define _GUARD_IP_YIELD_VALUE_r22 1028 +#define _GUARD_IP_YIELD_VALUE_r33 1029 +#define _GUARD_IP__PUSH_FRAME_r00 1030 +#define _GUARD_IP__PUSH_FRAME_r11 1031 +#define _GUARD_IP__PUSH_FRAME_r22 1032 +#define _GUARD_IP__PUSH_FRAME_r33 1033 +#define _GUARD_IS_FALSE_POP_r00 1034 +#define _GUARD_IS_FALSE_POP_r10 1035 +#define _GUARD_IS_FALSE_POP_r21 1036 +#define _GUARD_IS_FALSE_POP_r32 1037 +#define _GUARD_IS_NONE_POP_r00 1038 +#define _GUARD_IS_NONE_POP_r10 1039 +#define _GUARD_IS_NONE_POP_r21 1040 +#define _GUARD_IS_NONE_POP_r32 1041 +#define _GUARD_IS_NOT_NONE_POP_r10 1042 +#define _GUARD_IS_TRUE_POP_r00 1043 +#define _GUARD_IS_TRUE_POP_r10 1044 +#define _GUARD_IS_TRUE_POP_r21 1045 +#define _GUARD_IS_TRUE_POP_r32 1046 +#define _GUARD_ITERATOR_r01 1047 +#define _GUARD_ITERATOR_r11 1048 +#define _GUARD_ITERATOR_r22 1049 +#define _GUARD_ITERATOR_r33 1050 +#define _GUARD_ITER_VIRTUAL_r01 1051 +#define _GUARD_ITER_VIRTUAL_r11 1052 +#define _GUARD_ITER_VIRTUAL_r22 1053 +#define _GUARD_ITER_VIRTUAL_r33 1054 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r03 1055 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r13 1056 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r23 1057 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r33 1058 +#define _GUARD_NOS_COMPACT_ASCII_r02 1059 +#define _GUARD_NOS_COMPACT_ASCII_r12 1060 +#define _GUARD_NOS_COMPACT_ASCII_r22 1061 +#define _GUARD_NOS_COMPACT_ASCII_r33 1062 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 1063 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 1064 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 1065 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 1066 +#define _GUARD_NOS_DICT_SUBSCRIPT_r02 1067 +#define _GUARD_NOS_DICT_SUBSCRIPT_r12 1068 +#define _GUARD_NOS_DICT_SUBSCRIPT_r22 1069 +#define _GUARD_NOS_DICT_SUBSCRIPT_r33 1070 +#define _GUARD_NOS_FLOAT_r02 1071 +#define _GUARD_NOS_FLOAT_r12 1072 +#define _GUARD_NOS_FLOAT_r22 1073 +#define _GUARD_NOS_FLOAT_r33 1074 +#define _GUARD_NOS_INT_r02 1075 +#define _GUARD_NOS_INT_r12 1076 +#define _GUARD_NOS_INT_r22 1077 +#define _GUARD_NOS_INT_r33 1078 +#define _GUARD_NOS_ITER_VIRTUAL_r02 1079 +#define _GUARD_NOS_ITER_VIRTUAL_r12 1080 +#define _GUARD_NOS_ITER_VIRTUAL_r22 1081 +#define _GUARD_NOS_ITER_VIRTUAL_r33 1082 +#define _GUARD_NOS_LIST_r02 1083 +#define _GUARD_NOS_LIST_r12 1084 +#define _GUARD_NOS_LIST_r22 1085 +#define _GUARD_NOS_LIST_r33 1086 +#define _GUARD_NOS_NOT_NULL_r02 1087 +#define _GUARD_NOS_NOT_NULL_r12 1088 +#define _GUARD_NOS_NOT_NULL_r22 1089 +#define _GUARD_NOS_NOT_NULL_r33 1090 +#define _GUARD_NOS_NULL_r02 1091 +#define _GUARD_NOS_NULL_r12 1092 +#define _GUARD_NOS_NULL_r22 1093 +#define _GUARD_NOS_NULL_r33 1094 +#define _GUARD_NOS_OVERFLOWED_r02 1095 +#define _GUARD_NOS_OVERFLOWED_r12 1096 +#define _GUARD_NOS_OVERFLOWED_r22 1097 +#define _GUARD_NOS_OVERFLOWED_r33 1098 +#define _GUARD_NOS_TUPLE_r02 1099 +#define _GUARD_NOS_TUPLE_r12 1100 +#define _GUARD_NOS_TUPLE_r22 1101 +#define _GUARD_NOS_TUPLE_r33 1102 +#define _GUARD_NOS_TYPE_VERSION_r02 1103 +#define _GUARD_NOS_TYPE_VERSION_r12 1104 +#define _GUARD_NOS_TYPE_VERSION_r22 1105 +#define _GUARD_NOS_TYPE_VERSION_r33 1106 +#define _GUARD_NOS_UNICODE_r02 1107 +#define _GUARD_NOS_UNICODE_r12 1108 +#define _GUARD_NOS_UNICODE_r22 1109 +#define _GUARD_NOS_UNICODE_r33 1110 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 1111 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 1112 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 1113 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 1114 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 1115 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 1116 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 1117 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 1118 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 1119 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 1120 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 1121 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 1122 +#define _GUARD_THIRD_NULL_r03 1123 +#define _GUARD_THIRD_NULL_r13 1124 +#define _GUARD_THIRD_NULL_r23 1125 +#define _GUARD_THIRD_NULL_r33 1126 +#define _GUARD_TOS_ANY_DICT_r01 1127 +#define _GUARD_TOS_ANY_DICT_r11 1128 +#define _GUARD_TOS_ANY_DICT_r22 1129 +#define _GUARD_TOS_ANY_DICT_r33 1130 +#define _GUARD_TOS_ANY_SET_r01 1131 +#define _GUARD_TOS_ANY_SET_r11 1132 +#define _GUARD_TOS_ANY_SET_r22 1133 +#define _GUARD_TOS_ANY_SET_r33 1134 +#define _GUARD_TOS_DICT_r01 1135 +#define _GUARD_TOS_DICT_r11 1136 +#define _GUARD_TOS_DICT_r22 1137 +#define _GUARD_TOS_DICT_r33 1138 +#define _GUARD_TOS_FLOAT_r01 1139 +#define _GUARD_TOS_FLOAT_r11 1140 +#define _GUARD_TOS_FLOAT_r22 1141 +#define _GUARD_TOS_FLOAT_r33 1142 +#define _GUARD_TOS_FROZENDICT_r01 1143 +#define _GUARD_TOS_FROZENDICT_r11 1144 +#define _GUARD_TOS_FROZENDICT_r22 1145 +#define _GUARD_TOS_FROZENDICT_r33 1146 +#define _GUARD_TOS_FROZENSET_r01 1147 +#define _GUARD_TOS_FROZENSET_r11 1148 +#define _GUARD_TOS_FROZENSET_r22 1149 +#define _GUARD_TOS_FROZENSET_r33 1150 +#define _GUARD_TOS_INT_r01 1151 +#define _GUARD_TOS_INT_r11 1152 +#define _GUARD_TOS_INT_r22 1153 +#define _GUARD_TOS_INT_r33 1154 +#define _GUARD_TOS_IS_NONE_r01 1155 +#define _GUARD_TOS_IS_NONE_r11 1156 +#define _GUARD_TOS_IS_NONE_r22 1157 +#define _GUARD_TOS_IS_NONE_r33 1158 +#define _GUARD_TOS_LIST_r01 1159 +#define _GUARD_TOS_LIST_r11 1160 +#define _GUARD_TOS_LIST_r22 1161 +#define _GUARD_TOS_LIST_r33 1162 +#define _GUARD_TOS_NOT_NULL_r01 1163 +#define _GUARD_TOS_NOT_NULL_r11 1164 +#define _GUARD_TOS_NOT_NULL_r22 1165 +#define _GUARD_TOS_NOT_NULL_r33 1166 +#define _GUARD_TOS_OVERFLOWED_r01 1167 +#define _GUARD_TOS_OVERFLOWED_r11 1168 +#define _GUARD_TOS_OVERFLOWED_r22 1169 +#define _GUARD_TOS_OVERFLOWED_r33 1170 +#define _GUARD_TOS_SET_r01 1171 +#define _GUARD_TOS_SET_r11 1172 +#define _GUARD_TOS_SET_r22 1173 +#define _GUARD_TOS_SET_r33 1174 +#define _GUARD_TOS_SLICE_r01 1175 +#define _GUARD_TOS_SLICE_r11 1176 +#define _GUARD_TOS_SLICE_r22 1177 +#define _GUARD_TOS_SLICE_r33 1178 +#define _GUARD_TOS_TUPLE_r01 1179 +#define _GUARD_TOS_TUPLE_r11 1180 +#define _GUARD_TOS_TUPLE_r22 1181 +#define _GUARD_TOS_TUPLE_r33 1182 +#define _GUARD_TOS_UNICODE_r01 1183 +#define _GUARD_TOS_UNICODE_r11 1184 +#define _GUARD_TOS_UNICODE_r22 1185 +#define _GUARD_TOS_UNICODE_r33 1186 +#define _GUARD_TYPE_r01 1187 +#define _GUARD_TYPE_r11 1188 +#define _GUARD_TYPE_r22 1189 +#define _GUARD_TYPE_r33 1190 +#define _GUARD_TYPE_ITER_r02 1191 +#define _GUARD_TYPE_ITER_r12 1192 +#define _GUARD_TYPE_ITER_r22 1193 +#define _GUARD_TYPE_ITER_r33 1194 +#define _GUARD_TYPE_VERSION_r01 1195 +#define _GUARD_TYPE_VERSION_r11 1196 +#define _GUARD_TYPE_VERSION_r22 1197 +#define _GUARD_TYPE_VERSION_r33 1198 +#define _GUARD_TYPE_VERSION_LOCKED_r01 1199 +#define _GUARD_TYPE_VERSION_LOCKED_r11 1200 +#define _GUARD_TYPE_VERSION_LOCKED_r22 1201 +#define _GUARD_TYPE_VERSION_LOCKED_r33 1202 +#define _HANDLE_PENDING_AND_DEOPT_r00 1203 +#define _HANDLE_PENDING_AND_DEOPT_r10 1204 +#define _HANDLE_PENDING_AND_DEOPT_r20 1205 +#define _HANDLE_PENDING_AND_DEOPT_r30 1206 +#define _IMPORT_FROM_r12 1207 +#define _IMPORT_NAME_r21 1208 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1209 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1210 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1211 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1212 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1213 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1214 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1215 +#define _INSERT_NULL_r10 1216 +#define _INSTRUMENTED_FOR_ITER_r23 1217 +#define _INSTRUMENTED_INSTRUCTION_r00 1218 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1219 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1220 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1221 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1222 +#define _INSTRUMENTED_LINE_r00 1223 +#define _INSTRUMENTED_NOT_TAKEN_r00 1224 +#define _INSTRUMENTED_NOT_TAKEN_r11 1225 +#define _INSTRUMENTED_NOT_TAKEN_r22 1226 +#define _INSTRUMENTED_NOT_TAKEN_r33 1227 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1228 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1229 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1230 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1231 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1232 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1233 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1234 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1235 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1236 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1237 +#define _IS_NONE_r11 1238 +#define _IS_OP_r03 1239 +#define _IS_OP_r13 1240 +#define _IS_OP_r23 1241 +#define _ITER_CHECK_LIST_r02 1242 +#define _ITER_CHECK_LIST_r12 1243 +#define _ITER_CHECK_LIST_r22 1244 +#define _ITER_CHECK_LIST_r33 1245 +#define _ITER_CHECK_RANGE_r02 1246 +#define _ITER_CHECK_RANGE_r12 1247 +#define _ITER_CHECK_RANGE_r22 1248 +#define _ITER_CHECK_RANGE_r33 1249 +#define _ITER_CHECK_TUPLE_r02 1250 +#define _ITER_CHECK_TUPLE_r12 1251 +#define _ITER_CHECK_TUPLE_r22 1252 +#define _ITER_CHECK_TUPLE_r33 1253 +#define _ITER_JUMP_LIST_r02 1254 +#define _ITER_JUMP_LIST_r12 1255 +#define _ITER_JUMP_LIST_r22 1256 +#define _ITER_JUMP_LIST_r33 1257 +#define _ITER_JUMP_RANGE_r02 1258 +#define _ITER_JUMP_RANGE_r12 1259 +#define _ITER_JUMP_RANGE_r22 1260 +#define _ITER_JUMP_RANGE_r33 1261 +#define _ITER_JUMP_TUPLE_r02 1262 +#define _ITER_JUMP_TUPLE_r12 1263 +#define _ITER_JUMP_TUPLE_r22 1264 +#define _ITER_JUMP_TUPLE_r33 1265 +#define _ITER_NEXT_INLINE_r23 1266 +#define _ITER_NEXT_LIST_r23 1267 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1268 +#define _ITER_NEXT_RANGE_r03 1269 +#define _ITER_NEXT_RANGE_r13 1270 +#define _ITER_NEXT_RANGE_r23 1271 +#define _ITER_NEXT_TUPLE_r03 1272 +#define _ITER_NEXT_TUPLE_r13 1273 +#define _ITER_NEXT_TUPLE_r23 1274 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1275 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1276 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1277 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1278 +#define _JUMP_TO_TOP_r00 1279 +#define _LIST_APPEND_r10 1280 +#define _LIST_EXTEND_r11 1281 +#define _LOAD_ATTR_r10 1282 +#define _LOAD_ATTR_CLASS_r11 1283 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME_r11 1284 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1285 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1286 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1287 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1288 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1289 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1290 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1291 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1292 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1293 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1294 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1295 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1296 +#define _LOAD_ATTR_MODULE_r12 1297 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1298 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1299 +#define _LOAD_ATTR_PROPERTY_FRAME_r01 1300 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1301 +#define _LOAD_ATTR_PROPERTY_FRAME_r22 1302 +#define _LOAD_ATTR_PROPERTY_FRAME_r33 1303 +#define _LOAD_ATTR_SLOT_r02 1304 +#define _LOAD_ATTR_SLOT_r12 1305 +#define _LOAD_ATTR_SLOT_r23 1306 +#define _LOAD_ATTR_WITH_HINT_r12 1307 +#define _LOAD_BUILD_CLASS_r01 1308 +#define _LOAD_BYTECODE_r00 1309 +#define _LOAD_COMMON_CONSTANT_r01 1310 +#define _LOAD_COMMON_CONSTANT_r12 1311 +#define _LOAD_COMMON_CONSTANT_r23 1312 +#define _LOAD_CONST_r01 1313 +#define _LOAD_CONST_r12 1314 +#define _LOAD_CONST_r23 1315 +#define _LOAD_CONST_INLINE_r01 1316 +#define _LOAD_CONST_INLINE_r12 1317 +#define _LOAD_CONST_INLINE_r23 1318 +#define _LOAD_CONST_INLINE_BORROW_r01 1319 +#define _LOAD_CONST_INLINE_BORROW_r12 1320 +#define _LOAD_CONST_INLINE_BORROW_r23 1321 +#define _LOAD_DEREF_r01 1322 +#define _LOAD_FAST_r01 1323 +#define _LOAD_FAST_r12 1324 +#define _LOAD_FAST_r23 1325 +#define _LOAD_FAST_0_r01 1326 +#define _LOAD_FAST_0_r12 1327 +#define _LOAD_FAST_0_r23 1328 +#define _LOAD_FAST_1_r01 1329 +#define _LOAD_FAST_1_r12 1330 +#define _LOAD_FAST_1_r23 1331 +#define _LOAD_FAST_2_r01 1332 +#define _LOAD_FAST_2_r12 1333 +#define _LOAD_FAST_2_r23 1334 +#define _LOAD_FAST_3_r01 1335 +#define _LOAD_FAST_3_r12 1336 +#define _LOAD_FAST_3_r23 1337 +#define _LOAD_FAST_4_r01 1338 +#define _LOAD_FAST_4_r12 1339 +#define _LOAD_FAST_4_r23 1340 +#define _LOAD_FAST_5_r01 1341 +#define _LOAD_FAST_5_r12 1342 +#define _LOAD_FAST_5_r23 1343 +#define _LOAD_FAST_6_r01 1344 +#define _LOAD_FAST_6_r12 1345 +#define _LOAD_FAST_6_r23 1346 +#define _LOAD_FAST_7_r01 1347 +#define _LOAD_FAST_7_r12 1348 +#define _LOAD_FAST_7_r23 1349 +#define _LOAD_FAST_AND_CLEAR_r01 1350 +#define _LOAD_FAST_AND_CLEAR_r12 1351 +#define _LOAD_FAST_AND_CLEAR_r23 1352 +#define _LOAD_FAST_BORROW_r01 1353 +#define _LOAD_FAST_BORROW_r12 1354 +#define _LOAD_FAST_BORROW_r23 1355 +#define _LOAD_FAST_BORROW_0_r01 1356 +#define _LOAD_FAST_BORROW_0_r12 1357 +#define _LOAD_FAST_BORROW_0_r23 1358 +#define _LOAD_FAST_BORROW_1_r01 1359 +#define _LOAD_FAST_BORROW_1_r12 1360 +#define _LOAD_FAST_BORROW_1_r23 1361 +#define _LOAD_FAST_BORROW_2_r01 1362 +#define _LOAD_FAST_BORROW_2_r12 1363 +#define _LOAD_FAST_BORROW_2_r23 1364 +#define _LOAD_FAST_BORROW_3_r01 1365 +#define _LOAD_FAST_BORROW_3_r12 1366 +#define _LOAD_FAST_BORROW_3_r23 1367 +#define _LOAD_FAST_BORROW_4_r01 1368 +#define _LOAD_FAST_BORROW_4_r12 1369 +#define _LOAD_FAST_BORROW_4_r23 1370 +#define _LOAD_FAST_BORROW_5_r01 1371 +#define _LOAD_FAST_BORROW_5_r12 1372 +#define _LOAD_FAST_BORROW_5_r23 1373 +#define _LOAD_FAST_BORROW_6_r01 1374 +#define _LOAD_FAST_BORROW_6_r12 1375 +#define _LOAD_FAST_BORROW_6_r23 1376 +#define _LOAD_FAST_BORROW_7_r01 1377 +#define _LOAD_FAST_BORROW_7_r12 1378 +#define _LOAD_FAST_BORROW_7_r23 1379 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1380 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1381 +#define _LOAD_FAST_CHECK_r01 1382 +#define _LOAD_FAST_CHECK_r12 1383 +#define _LOAD_FAST_CHECK_r23 1384 +#define _LOAD_FAST_LOAD_FAST_r02 1385 +#define _LOAD_FAST_LOAD_FAST_r13 1386 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1387 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1388 +#define _LOAD_GLOBAL_r00 1389 +#define _LOAD_GLOBAL_BUILTINS_r01 1390 +#define _LOAD_GLOBAL_MODULE_r01 1391 +#define _LOAD_LOCALS_r01 1392 +#define _LOAD_LOCALS_r12 1393 +#define _LOAD_LOCALS_r23 1394 +#define _LOAD_NAME_r01 1395 +#define _LOAD_SMALL_INT_r01 1396 +#define _LOAD_SMALL_INT_r12 1397 +#define _LOAD_SMALL_INT_r23 1398 +#define _LOAD_SMALL_INT_0_r01 1399 +#define _LOAD_SMALL_INT_0_r12 1400 +#define _LOAD_SMALL_INT_0_r23 1401 +#define _LOAD_SMALL_INT_1_r01 1402 +#define _LOAD_SMALL_INT_1_r12 1403 +#define _LOAD_SMALL_INT_1_r23 1404 +#define _LOAD_SMALL_INT_2_r01 1405 +#define _LOAD_SMALL_INT_2_r12 1406 +#define _LOAD_SMALL_INT_2_r23 1407 +#define _LOAD_SMALL_INT_3_r01 1408 +#define _LOAD_SMALL_INT_3_r12 1409 +#define _LOAD_SMALL_INT_3_r23 1410 +#define _LOAD_SPECIAL_r00 1411 +#define _LOAD_SUPER_ATTR_ATTR_r31 1412 +#define _LOAD_SUPER_ATTR_METHOD_r32 1413 +#define _LOCK_OBJECT_r01 1414 +#define _LOCK_OBJECT_r11 1415 +#define _LOCK_OBJECT_r22 1416 +#define _LOCK_OBJECT_r33 1417 +#define _MAKE_CALLARGS_A_TUPLE_r33 1418 +#define _MAKE_CELL_r00 1419 +#define _MAKE_FUNCTION_r12 1420 +#define _MAKE_HEAP_SAFE_r01 1421 +#define _MAKE_HEAP_SAFE_r11 1422 +#define _MAKE_HEAP_SAFE_r22 1423 +#define _MAKE_HEAP_SAFE_r33 1424 +#define _MAKE_WARM_r00 1425 +#define _MAKE_WARM_r11 1426 +#define _MAKE_WARM_r22 1427 +#define _MAKE_WARM_r33 1428 +#define _MAP_ADD_r20 1429 +#define _MATCH_CLASS_r33 1430 +#define _MATCH_KEYS_r23 1431 +#define _MATCH_MAPPING_r02 1432 +#define _MATCH_MAPPING_r12 1433 +#define _MATCH_MAPPING_r23 1434 +#define _MATCH_SEQUENCE_r02 1435 +#define _MATCH_SEQUENCE_r12 1436 +#define _MATCH_SEQUENCE_r23 1437 +#define _MAYBE_EXPAND_METHOD_r00 1438 +#define _MAYBE_EXPAND_METHOD_KW_r11 1439 +#define _MONITOR_CALL_r00 1440 +#define _MONITOR_CALL_KW_r11 1441 +#define _MONITOR_JUMP_BACKWARD_r00 1442 +#define _MONITOR_JUMP_BACKWARD_r11 1443 +#define _MONITOR_JUMP_BACKWARD_r22 1444 +#define _MONITOR_JUMP_BACKWARD_r33 1445 +#define _MONITOR_RESUME_r00 1446 +#define _NOP_r00 1447 +#define _NOP_r11 1448 +#define _NOP_r22 1449 +#define _NOP_r33 1450 +#define _POP_EXCEPT_r10 1451 +#define _POP_ITER_r20 1452 +#define _POP_JUMP_IF_FALSE_r00 1453 +#define _POP_JUMP_IF_FALSE_r10 1454 +#define _POP_JUMP_IF_FALSE_r21 1455 +#define _POP_JUMP_IF_FALSE_r32 1456 +#define _POP_JUMP_IF_TRUE_r00 1457 +#define _POP_JUMP_IF_TRUE_r10 1458 +#define _POP_JUMP_IF_TRUE_r21 1459 +#define _POP_JUMP_IF_TRUE_r32 1460 +#define _POP_TOP_r10 1461 +#define _POP_TOP_FLOAT_r00 1462 +#define _POP_TOP_FLOAT_r10 1463 +#define _POP_TOP_FLOAT_r21 1464 +#define _POP_TOP_FLOAT_r32 1465 +#define _POP_TOP_INT_r00 1466 +#define _POP_TOP_INT_r10 1467 +#define _POP_TOP_INT_r21 1468 +#define _POP_TOP_INT_r32 1469 +#define _POP_TOP_NOP_r00 1470 +#define _POP_TOP_NOP_r10 1471 +#define _POP_TOP_NOP_r21 1472 +#define _POP_TOP_NOP_r32 1473 +#define _POP_TOP_OPARG_r00 1474 +#define _POP_TOP_UNICODE_r00 1475 +#define _POP_TOP_UNICODE_r10 1476 +#define _POP_TOP_UNICODE_r21 1477 +#define _POP_TOP_UNICODE_r32 1478 +#define _PUSH_EXC_INFO_r02 1479 +#define _PUSH_EXC_INFO_r12 1480 +#define _PUSH_EXC_INFO_r23 1481 +#define _PUSH_FRAME_r10 1482 +#define _PUSH_NULL_r01 1483 +#define _PUSH_NULL_r12 1484 +#define _PUSH_NULL_r23 1485 +#define _PUSH_NULL_CONDITIONAL_r00 1486 +#define _PUSH_TAGGED_ZERO_r01 1487 +#define _PUSH_TAGGED_ZERO_r12 1488 +#define _PUSH_TAGGED_ZERO_r23 1489 +#define _PY_FRAME_EX_r31 1490 +#define _PY_FRAME_GENERAL_r01 1491 +#define _PY_FRAME_KW_r11 1492 +#define _REPLACE_WITH_TRUE_r02 1493 +#define _REPLACE_WITH_TRUE_r12 1494 +#define _REPLACE_WITH_TRUE_r23 1495 +#define _RESUME_CHECK_r00 1496 +#define _RESUME_CHECK_r11 1497 +#define _RESUME_CHECK_r22 1498 +#define _RESUME_CHECK_r33 1499 +#define _RETURN_GENERATOR_r01 1500 +#define _RETURN_VALUE_r11 1501 +#define _RROT_3_r03 1502 +#define _RROT_3_r13 1503 +#define _RROT_3_r23 1504 +#define _RROT_3_r33 1505 +#define _SAVE_RETURN_OFFSET_r00 1506 +#define _SAVE_RETURN_OFFSET_r11 1507 +#define _SAVE_RETURN_OFFSET_r22 1508 +#define _SAVE_RETURN_OFFSET_r33 1509 +#define _SEND_ASYNC_GEN_r33 1510 +#define _SEND_ASYNC_GEN_TIER_TWO_r33 1511 +#define _SEND_GEN_FRAME_r33 1512 +#define _SEND_VIRTUAL_r33 1513 +#define _SEND_VIRTUAL_TIER_TWO_r03 1514 +#define _SEND_VIRTUAL_TIER_TWO_r13 1515 +#define _SEND_VIRTUAL_TIER_TWO_r23 1516 +#define _SEND_VIRTUAL_TIER_TWO_r33 1517 +#define _SETUP_ANNOTATIONS_r00 1518 +#define _SET_ADD_r10 1519 +#define _SET_FUNCTION_ATTRIBUTE_r01 1520 +#define _SET_FUNCTION_ATTRIBUTE_r11 1521 +#define _SET_FUNCTION_ATTRIBUTE_r21 1522 +#define _SET_FUNCTION_ATTRIBUTE_r32 1523 +#define _SET_IP_r00 1524 +#define _SET_IP_r11 1525 +#define _SET_IP_r22 1526 +#define _SET_IP_r33 1527 +#define _SET_UPDATE_r11 1528 +#define _SPILL_OR_RELOAD_r01 1529 +#define _SPILL_OR_RELOAD_r02 1530 +#define _SPILL_OR_RELOAD_r03 1531 +#define _SPILL_OR_RELOAD_r10 1532 +#define _SPILL_OR_RELOAD_r12 1533 +#define _SPILL_OR_RELOAD_r13 1534 +#define _SPILL_OR_RELOAD_r20 1535 +#define _SPILL_OR_RELOAD_r21 1536 +#define _SPILL_OR_RELOAD_r23 1537 +#define _SPILL_OR_RELOAD_r30 1538 +#define _SPILL_OR_RELOAD_r31 1539 +#define _SPILL_OR_RELOAD_r32 1540 +#define _START_EXECUTOR_r00 1541 +#define _STORE_ATTR_r20 1542 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1543 +#define _STORE_ATTR_SLOT_r21 1544 +#define _STORE_ATTR_WITH_HINT_r21 1545 +#define _STORE_DEREF_r10 1546 +#define _STORE_FAST_LOAD_FAST_r11 1547 +#define _STORE_FAST_STORE_FAST_r20 1548 +#define _STORE_GLOBAL_r10 1549 +#define _STORE_NAME_r10 1550 +#define _STORE_SLICE_r30 1551 +#define _STORE_SUBSCR_r30 1552 +#define _STORE_SUBSCR_DICT_r31 1553 +#define _STORE_SUBSCR_DICT_KNOWN_HASH_r31 1554 +#define _STORE_SUBSCR_LIST_INT_r32 1555 +#define _SWAP_r11 1556 +#define _SWAP_2_r02 1557 +#define _SWAP_2_r12 1558 +#define _SWAP_2_r22 1559 +#define _SWAP_2_r33 1560 +#define _SWAP_3_r03 1561 +#define _SWAP_3_r13 1562 +#define _SWAP_3_r23 1563 +#define _SWAP_3_r33 1564 +#define _SWAP_FAST_r01 1565 +#define _SWAP_FAST_r11 1566 +#define _SWAP_FAST_r22 1567 +#define _SWAP_FAST_r33 1568 +#define _SWAP_FAST_0_r01 1569 +#define _SWAP_FAST_0_r11 1570 +#define _SWAP_FAST_0_r22 1571 +#define _SWAP_FAST_0_r33 1572 +#define _SWAP_FAST_1_r01 1573 +#define _SWAP_FAST_1_r11 1574 +#define _SWAP_FAST_1_r22 1575 +#define _SWAP_FAST_1_r33 1576 +#define _SWAP_FAST_2_r01 1577 +#define _SWAP_FAST_2_r11 1578 +#define _SWAP_FAST_2_r22 1579 +#define _SWAP_FAST_2_r33 1580 +#define _SWAP_FAST_3_r01 1581 +#define _SWAP_FAST_3_r11 1582 +#define _SWAP_FAST_3_r22 1583 +#define _SWAP_FAST_3_r33 1584 +#define _SWAP_FAST_4_r01 1585 +#define _SWAP_FAST_4_r11 1586 +#define _SWAP_FAST_4_r22 1587 +#define _SWAP_FAST_4_r33 1588 +#define _SWAP_FAST_5_r01 1589 +#define _SWAP_FAST_5_r11 1590 +#define _SWAP_FAST_5_r22 1591 +#define _SWAP_FAST_5_r33 1592 +#define _SWAP_FAST_6_r01 1593 +#define _SWAP_FAST_6_r11 1594 +#define _SWAP_FAST_6_r22 1595 +#define _SWAP_FAST_6_r33 1596 +#define _SWAP_FAST_7_r01 1597 +#define _SWAP_FAST_7_r11 1598 +#define _SWAP_FAST_7_r22 1599 +#define _SWAP_FAST_7_r33 1600 +#define _TIER2_RESUME_CHECK_r00 1601 +#define _TIER2_RESUME_CHECK_r11 1602 +#define _TIER2_RESUME_CHECK_r22 1603 +#define _TIER2_RESUME_CHECK_r33 1604 +#define _TO_BOOL_r11 1605 +#define _TO_BOOL_BOOL_r01 1606 +#define _TO_BOOL_BOOL_r11 1607 +#define _TO_BOOL_BOOL_r22 1608 +#define _TO_BOOL_BOOL_r33 1609 +#define _TO_BOOL_INT_r02 1610 +#define _TO_BOOL_INT_r12 1611 +#define _TO_BOOL_INT_r23 1612 +#define _TO_BOOL_LIST_r02 1613 +#define _TO_BOOL_LIST_r12 1614 +#define _TO_BOOL_LIST_r23 1615 +#define _TO_BOOL_NONE_r01 1616 +#define _TO_BOOL_NONE_r11 1617 +#define _TO_BOOL_NONE_r22 1618 +#define _TO_BOOL_NONE_r33 1619 +#define _TO_BOOL_STR_r02 1620 +#define _TO_BOOL_STR_r12 1621 +#define _TO_BOOL_STR_r23 1622 +#define _TRACE_RECORD_r00 1623 +#define _UNARY_INVERT_r12 1624 +#define _UNARY_NEGATIVE_r12 1625 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r02 1626 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r12 1627 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r23 1628 +#define _UNARY_NOT_r01 1629 +#define _UNARY_NOT_r11 1630 +#define _UNARY_NOT_r22 1631 +#define _UNARY_NOT_r33 1632 +#define _UNPACK_EX_r10 1633 +#define _UNPACK_SEQUENCE_r10 1634 +#define _UNPACK_SEQUENCE_LIST_r10 1635 +#define _UNPACK_SEQUENCE_TUPLE_r10 1636 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1637 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1638 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1639 +#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1640 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1641 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1642 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1643 +#define _WITH_EXCEPT_START_r33 1644 +#define _YIELD_VALUE_r11 1645 +#define MAX_UOP_REGS_ID 1645 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index d4cceb5a500cab5..990706c0b329223 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -283,7 +283,6 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_SPECIAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_WITH_EXCEPT_START] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_PUSH_EXC_INFO] = 0, - [_GUARD_KEYS_VERSION] = HAS_EXIT_FLAG, [_LOAD_ATTR_METHOD_WITH_VALUES] = HAS_ARG_FLAG, [_LOAD_ATTR_METHOD_NO_DICT] = HAS_ARG_FLAG, [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, @@ -2677,15 +2676,6 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, - [_GUARD_KEYS_VERSION] = { - .best = { 0, 1, 2, 3 }, - .entries = { - { 1, 0, _GUARD_KEYS_VERSION_r01 }, - { 1, 1, _GUARD_KEYS_VERSION_r11 }, - { 2, 2, _GUARD_KEYS_VERSION_r22 }, - { 3, 3, _GUARD_KEYS_VERSION_r33 }, - }, - }, [_LOAD_ATTR_METHOD_WITH_VALUES] = { .best = { 0, 1, 2, 2 }, .entries = { @@ -4496,10 +4486,6 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_PUSH_EXC_INFO_r02] = _PUSH_EXC_INFO, [_PUSH_EXC_INFO_r12] = _PUSH_EXC_INFO, [_PUSH_EXC_INFO_r23] = _PUSH_EXC_INFO, - [_GUARD_KEYS_VERSION_r01] = _GUARD_KEYS_VERSION, - [_GUARD_KEYS_VERSION_r11] = _GUARD_KEYS_VERSION, - [_GUARD_KEYS_VERSION_r22] = _GUARD_KEYS_VERSION, - [_GUARD_KEYS_VERSION_r33] = _GUARD_KEYS_VERSION, [_LOAD_ATTR_METHOD_WITH_VALUES_r02] = _LOAD_ATTR_METHOD_WITH_VALUES, [_LOAD_ATTR_METHOD_WITH_VALUES_r12] = _LOAD_ATTR_METHOD_WITH_VALUES, [_LOAD_ATTR_METHOD_WITH_VALUES_r23] = _LOAD_ATTR_METHOD_WITH_VALUES, @@ -5415,11 +5401,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_GUARD_ITER_VIRTUAL_r11] = "_GUARD_ITER_VIRTUAL_r11", [_GUARD_ITER_VIRTUAL_r22] = "_GUARD_ITER_VIRTUAL_r22", [_GUARD_ITER_VIRTUAL_r33] = "_GUARD_ITER_VIRTUAL_r33", - [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION", - [_GUARD_KEYS_VERSION_r01] = "_GUARD_KEYS_VERSION_r01", - [_GUARD_KEYS_VERSION_r11] = "_GUARD_KEYS_VERSION_r11", - [_GUARD_KEYS_VERSION_r22] = "_GUARD_KEYS_VERSION_r22", - [_GUARD_KEYS_VERSION_r33] = "_GUARD_KEYS_VERSION_r33", [_GUARD_LOAD_SUPER_ATTR_METHOD] = "_GUARD_LOAD_SUPER_ATTR_METHOD", [_GUARD_LOAD_SUPER_ATTR_METHOD_r03] = "_GUARD_LOAD_SUPER_ATTR_METHOD_r03", [_GUARD_LOAD_SUPER_ATTR_METHOD_r13] = "_GUARD_LOAD_SUPER_ATTR_METHOD_r13", @@ -6662,8 +6643,6 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _PUSH_EXC_INFO: return 1; - case _GUARD_KEYS_VERSION: - return 0; case _LOAD_ATTR_METHOD_WITH_VALUES: return 1; case _LOAD_ATTR_METHOD_NO_DICT: diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 1255d842dbff48f..0c99bbc759e672a 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -2,7 +2,7 @@ import unittest from concurrent.futures import ThreadPoolExecutor -from threading import Thread +from threading import Barrier, Thread from unittest import TestCase from test.support import threading_helper @@ -160,6 +160,84 @@ def reader(): self.run_one(writer, reader) + def test_race_type_attr_added(self): + NROUNDS = 50 + NSTOPPERS = 4 + NWRITERS = 4 + WARM = 8 + KEY = "foo" + def make_reader(): + ns = {} + exec( + "def read(o):\n return o.%s\n" % KEY, ns + ) # fresh code object per round + return ns["read"] + + + stop_all = [False] + + + def stopper(): + class Dummy: + pass + + Dummy() + while not stop_all[0]: + try: + Dummy.__abstractmethods__ = frozenset() + except Exception: + pass + + + box = {} + bugs = [] # (round, tid, stored, read_back) + + def writer(tid): + for _ in range(NROUNDS): + box["start"].wait() + sentinel = box["sentinel"] + reader = box["reader"] + obj = box["objs"][tid] + val = box["vals"][tid] + # 1) warm THIS thread's own copy while KEY is absent -> NDV cached at V + for _ in range(WARM): + reader(obj) + box["race"].wait() + # 2) race: store, then read back through our own NDV site + setattr(obj, KEY, val) + got = reader(obj) + if got is sentinel: + bugs.append((box["round"], tid, val, got)) + box["end"].wait() + + box["start"] = Barrier(NWRITERS + 1) + box["race"] = Barrier(NWRITERS) + box["end"] = Barrier(NWRITERS + 1) + + stoppers = [Thread(target=stopper, daemon=True) for _ in range(NSTOPPERS)] + writers = [Thread(target=writer, args=(i,)) for i in range(NWRITERS)] + for t in stoppers + writers: + t.start() + + for r in range(NROUNDS): + sentinel = type( + "SENTINEL_%d" % r, (), {} + ) # non-descriptor, deferred refcount + C = type("C", (), {KEY: sentinel}) + box["round"] = r + box["sentinel"] = sentinel + box["reader"] = make_reader() + box["objs"] = [C() for _ in range(NWRITERS)] + box["vals"] = [["value-%d-%d" % (r, i)] for i in range(NWRITERS)] + box["start"].wait() + box["end"].wait() + + stop_all[0] = True + for t in writers: + t.join() + + self.assertFalse(bugs) + def run_one(self, writer_func, reader_func): barrier = threading.Barrier(NTHREADS) diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index ab80c422687bf2a..a17648a33d4fe4a 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -9166,18 +9166,7 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } - // _GUARD_KEYS_VERSION - { - uint32_t keys_version = read_u32(&this_instr[4].cache); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } + /* Skip 2 cache entries */ // _LOAD_ATTR_METHOD_WITH_VALUES { PyObject *descr = read_obj(&this_instr[6].cache); @@ -9362,18 +9351,7 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } - // _GUARD_KEYS_VERSION - { - uint32_t keys_version = read_u32(&this_instr[4].cache); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } + /* Skip 2 cache entries */ // _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES { PyObject *descr = read_obj(&this_instr[6].cache); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 6029205eac8b20f..246ffe6c18e9b51 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -799,16 +799,12 @@ _PyDict_CheckConsistency(PyObject *op, int check_content) } -static PyDictKeysObject* -new_keys_object(uint8_t log2_size, bool unicode) +static inline int +get_log2_bytes(uint8_t log2_size) { - Py_ssize_t usable; int log2_bytes; - size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry); - assert(log2_size >= PyDict_LOG_MINSIZE); - usable = USABLE_FRACTION((size_t)1<dk_refcnt = 1; dk->dk_log2_size = log2_size; dk->dk_log2_index_bytes = log2_bytes; - dk->dk_kind = unicode ? DICT_KEYS_UNICODE : DICT_KEYS_GENERAL; + dk->dk_kind = kind; #ifdef Py_GIL_DISABLED dk->dk_mutex = (PyMutex){0}; #endif @@ -852,15 +842,51 @@ new_keys_object(uint8_t log2_size, bool unicode) dk->dk_version = 0; memset(&dk->dk_indices[0], 0xff, ((size_t)1 << log2_bytes)); memset(&dk->dk_indices[(size_t)1 << log2_bytes], 0, entry_size * usable); +} + +static PyDictKeysObject* +new_keys_object(uint8_t log2_size, bool unicode) +{ + Py_ssize_t usable = USABLE_FRACTION((size_t)1<dk_kind == DICT_KEYS_SPLIT) { + ptr = _PyDictKeys_AsSharedKeys(keys); +#ifdef Py_GIL_DISABLED + size += offsetof(struct _instancekeysobject, dsk_keys); +#endif + } #ifdef Py_GIL_DISABLED if (use_qsbr) { - _PyMem_FreeDelayed(keys, _PyDict_KeysSize(keys)); + _PyMem_FreeDelayed(ptr, size); return; } #endif @@ -868,7 +894,7 @@ free_keys_object(PyDictKeysObject *keys, bool use_qsbr) _Py_FREELIST_FREE(dictkeys, keys, PyMem_Free); } else { - PyMem_Free(keys); + PyMem_Free(ptr); } } @@ -1925,6 +1951,12 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash) if (ix >= 0) { return ix; } + + // We need to acquire the type lock before the keys mutex. Another lock + // is never acquired below the keys mutex but a keys mutex can be acquired + // elsewhere while we hold the types lock. To avoid deadlocks we must always + // acquire the type lock first. + Py_BEGIN_CRITICAL_SECTION_MUTEX(&_PyInterpreterState_GET()->types.mutex); #endif LOCK_KEYS(keys); @@ -1932,6 +1964,12 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash) if (ix == DKIX_EMPTY && keys->dk_usable > 0) { // Insert into new slot FT_ATOMIC_STORE_UINT32_RELAXED(keys->dk_version, 0); + struct _instancekeysobject *shared_keys = _PyDictKeys_AsSharedKeys(keys); + PyTypeObject *type = FT_ATOMIC_LOAD_PTR_ACQUIRE(shared_keys->dsk_owning_type); + if (type) { + // we acquired the type lock above + _PyType_Modified_Unlocked(type); + } Py_ssize_t hashpos = find_empty_slot(keys, hash); ix = keys->dk_nentries; dictkeys_set_index(keys, hashpos, ix); @@ -1941,6 +1979,10 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash) } assert (ix < SHARED_KEYS_MAX_SIZE); UNLOCK_KEYS(keys); + +#ifdef Py_GIL_DISABLED + Py_END_CRITICAL_SECTION(); +#endif return ix; } @@ -7216,16 +7258,24 @@ dictvalues_reversed(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDictKeysObject * _PyDict_NewKeysForClass(PyHeapTypeObject *cls) { - PyDictKeysObject *keys = new_keys_object(NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1); - if (keys == NULL) { + int log2_bytes = get_log2_bytes(NEXT_LOG2_SHARED_KEYS_MAX_SIZE); + Py_ssize_t usable = USABLE_FRACTION((size_t)1<dk_nentries == 0); - /* Set to max size+1 as it will shrink by one before each new object */ - keys->dk_usable = SHARED_KEYS_MAX_SIZE; - keys->dk_kind = DICT_KEYS_SPLIT; - } + + shared_keys->dsk_owning_type = (PyTypeObject *)cls; + PyDictKeysObject* keys = &shared_keys->dsk_keys; + init_keys_object(keys, NEXT_LOG2_SHARED_KEYS_MAX_SIZE, log2_bytes, DICT_KEYS_SPLIT, + SHARED_KEYS_MAX_SIZE, sizeof(PyDictUnicodeEntry)); + assert(keys->dk_nentries == 0); + /* Set to max size+1 as it will shrink by one before each new object */ if (cls->ht_type.tp_dict) { PyObject *attrs = PyDict_GetItem(cls->ht_type.tp_dict, &_Py_ID(__static_attributes__)); if (attrs != NULL && PyTuple_Check(attrs)) { @@ -7243,6 +7293,15 @@ _PyDict_NewKeysForClass(PyHeapTypeObject *cls) return keys; } +void +_PyDict_RemoveKeysForClass(PyHeapTypeObject *cls) +{ + struct _instancekeysobject *shared_keys = _PyDictKeys_AsSharedKeys(cls->ht_cached_keys); + FT_ATOMIC_STORE_PTR_RELEASE(shared_keys->dsk_owning_type, NULL); + + _PyDictKeys_DecRef(cls->ht_cached_keys); +} + void _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d52cdedff10f96b..b77f3e3bce54551 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1162,8 +1162,8 @@ set_version_unlocked(PyTypeObject *tp, unsigned int version) #endif } -static void -type_modified_unlocked(PyTypeObject *type) +void +_PyType_Modified_Unlocked(PyTypeObject *type) { /* Invalidate any cached data for the specified type and all subclasses. This function is called after the base @@ -1203,7 +1203,7 @@ type_modified_unlocked(PyTypeObject *type) if (subclass == NULL) { continue; } - type_modified_unlocked(subclass); + _PyType_Modified_Unlocked(subclass); Py_DECREF(subclass); } } @@ -1248,7 +1248,7 @@ PyType_Modified(PyTypeObject *type) } BEGIN_TYPE_LOCK(); - type_modified_unlocked(type); + _PyType_Modified_Unlocked(type); END_TYPE_LOCK(); } @@ -1741,7 +1741,7 @@ type_set_abstractmethods(PyObject *tp, PyObject *value, void *Py_UNUSED(closure) } BEGIN_TYPE_LOCK(); - type_modified_unlocked(type); + _PyType_Modified_Unlocked(type); types_stop_world(); if (abstract) type_add_flags(type, Py_TPFLAGS_IS_ABSTRACT); @@ -1968,7 +1968,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b goto bail; } /* Clear the VALID_VERSION flag of 'type' and all its subclasses. */ - type_modified_unlocked(type); + _PyType_Modified_Unlocked(type); } else { res = 0; @@ -3684,7 +3684,7 @@ mro_internal(PyTypeObject *type, int initial, PyObject **p_old_mro) // XXX Expand this to Py_TPFLAGS_IMMUTABLETYPE? if (!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)) { - type_modified_unlocked(type); + _PyType_Modified_Unlocked(type); } else { /* For static builtin types, this is only called during init @@ -6500,14 +6500,14 @@ _PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long { BEGIN_TYPE_LOCK(); /* Ideally, changing flags and invalidating the old version tag would - happen in one step. But type_modified_unlocked() is re-entrant and + happen in one step. But _PyType_Modified_Unlocked() is re-entrant and cannot run with the world stopped, so we must invalidate first. Immutable/static-builtin types are skipped because set_flags_recursive() does not modify them. */ if (!PyType_HasFeature(self, Py_TPFLAGS_IMMUTABLETYPE) && (self->tp_flags & mask) != flags) { - type_modified_unlocked(self); + _PyType_Modified_Unlocked(self); } /* Keep TYPE_LOCK held while waiting for stop-the-world so no thread can reassign a version tag before the flag update. */ @@ -6688,7 +6688,7 @@ type_update_dict(PyTypeObject *type, PyDictObject *dict, PyObject *name, PyObject *value, PyObject **old_value) { // We don't want any re-entrancy between when we update the dict - // and call type_modified_unlocked, including running the destructor + // and call _PyType_Modified_Unlocked, including running the destructor // of the current value as it can observe the cache in an inconsistent // state. Because we have an exact unicode and our dict has exact // unicodes we know that this will all complete without releasing @@ -6702,7 +6702,7 @@ type_update_dict(PyTypeObject *type, PyDictObject *dict, PyObject *name, update_subclasses() recursion in update_slot(), but carefully: they each have their own conditions on which to stop recursing into subclasses. */ - type_modified_unlocked(type); + _PyType_Modified_Unlocked(type); if (_PyDict_SetItem_LockHeld(dict, name, value) < 0) { PyErr_Format(PyExc_AttributeError, @@ -7026,7 +7026,7 @@ type_dealloc(PyObject *self) Py_XDECREF(et->ht_qualname); Py_XDECREF(et->ht_slots); if (et->ht_cached_keys) { - _PyDictKeys_DecRef(et->ht_cached_keys); + _PyDict_RemoveKeysForClass(et); } Py_XDECREF(et->ht_module); PyMem_Free(et->_ht_tpname); @@ -12517,7 +12517,7 @@ PyType_Freeze(PyTypeObject *type) type_add_flags(type, Py_TPFLAGS_IMMUTABLETYPE); types_start_world(); ASSERT_TYPE_LOCK_HELD(); - type_modified_unlocked(type); + _PyType_Modified_Unlocked(type); END_TYPE_LOCK(); return 0; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 689feeb0a1e0700..4d7b338e2dbd4c3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4231,13 +4231,6 @@ dummy_func( DEAD(exc); } - op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) { - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - EXIT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version); - } - op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) { assert(oparg & 1); /* Cached method object */ @@ -4254,7 +4247,7 @@ dummy_func( _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _CHECK_MANAGED_OBJECT_HAS_VALUES + - _GUARD_KEYS_VERSION + + unused/2 + _LOAD_ATTR_METHOD_WITH_VALUES; op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self)) { @@ -4288,7 +4281,7 @@ dummy_func( _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _CHECK_MANAGED_OBJECT_HAS_VALUES + - _GUARD_KEYS_VERSION + + unused/2 + _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index a012f14f7fbebe2..e45bbd7cceb295f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -16306,103 +16306,6 @@ break; } - case _GUARD_KEYS_VERSION_r01: { - CHECK_CURRENT_CACHED_VALUES(0); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - _PyStackRef owner; - owner = stack_pointer[-1]; - uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UOP_STAT_INC(uopcode, miss); - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_JUMP_TARGET(); - } - _tos_cache0 = owner; - SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - break; - } - - case _GUARD_KEYS_VERSION_r11: { - CHECK_CURRENT_CACHED_VALUES(1); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - _PyStackRef owner; - _PyStackRef _stack_item_0 = _tos_cache0; - owner = _stack_item_0; - uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UOP_STAT_INC(uopcode, miss); - _tos_cache0 = owner; - SET_CURRENT_CACHED_VALUES(1); - JUMP_TO_JUMP_TARGET(); - } - _tos_cache0 = owner; - SET_CURRENT_CACHED_VALUES(1); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - break; - } - - case _GUARD_KEYS_VERSION_r22: { - CHECK_CURRENT_CACHED_VALUES(2); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - _PyStackRef owner; - _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; - owner = _stack_item_1; - uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UOP_STAT_INC(uopcode, miss); - _tos_cache1 = owner; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(2); - JUMP_TO_JUMP_TARGET(); - } - _tos_cache1 = owner; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(2); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - break; - } - - case _GUARD_KEYS_VERSION_r33: { - CHECK_CURRENT_CACHED_VALUES(3); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - _PyStackRef owner; - _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; - _PyStackRef _stack_item_2 = _tos_cache2; - owner = _stack_item_2; - uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UOP_STAT_INC(uopcode, miss); - _tos_cache2 = owner; - _tos_cache1 = _stack_item_1; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(3); - JUMP_TO_JUMP_TARGET(); - } - _tos_cache2 = owner; - _tos_cache1 = _stack_item_1; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(3); - ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); - break; - } - case _LOAD_ATTR_METHOD_WITH_VALUES_r02: { CHECK_CURRENT_CACHED_VALUES(0); ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b72116d367634d8..6178dc70c1b80e7 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -9165,18 +9165,7 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } - // _GUARD_KEYS_VERSION - { - uint32_t keys_version = read_u32(&this_instr[4].cache); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } + /* Skip 2 cache entries */ // _LOAD_ATTR_METHOD_WITH_VALUES { PyObject *descr = read_obj(&this_instr[6].cache); @@ -9361,18 +9350,7 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } - // _GUARD_KEYS_VERSION - { - uint32_t keys_version = read_u32(&this_instr[4].cache); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; - if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } + /* Skip 2 cache entries */ // _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES { PyObject *descr = read_obj(&this_instr[6].cache); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 3ad23c3a74f7087..5e110360b81b445 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3922,10 +3922,6 @@ break; } - case _GUARD_KEYS_VERSION: { - break; - } - case _LOAD_ATTR_METHOD_WITH_VALUES: { JitOptRef owner; JitOptRef attr; diff --git a/Python/specialize.c b/Python/specialize.c index 6aaae6f383d22f5..773b55c329c7720 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -980,12 +980,15 @@ static int specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name) { // 0 is not a valid version - uint32_t shared_keys_version = 0; - bool shadow = instance_has_key(owner, name, &shared_keys_version); PyObject *descr = NULL; unsigned int tp_version = 0; PyTypeObject *type = Py_TYPE(owner); + // Read the type version before the keys version, we could have a concurrent + // modification of the split keys in which case we update the keys version and + // then the type version, this ensures we will still deopt if that happens. DescriptorClassification kind = analyze_descriptor_load(type, name, &descr, &tp_version); + uint32_t shared_keys_version = 0; + bool shadow = instance_has_key(owner, name, &shared_keys_version); int result = do_specialize_instance_load_attr(owner, instr, name, shadow, shared_keys_version, kind, descr, tp_version); Py_XDECREF(descr); return result; @@ -1286,7 +1289,6 @@ specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); return 0; } - write_u32(cache->keys_version, shared_keys_version); specialize(instr, is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); } else { From 6efa411ba84a2d1c257be5fb4dea3c672a9f7e03 Mon Sep 17 00:00:00 2001 From: metsw24-max Date: Tue, 7 Jul 2026 01:46:43 +0530 Subject: [PATCH 54/61] gh-150479: reject CR and LF in email.utils.formataddr (#150480) --- Doc/library/email.utils.rst | 9 +++++++- Lib/email/utils.py | 9 +++++++- Lib/test/test_email/test_email.py | 22 +++++++++++++++++++ ...-05-26-19-30-00.gh-issue-150479.Kq7Lm2.rst | 4 ++++ 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-26-19-30-00.gh-issue-150479.Kq7Lm2.rst diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index e0d2c19a3b0737a..0a96dbfd196a051 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -70,7 +70,7 @@ of the new API. Add *strict* optional parameter and reject malformed inputs by default. -.. function:: formataddr(pair, charset='utf-8') +.. function:: formataddr(pair, charset='utf-8', *, strict=True) The inverse of :meth:`parseaddr`, this takes a 2-tuple of the form ``(realname, email_address)`` and returns the string value suitable for a :mailheader:`To` or @@ -82,9 +82,16 @@ of the new API. characters. Can be an instance of :class:`str` or a :class:`~email.charset.Charset`. Defaults to ``utf-8``. + If *strict* is true (the default), raise :exc:`ValueError` for inputs that + contain CR or LF, which are not allowed in an email address. Set *strict* + to ``False`` to allow non-strict inputs. + .. versionchanged:: 3.3 Added the *charset* option. + .. versionchanged:: next + Added the *strict* parameter. + .. function:: getaddresses(fieldvalues, *, strict=True) diff --git a/Lib/email/utils.py b/Lib/email/utils.py index d4824dc3601b2dd..7aefc24c15dc767 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -69,7 +69,7 @@ def _sanitize(string): # Helpers -def formataddr(pair, charset='utf-8'): +def formataddr(pair, charset='utf-8', *, strict=True): """The inverse of parseaddr(), this takes a 2-tuple of the form (realname, email_address) and returns the string value suitable for an RFC 2822 From, To or Cc header. @@ -81,8 +81,15 @@ def formataddr(pair, charset='utf-8'): realname in case realname is not ASCII safe. Can be an instance of str or a Charset-like object which has a header_encode method. Default is 'utf-8'. + + If strict is True (the default), raise ValueError for inputs that + contain CR or LF, which are not allowed in an email address. """ name, address = pair + if strict and ('\r' in address or '\n' in address + or (name and ('\r' in name or '\n' in name))): + raise ValueError( + "invalid arguments; address parts cannot contain CR or LF") # The address MUST (per RFC) be ascii, so raise a UnicodeError if it isn't. address.encode('ascii') if name: diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 19555d87085e176..e40c82bba9af426 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3277,6 +3277,28 @@ def test_unicode_address_raises_error(self): self.assertRaises(UnicodeError, utils.formataddr, (None, addr)) self.assertRaises(UnicodeError, utils.formataddr, ("Name", addr)) + def test_crlf_in_parts_raises_error(self): + # formataddr() must reject CR and LF in either part so that the + # returned header value cannot be used to inject extra headers, + # matching email.headerregistry.Address. + for name, addr in [ + ('Real\rName', 'person@dom.ain'), + ('Real\nName', 'person@dom.ain'), + ('Real Name', 'person@dom.ain\r\nBcc: victim@dom.ain'), + ('Real Name', 'person@dom.ain\nSubject: spoofed'), + ]: + with self.subTest(name=name, addr=addr): + self.assertRaises(ValueError, utils.formataddr, (name, addr)) + + def test_crlf_in_parts_allowed_when_not_strict(self): + # strict=False keeps the old behaviour and passes CR/LF through. + self.assertEqual( + utils.formataddr(('Real\rName', 'person@dom.ain'), strict=False), + 'Real\rName ') + self.assertEqual( + utils.formataddr(('Real Name', 'person@dom.ain\nfoo'), strict=False), + 'Real Name ') + def test_name_with_dot(self): x = 'John X. Doe ' y = '"John X. Doe" ' diff --git a/Misc/NEWS.d/next/Library/2026-05-26-19-30-00.gh-issue-150479.Kq7Lm2.rst b/Misc/NEWS.d/next/Library/2026-05-26-19-30-00.gh-issue-150479.Kq7Lm2.rst new file mode 100644 index 000000000000000..5a41273f3501e39 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-26-19-30-00.gh-issue-150479.Kq7Lm2.rst @@ -0,0 +1,4 @@ +:func:`email.utils.formataddr` now raises :exc:`ValueError` when the name or +address contains a carriage return or line feed, matching +:class:`email.headerregistry.Address`. This check can be disabled by passing +``strict=False``. From 7eb60bd1b13f854f952c9bfb73eb4fa637761cef Mon Sep 17 00:00:00 2001 From: An Long Date: Tue, 7 Jul 2026 08:36:26 +0900 Subject: [PATCH 55/61] gh-153068: Preserve cprofile enable errors (#153070) --- Lib/test/test_profiling/test_tracing_profiler.py | 5 +++-- .../Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst | 2 ++ Modules/_lsprof.c | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst diff --git a/Lib/test/test_profiling/test_tracing_profiler.py b/Lib/test/test_profiling/test_tracing_profiler.py index 3668e24e073ce4d..e9f55613b6cfbb8 100644 --- a/Lib/test/test_profiling/test_tracing_profiler.py +++ b/Lib/test/test_profiling/test_tracing_profiler.py @@ -118,8 +118,9 @@ def test_second_profiler(self): pr = self.profilerclass() pr2 = self.profilerclass() pr.enable() - self.assertRaises(ValueError, pr2.enable) - pr.disable() + self.addCleanup(pr.disable) + msg = f"tool {sys.monitoring.PROFILER_ID} is already in use" + self.assertRaisesRegex(ValueError, msg, pr2.enable) def test_throw(self): """ diff --git a/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst b/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst new file mode 100644 index 000000000000000..accf6e99cd6434d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-05-16-09-31.gh-issue-153068.huY9Jh.rst @@ -0,0 +1,2 @@ +Fix :meth:`!cProfile.Profile.enable` to no longer overwrite errors from +:mod:`sys.monitoring`. diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 3d341a336ab22e6..4e50ca64f59af22 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -821,7 +821,6 @@ _lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, "use_tool_id", "is", self->tool_id, "cProfile"); if (check == NULL) { - PyErr_Format(PyExc_ValueError, "Another profiling tool is already active"); goto error; } Py_DECREF(check); From eba35f97808ed1197112e72eb0d900d7067048e5 Mon Sep 17 00:00:00 2001 From: Duprat Date: Tue, 7 Jul 2026 01:39:06 +0200 Subject: [PATCH 56/61] gh-140729: Fix the cProfile module when the executed script contains calls to multiprocessing.Process (#144715) Co-authored-by: Pablo Galindo Salgado --- Lib/profiling/tracing/__init__.py | 4 ++- .../test_profiling/test_tracing_profiler.py | 35 ++++++++++++++++++- ...-02-11-16-47-27.gh-issue-140729.2uTPQp.rst | 3 ++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index bd3cbf299aab3b9..165665304e05a40 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -197,7 +197,9 @@ def main(): # in the module's namespace. globs = module.__dict__ globs.update({ - '__spec__': spec, + # Set __spec__ to None so the profiled program behaves like a + # script run directly (gh-140729). + '__spec__': None, '__file__': spec.origin, '__name__': spec.name, '__package__': None, diff --git a/Lib/test/test_profiling/test_tracing_profiler.py b/Lib/test/test_profiling/test_tracing_profiler.py index e9f55613b6cfbb8..8a7070142b60eec 100644 --- a/Lib/test/test_profiling/test_tracing_profiler.py +++ b/Lib/test/test_profiling/test_tracing_profiler.py @@ -1,5 +1,4 @@ """Test suite for the cProfile module.""" - import sys import unittest @@ -193,6 +192,40 @@ class Foo: f.close() assert_python_ok('-m', "cProfile", f.name) + def _test_process_run_pickle(self, start_method): + val = 10 + with tempfile.NamedTemporaryFile("w+", delete_on_close=False) as f: + f.write(textwrap.dedent( + f'''\ + import multiprocessing + + def worker(x): + print(__name__) + exit(x ** 2) + + if __name__ == "__main__": + multiprocessing.set_start_method('{start_method}') + p = multiprocessing.Process(target=worker, args=({val},)) + p.start() + p.join() + print("p.exitcode =", p.exitcode) + ''')) + f.close() + _, out, err = assert_python_ok('-m', "cProfile", f.name) + self.assertIn(b"__mp_main__", out) + self.assertIn(bytes(f"exitcode = {val**2}", encoding='utf8'), out) + self.assertNotIn(b"Can't pickle", err) + + def test_process_spawn_pickle(self): + # gh-140729: test use Process in cProfile. + self._test_process_run_pickle('spawn') + + @unittest.skipIf(sys.platform == 'win32', + "No 'forkserver' start method on Windows") + def test_process_forkserver_pickle(self): + # gh-140729: test use Process in cProfile. + self._test_process_run_pickle('forkserver') + def main(): if '-r' not in sys.argv: diff --git a/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst new file mode 100644 index 000000000000000..49c9adc4679abbf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst @@ -0,0 +1,3 @@ +Fix a pickling error in the ``cProfile`` module when profiling a script that +uses :class:`multiprocessing.Process` with the ``spawn`` and ``forkserver`` +start methods. From f77a7d53dc5b99c7545b5fc225d48ad54211b7b2 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Mon, 6 Jul 2026 16:54:16 -0700 Subject: [PATCH 57/61] gh-145177: Update Emscripten to 6.0.2 (#153235) Removes the patched `getentropy()` call since it has been included upstream. --- Platforms/emscripten/config.toml | 2 +- Python/emscripten_syscalls.c | 20 -------------------- configure | 2 -- configure.ac | 4 ---- 4 files changed, 1 insertion(+), 27 deletions(-) diff --git a/Platforms/emscripten/config.toml b/Platforms/emscripten/config.toml index 389d2ea66ce948e..0c65a6623c9798a 100644 --- a/Platforms/emscripten/config.toml +++ b/Platforms/emscripten/config.toml @@ -1,7 +1,7 @@ # Any data that can vary between Python versions is to be kept in this file. # This allows for blanket copying of the Emscripten build code between supported # Python versions. -emscripten-version = "6.0.0" +emscripten-version = "6.0.2" node-version = "24" test-args = [ "-m", "test", diff --git a/Python/emscripten_syscalls.c b/Python/emscripten_syscalls.c index b0c370ced36cc33..48ca208dedb14bb 100644 --- a/Python/emscripten_syscalls.c +++ b/Python/emscripten_syscalls.c @@ -293,26 +293,6 @@ int __syscall_poll(intptr_t fds, int nfds, int timeout) { return __block_for_int(p); } - -// Workaround for an Emscripten bug: getentropy(buffer, 1) returns the single -// byte of entropy as the return code. Fixed upstream by -// emscripten-core/emscripten#27122 -int __real_getentropy(void*, size_t); - -int __wrap_getentropy(void *buffer, size_t len) { - if (len != 1) { - return __real_getentropy(buffer, len); - } - // Length is 1. Workaround is to get two bytes of entropy and write the - // first one into the original target buffer. - uint8_t tmp[2]; - int ret = __real_getentropy(tmp, 2); - if (ret == 0) { - *(uint8_t *)buffer = tmp[0]; - } - return ret; -} - #include int syscall_ioctl_orig(int fd, int request, void* varargs) diff --git a/configure b/configure index 01faef615a3d5e1..76c58f7c3a463db 100755 --- a/configure +++ b/configure @@ -9803,8 +9803,6 @@ fi as_fn_append LINKFORSHARED " -sSTACK_SIZE=5MB" as_fn_append LINKFORSHARED " -sTEXTDECODER=2" - as_fn_append LDFLAGS_NODIST " -Wl,--wrap=getentropy" - if test "x$enable_wasm_dynamic_linking" = xyes then : diff --git a/configure.ac b/configure.ac index a9fe5c269618fcd..de7a3abb379e659 100644 --- a/configure.ac +++ b/configure.ac @@ -2411,10 +2411,6 @@ AS_CASE([$ac_sys_system], dnl Avoid bugs in JS fallback string decoding path AS_VAR_APPEND([LINKFORSHARED], [" -sTEXTDECODER=2"]) - dnl Workaround for a bug in Emscipten libc's getentropy. See - dnl __wrap_getentropy in Python/emscripten_syscalls.c. - AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--wrap=getentropy"]) - AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [ AS_VAR_APPEND([LINKFORSHARED], [" -sMAIN_MODULE"]) ]) From ad42bd691f9e2efc27396991d3c81b681da3fb9d Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 7 Jul 2026 11:25:30 +0300 Subject: [PATCH 58/61] gh-153210: Fix `array` module import crash under a memory pressure (#153238) --- Lib/test/test_array.py | 19 ++++++++++++++++++- ...-07-07-02-26-43.gh-issue-153210.LUXIcm.rst | 1 + Modules/arraymodule.c | 7 ------- 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 23d9f3c9667d868..27bd63bde08eb8b 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -5,7 +5,7 @@ import collections.abc import unittest from test import support -from test.support import import_helper +from test.support import import_helper, script_helper from test.support import os_helper from test.support import _2G from test.support import subTests @@ -42,6 +42,23 @@ def test_bad_constructor(self): self.assertRaises(ValueError, array.array, 'x') self.assertRaises(ValueError, array.array, 'Z') + @support.cpython_only + def test_does_not_crash_on_broken_imports(self): + # gh-153210 + code = """if 1: + import collections.abc + + del collections.abc.MutableSequence + + try: + import array # it used to crash before + except AttributeError: + pass + else: + raise AssertionError('AttributeError was not raised') + """ + script_helper.assert_python_ok('-c', code) + @support.cpython_only def test_disallow_instantiation(self): my_array = array.array("I") diff --git a/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst b/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst new file mode 100644 index 000000000000000..d5d4b7c1b8c0ed4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-07-02-26-43.gh-issue-153210.LUXIcm.rst @@ -0,0 +1 @@ +Fix crash on :mod:`array` import under a memory pressure. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 9f613927be63159..45aad5d6fe21918 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -3401,22 +3401,15 @@ array_modexec(PyObject *m) CREATE_TYPE(m, state->ArrayIterType, &arrayiter_spec); Py_SET_TYPE(state->ArrayIterType, &PyType_Type); - if (PyModule_AddObjectRef(m, "ArrayType", - (PyObject *)state->ArrayType) < 0) { - return -1; - } - PyObject *mutablesequence = PyImport_ImportModuleAttrString( "collections.abc", "MutableSequence"); if (!mutablesequence) { - Py_DECREF((PyObject *)state->ArrayType); return -1; } PyObject *res = PyObject_CallMethod(mutablesequence, "register", "O", (PyObject *)state->ArrayType); Py_DECREF(mutablesequence); if (!res) { - Py_DECREF((PyObject *)state->ArrayType); return -1; } Py_DECREF(res); From 9964dc3dfdcf6050387673804495b26275a820a2 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 7 Jul 2026 05:08:34 -0400 Subject: [PATCH 59/61] gh-153227: Use a development version of Pygments (#153228) --- Doc/pylock.toml | 34 +++++++++++++++++----------------- Doc/requirements.txt | 4 ++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Doc/pylock.toml b/Doc/pylock.toml index 154eee301ec9749..64a051c2399b0af 100644 --- a/Doc/pylock.toml +++ b/Doc/pylock.toml @@ -2,6 +2,7 @@ # uv pip compile Doc/requirements.txt --exclude-newer P14D --exclude-newer-package linklint=PT0S --exclude-newer-package python-docs-theme=PT0S --no-cache --output-file Doc/pylock.toml --python-version 3.12 --universal lock-version = "1.0" created-by = "uv" +requires-python = ">=3.12" [[packages]] name = "alabaster" @@ -23,9 +24,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/b4/03/374bd9e31b58e8a [[packages]] name = "certifi" -version = "2026.4.22" -sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", upload-time = 2026-04-22T11:26:11Z, size = 137077, hashes = { sha256 = "8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", upload-time = 2026-04-22T11:26:09Z, size = 135707, hashes = { sha256 = "3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a" } }] +version = "2026.6.17" +sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", upload-time = 2026-06-17T10:31:07Z, size = 134594, hashes = { sha256 = "024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", upload-time = 2026-06-17T10:31:06Z, size = 133289, hashes = { sha256 = "2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db" } }] [[packages]] name = "charset-normalizer" @@ -114,9 +115,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929 [[packages]] name = "idna" -version = "3.13" -sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", upload-time = 2026-04-22T16:42:42Z, size = 194210, hashes = { sha256 = "585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", upload-time = 2026-04-22T16:42:40Z, size = 68629, hashes = { sha256 = "892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3" } }] +version = "3.18" +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", upload-time = 2026-06-02T14:34:07Z, size = 196711, hashes = { sha256 = "ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", upload-time = 2026-06-02T14:34:06Z, size = 65455, hashes = { sha256 = "7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2" } }] [[packages]] name = "imagesize" @@ -132,9 +133,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f [[packages]] name = "linklint" -version = "1.0.0" -sdist = { url = "https://files.pythonhosted.org/packages/f3/59/a2bb261b3fc0e3bfdc9d3e6f8a37bdf1fb6eca8d992f23f55a83bf19acb1/linklint-1.0.0.tar.gz", upload-time = 2026-05-02T11:39:39Z, size = 21310, hashes = { sha256 = "52dc292f27b7eb4f3825d23ec1222d4a17bd116945b77c486406d97bb936e6c2" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/7b/78/98e52e4262416060a0eedc2e5514035cfcfc2fd962d09b84e27848c1aef3/linklint-1.0.0-py3-none-any.whl", upload-time = 2026-05-02T11:39:37Z, size = 12521, hashes = { sha256 = "bbb3f589ab65709cf23655ef6097bdc25180f80c0d42a4d9a1714366d2d3edab" } }] +version = "1.0.1" +sdist = { url = "https://files.pythonhosted.org/packages/62/22/c65a97b2192c3c317c472058bf52d7ca88e421998fa8d5c183b2280ab5d4/linklint-1.0.1.tar.gz", upload-time = 2026-06-09T12:30:47Z, size = 22412, hashes = { sha256 = "10201b4366edecfbeb3281883aff857dbe77d40bb56f16f212d372f597342d5f" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/7b/d8/b2f1708f55f4dd5358b48d28be07ff8e0dadd6d23e41ead2ed1424e90256/linklint-1.0.1-py3-none-any.whl", upload-time = 2026-06-09T12:30:46Z, size = 12828, hashes = { sha256 = "c931f110482f1d17808aa2df78b116adc44d7a14e9e79922c57bf9a7cba40a2d" } }] [[packages]] name = "markupsafe" @@ -162,8 +163,7 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c [[packages]] name = "pygments" version = "2.20.0" -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", upload-time = 2026-03-29T13:29:33Z, size = 4955991, hashes = { sha256 = "6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", upload-time = 2026-03-29T13:29:30Z, size = 1231151, hashes = { sha256 = "81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176" } }] +archive = { url = "https://github.com/pygments/pygments/archive/2cad2642058441b59782a6a18f03c98c42d081f1.tar.gz", hashes = { sha256 = "e6ae46831285e86355eabb969bf2d0520655b001dd882147637f4bc500e56bfb" } } [[packages]] name = "python-docs-theme" @@ -173,9 +173,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/db/05/b9298eb9330c70a [[packages]] name = "requests" -version = "2.33.1" -sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", upload-time = 2026-03-30T16:09:15Z, size = 134120, hashes = { sha256 = "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", upload-time = 2026-03-30T16:09:13Z, size = 64947, hashes = { sha256 = "4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a" } }] +version = "2.34.2" +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", upload-time = 2026-05-14T19:25:27Z, size = 142856, hashes = { sha256 = "f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", upload-time = 2026-05-14T19:25:26Z, size = 73075, hashes = { sha256 = "2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0" } }] [[packages]] name = "roman-numerals" @@ -251,6 +251,6 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/bf/a4/66c1fd4f8fab88f [[packages]] name = "urllib3" -version = "2.6.3" -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", upload-time = 2026-01-07T16:24:43Z, size = 435556, hashes = { sha256 = "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", upload-time = 2026-01-07T16:24:42Z, size = 131584, hashes = { sha256 = "bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" } }] +version = "2.7.0" +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", upload-time = 2026-05-07T16:13:18Z, size = 433602, hashes = { sha256 = "231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", upload-time = 2026-05-07T16:13:17Z, size = 131087, hashes = { sha256 = "9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897" } }] diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 536ae57e4efc298..c5cd360ff317521 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -9,6 +9,10 @@ # Keep this version in sync with ``Doc/conf.py``. sphinx<9.0.0 +# Temporary direct requirement, pending release of Pygments > 2.20.0 +# https://github.com/pygments/pygments/discussions/3145 +pygments @ https://github.com/pygments/pygments/archive/2cad2642058441b59782a6a18f03c98c42d081f1.tar.gz + blurb sphinxext-opengraph~=0.13.0 From e2de1a28878a864865313b44f3630a479b927122 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 7 Jul 2026 12:37:04 +0300 Subject: [PATCH 60/61] gh-143990: Allow tkinter.font.Font to wrap a font description (GH-152025) With exists=True and no name, Font now wraps the font description as is, without creating a new named font, so that it is used without loss of precision by actual(), measure() and metrics(). Its name attribute is then the description rather than a string. Keyword options now override the corresponding settings of the given font instead of being ignored. Co-Authored-By: Claude Opus 4.8 --- Doc/library/tkinter.font.rst | 70 +++++++++++----- Doc/whatsnew/3.16.rst | 6 ++ Lib/test/test_tkinter/test_font.py | 82 ++++++++++++++++++- Lib/tkinter/font.py | 63 +++++++++----- ...-06-23-18-42-37.gh-issue-143990.o65v7O.rst | 6 ++ 5 files changed, 180 insertions(+), 47 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-23-18-42-37.gh-issue-143990.o65v7O.rst diff --git a/Doc/library/tkinter.font.rst b/Doc/library/tkinter.font.rst index 2a9563fffab1f71..1ac7ac8e98d1662 100644 --- a/Doc/library/tkinter.font.rst +++ b/Doc/library/tkinter.font.rst @@ -20,33 +20,53 @@ The different font weights and slants are: .. class:: Font(root=None, font=None, name=None, exists=False, **options) - The :class:`Font` class represents a named font. *Font* instances are given - unique names and can be specified by their family, size, and style - configuration. Named fonts are Tk's method of creating and identifying - fonts as a single object, rather than specifying a font by its attributes - with each occurrence. + The :class:`Font` class represents a font used by Tk widgets. + It either creates a new *named font* or refers to an existing font. + A named font is Tk's way of identifying a font as a single object that can + be referred to by name and reconfigured in place, + rather than respecifying its attributes at each use. + + With *exists* false (the default), a new named font is created. + Its attributes are taken from the font description *font* if it is given, + overridden by any keyword *options*. + The new font is named *name*, or a generated unique name if *name* is + omitted. + + With *exists* true, an existing font is referred to instead of being + created. + If *name* is given, it is the name of the font, + which is reconfigured by *font* and *options* if either is given. + If *name* is omitted, the font description *font* is wrapped as is, + without creating a named font, + so that it is used without loss of precision by :meth:`actual`, + :meth:`measure` and :meth:`metrics`. + In this case no keyword options are accepted, + and the :attr:`!name` attribute is the description itself rather than a + string. + + The font description *font* is a tuple of the family name, the size and + zero or more styles, + or any other form accepted by Tk, such as the name of a named font. + + The keyword *options* are: + + | *family* - font family, for example, Courier, Times + | *size* - font size + | If *size* is positive it is interpreted as size in points. + | If *size* is a negative number its absolute value is treated + | as size in pixels. + | *weight* - font emphasis (NORMAL, BOLD) + | *slant* - ROMAN, ITALIC + | *underline* - font underlining (0 - none, 1 - underline) + | *overstrike* - font strikeout (0 - none, 1 - strikeout) .. versionchanged:: 3.10 Two fonts now compare equal (``==``) only when both are :class:`Font` instances with the same name belonging to the same Tcl interpreter. - arguments: - - | *font* - font specifier tuple (family, size, options) - | *name* - unique font name - | *exists* - self points to existing named font if true - - additional keyword options (ignored if *font* is specified): - - | *family* - font family, for example, Courier, Times - | *size* - font size - | If *size* is positive it is interpreted as size in points. - | If *size* is a negative number its absolute value is treated - | as size in pixels. - | *weight* - font emphasis (NORMAL, BOLD) - | *slant* - ROMAN, ITALIC - | *underline* - font underlining (0 - none, 1 - underline) - | *overstrike* - font strikeout (0 - none, 1 - strikeout) + .. versionchanged:: next + A font description can now be wrapped without creating a new named font, + and keyword options now override the attributes of the specified *font*. .. method:: actual(option=None, displayof=None) @@ -59,6 +79,12 @@ The different font weights and slants are: Retrieve an attribute of the font. + .. note:: + + :meth:`!cget` and :meth:`configure` operate on a named font and raise + :exc:`~tkinter.TclError` for a wrapped font description. + Use :meth:`actual` to query the attributes of the latter. + .. method:: config(**options) :no-typesetting: diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index e8c75d2f571061a..dd2c7b68d039921 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -408,6 +408,12 @@ tkinter them. (Contributed by Serhiy Storchaka in :gh:`59396`.) +* :class:`tkinter.font.Font` can now wrap a font description without creating a + new named font, by passing it as *font* with ``exists=True`` and no *name*. + This avoids a loss of precision in :meth:`~tkinter.font.Font.actual`, + :meth:`~tkinter.font.Font.measure` and :meth:`~tkinter.font.Font.metrics`. + (Contributed by Serhiy Storchaka in :gh:`143990`.) + xml --- diff --git a/Lib/test/test_tkinter/test_font.py b/Lib/test/test_tkinter/test_font.py index 8adc9e1151db4ed..e6f331332eb20a9 100644 --- a/Lib/test/test_tkinter/test_font.py +++ b/Lib/test/test_tkinter/test_font.py @@ -44,6 +44,70 @@ def test_configure(self): self.assertRaises(TypeError, self.font.cget) self.assertRaises(TypeError, self.font.cget, 'size', 'weight') + def test_create(self): + sizetype = int if self.wantobjects else str + + # A new named font is created from the font description... + f = font.Font(root=self.root, font=('Times', 20, 'bold')) + self.assertIn(f.name, font.names(self.root)) + self.assertEqual(f.actual('weight'), 'bold') + self.assertEqual(f.cget('size'), sizetype(20)) + + # ... or from the keyword options. + f = font.Font(root=self.root, family='Times', size=20, weight='bold') + self.assertIn(f.name, font.names(self.root)) + self.assertEqual(f.actual('weight'), 'bold') + self.assertEqual(f.cget('size'), sizetype(20)) + + # Explicit options override the corresponding settings of *font*. + f = font.Font(root=self.root, font=('Times', 20, 'bold'), weight='normal') + self.assertEqual(f.actual('weight'), 'normal') + self.assertEqual(f.cget('size'), sizetype(20)) + + # The new font can be given an explicit name. + f = font.Font(root=self.root, name='testfont', font=('Times', 20)) + self.assertEqual(f.name, 'testfont') + self.assertIn('testfont', font.names(self.root)) + self.assertEqual(f.cget('size'), sizetype(20)) + # Reusing the name of an existing font fails. + self.assertRaises(tkinter.TclError, font.Font, root=self.root, + name='testfont', font=('Times', 10)) + + def test_existing(self): + sizetype = int if self.wantobjects else str + + # With a name, refer to the existing named font. + named = font.Font(root=self.root, name='existingfont', family='Times', size=20) + f = font.Font(root=self.root, name='existingfont', exists=True) + self.assertEqual(f.name, 'existingfont') + self.assertEqual(f.cget('size'), sizetype(20)) + # Referring to a non-existent named font fails. + self.assertRaises(tkinter.TclError, font.Font, root=self.root, + name='nosuchfont', exists=True) + # A name and options reconfigure the existing font. + font.Font(root=self.root, name='existingfont', exists=True, size=8) + self.assertEqual(f.cget('size'), sizetype(8)) + + # With a description and no name, the description is wrapped without + # creating a new named font (gh-143990), so that it is used without + # loss of precision by actual(), measure() and metrics(). + f = font.Font(root=self.root, font=('Times', 20, 'bold'), exists=True) + self.assertEqual(f.name, ('Times', 20, 'bold')) + self.assertEqual(str(f), 'Times 20 bold') + self.assertNotIn(f.name, font.names(self.root)) + self.assertEqual(f.actual('weight'), 'bold') + self.assertEqual(f.actual('size'), sizetype(20)) + # It can be used as a widget option, with the same effect as the + # description itself (gh-143990). + self.assertEqual(tkinter.Label(self.root, font=f).cget('font'), + tkinter.Label(self.root, font=f.name).cget('font')) + + # Options cannot be combined with a wrapped description. + self.assertRaises(TypeError, font.Font, root=self.root, + font=('Times', 20), exists=True, weight='bold') + # A name or a description is required. + self.assertRaises(TypeError, font.Font, root=self.root, exists=True) + def test_copy(self): f = font.Font(root=self.root, family='Times', size=10, weight='bold') copied = f.copy() @@ -60,10 +124,7 @@ def test_copy(self): def test_unicode_family(self): family = 'MS \u30b4\u30b7\u30c3\u30af' - try: - f = font.Font(root=self.root, family=family, exists=True) - except tkinter.TclError: - f = font.Font(root=self.root, family=family, exists=False) + f = font.Font(root=self.root, family=family) self.assertEqual(f.cget('family'), family) del f gc_collect() @@ -96,6 +157,19 @@ def test_equality(self): self.assertEqual(font1, font2) self.assertNotEqual(font1, font1.copy()) + # Wrapped descriptions (gh-143990) compare by the description. + w1 = font.Font(root=self.root, font=('Times', 20, 'bold'), exists=True) + w2 = font.Font(root=self.root, font=('Times', 20, 'bold'), exists=True) + self.assertIsNot(w1, w2) + self.assertEqual(w1, w2) + w3 = font.Font(root=self.root, font=('Times', 12), exists=True) + self.assertNotEqual(w1, w3) + # A wrapped description never equals a named font, even one whose name + # is the string form of the description. + named = font.Font(root=self.root, name=str(w1), family='Courier') + self.assertNotEqual(w1, named) + self.assertNotEqual(named, w1) + self.assertNotEqual(font1, 0) self.assertEqual(font1, ALWAYS_EQ) diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py index 896e910d69f6f33..d59b04d36638e79 100644 --- a/Lib/tkinter/font.py +++ b/Lib/tkinter/font.py @@ -70,34 +70,55 @@ def __init__(self, root=None, font=None, name=None, exists=False, if root is None: root = tkinter._get_default_root('use font') tk = getattr(root, 'tk', root) - if font: - # get actual settings corresponding to the given font - font = tk.splitlist(tk.call("font", "actual", font)) + self.delete_font = False + if exists and not name: + if not font: + raise TypeError("font name or description is required if exists=True") + if options: + raise TypeError("cannot specify font options when wrapping an " + "existing font description") + # Wrap the description without creating a new named font, so that + # it is used as is by actual(), measure() and metrics(). 'name' is + # then the description rather than a string. + self.name = font else: - font = self._set(options) - if not name: - name = "font" + str(next(self.counter)) - self.name = name - - if exists: - self.delete_font = False - # confirm font exists - if self.name not in tk.splitlist(tk.call("font", "names")): - raise tkinter._tkinter.TclError( - "named font %s does not already exist" % (self.name,)) - # if font config info supplied, apply it if font: - tk.call("font", "configure", self.name, *font) - else: - # create new font (raises TclError if the font exists) - tk.call("font", "create", self.name, *font) - self.delete_font = True + # start from the actual settings of the given font + font = tk.splitlist(tk.call("font", "actual", font)) + if options: + # explicit options override the corresponding settings + settings = self._mkdict(font) + settings.update(options) + font = self._set(settings) + else: + font = self._set(options) + if exists: + self.name = name + # confirm font exists + if self.name not in tk.splitlist(tk.call("font", "names")): + raise tkinter._tkinter.TclError( + "named font %s does not already exist" % (self.name,)) + # if font config info supplied, apply it + if font: + tk.call("font", "configure", self.name, *font) + else: + if name: + self.name = name + else: + self.name = "font" + str(next(self.counter)) + # create new font (raises TclError if the font exists) + tk.call("font", "create", self.name, *font) + self.delete_font = True # set after creation self._tk = tk self._split = tk.splitlist self._call = tk.call def __str__(self): - return self.name + # A wrapped description is a list or tuple, not a string; format it as + # a Tcl word so it can be used as an option value (as ttk does). + if isinstance(self.name, str): + return self.name + return tkinter._join(self.name) def __repr__(self): return f"<{self.__class__.__module__}.{self.__class__.__qualname__}" \ diff --git a/Misc/NEWS.d/next/Library/2026-06-23-18-42-37.gh-issue-143990.o65v7O.rst b/Misc/NEWS.d/next/Library/2026-06-23-18-42-37.gh-issue-143990.o65v7O.rst new file mode 100644 index 000000000000000..c464f81a6bb2547 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-23-18-42-37.gh-issue-143990.o65v7O.rst @@ -0,0 +1,6 @@ +:class:`tkinter.font.Font` can now wrap a font description without creating a +new named font, by passing it as *font* with ``exists=True`` and no *name*. +This avoids a loss of precision in :meth:`~tkinter.font.Font.actual`, +:meth:`~tkinter.font.Font.measure` and :meth:`~tkinter.font.Font.metrics`. +Keyword options now override the corresponding settings of the given *font* +instead of being ignored. From 34e6a4e2778adee3182763f43618856633c66d52 Mon Sep 17 00:00:00 2001 From: Wojusensei Date: Tue, 7 Jul 2026 19:41:32 +0800 Subject: [PATCH 61/61] gh-152798: Update sys.thread_info.lock documentation 2 match implementation --- Doc/library/sys.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index d0fe0625deb5133..63741fedcbcd947 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -2240,9 +2240,8 @@ always available. Unless explicitly noted otherwise, all variables are read-only The name of the lock implementation: - * ``"semaphore"``: a lock uses a semaphore - * ``"mutex+cond"``: a lock uses a mutex and a condition variable - * ``None`` if this information is unknown + * ``"pymutex"``: a lock uses the PyMutex implementation. + * ``None`` if the lock implementation is not exposed (e.g.:on Windows and WASI) .. attribute:: thread_info.version